AndroidManifest.xml
新增 <provider>
section
...
<application
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="YOUR_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
</application>
YOUR_PACKAGE_NAME
為 App 唯一識別的 package name
res
資料夾底下新增 raw/sample_pdf.pdf
sample_pdf.pdf
為您要 demo 的 pdf
檔
res
資料夾底下新增 xml/file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files_shared" path="."/>
</paths>
<files-path>
設定檔案共享的目錄,此指定內部私有空間中的 files
資料夾 (data/../YOUR_PACKAGE_NAME/files
);path="."
表示允許分享給應用程式的files
的子目錄,"."
表示 files
資料夾底下的所有檔案都允許分享;name="files_shared"
表示子目錄名稱的別名,當傳分享檔案的位置給其他應用程式,產生 content:// URI
時,會使用此別名來代表實際的檔案路徑。其他屬性代表的意義可參考
因 Android 無法直接開啟既有的檔案(res/raw/sample_pdf
),所以要先拷貝一份至 App 本身的儲存空間,再從那裡取出檔案位置,再開啟檔案。
public static void view_pdf(Context context) {
// 檢查 App 本身的儲存空間是否存在 pdf 檔
// 這裡是使用的位置是 getFilesDir(), ex: /data/user/0/YOUR_PACKAGE_NAME/files
File file = new File(context.getFilesDir(), "sample_pdf.pdf");
InputStream in = null;
OutputStream out = null;
if (!file.exists()) {
try {
// Demo 用: 從資料夾 res/raw/ 取得 pdf file
in = context.getResources().openRawResource(R.raw.sample_pdf);
out = new FileOutputStream(file.getAbsolutePath());
//out = context.openFileOutput(file.getName(), context.MODE_PRIVATE); // 同上
copyPdfFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
logger.error("exception " + e.getMessage());
}
}
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri;
/**
* 在 Android 7.0 之後, 跨 App 分享檔案路徑必須透過 FileProvider
* 為了更注重安全性, FileProvider 會隱藏的檔案的實際路徑; 若沒有透過 FileProvider App 會拋出 FileUriExposedException
* 而原使用 file:// 要改成 content://
*/
// > API 24 (Android 7.0): 使用 FileProvider.getUriForFile()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 第二個參數: 須與 AndroidManifest 中 <provider> 的 android:authorities 屬性值一致
uri = FileProvider.getUriForFile(
context,
"com.maxkit.msicloud_android.fileprovider",
file
);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
// < API 24: 使用 Uri.fromFile()
else {
uri = Uri.fromFile(file);
}
// 設定要分享的檔案類型
intent.setDataAndType(uri, "application/pdf");
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(
context,
"不存在 Pdf 檢視器",
Toast.LENGTH_LONG
).show();
}
}
private static void copyPdfFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
Reading .pdf from raw folder in project
How to open a pdf stored either in res/raw or assets folder?
File Provider
Android 跨 App 分享檔案 — FileProvider introduced on Android N
File 相關