範例專案 : XFFileProvider
了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
在上兩篇文章 Xamarin.Android 執行時期的權限處理說明 2 使用 Plugin.Permissions / Xamarin.Android 執行時期的權限處理說明 1 最低的 Android 版本 / 目標 Android 版本 / 目標 Framework 中,我們說明了 Android API Level 23 以上的作業系統,如何進行處理執行時期的權限授權處理方法,在這篇文章中,我們將會產生一個檔案到 Android 檔案系統中,不過,我們不是要將檔案儲存 App Sandbox 沙箱目錄內,而是要建立在 Download 資料夾內,這個資料夾內存在的檔案,連使用者也可以自行查看與開啟,不過,我們將要使用手機內已將安裝的其他,使用這些 App 來開啟這個檔案,在這裡,我們會建立一個 PDF 檔案,不過,檔案內容卻是一般文字,接者,可以讓使用者選取要使用哪個已安裝的 PDF 檢視軟體來開啟這個檔案。
不過,由於在 Android SDK 24 以上的版本,在使用 Intent 來開啟檔案的時候,加入了開啟檔案的權限判斷,因此,我們之前所使用的 Android.Net.Uri.FromFile(file); 方法,將會需要修改成為 Android.Support.V4.Content.FileProvider.GetUriForFile(Android.App.Application.Context,Android.App.Application.Context.PackageName + ".fileprovider", file); 這樣的方法呼叫,不過,還不只如此,我們還需要在 AndroidManifest 檔案內,加入額外的宣告,並且另外新增一個 XML 檔案。
因此,在這篇文章中,我們將會說明要如何做到這樣的事情,我們會設計一個頁面,裡面有兩個按鈕,第一個按鈕,將會取得使用者授權這個 App 可以使用 Storage 使用權限,第二個按鈕,將會在 download 目錄下產生一個 pdf 檔案,緊接著,將會使用手機內可以開啟 pdf 的檔案,幫助我們開啟這個 PDF 檔案與看到這些內容,當然,若您的手機中,可以開啟 pdf 的檔案 App 超過一個以上,Android 系統,將會顯示一個小對話窗,列出您手機中可以開啟 pdf 檔案的所有 App,您可以選擇任何一個來開啟這個 pdf 檔案。
在 Download 目錄下建立一個 PDF 檔案
在這個按鈕的命令委派方法中,我們透過相依性注入方法,取得了 download 目錄的路徑,並且包裝成為 PCLStorage 套件中使用的 IFolder 物件,如此,我們針對這個 IFolder 注入後的物件,也就是下面程式碼中的 rootFoler 變數,就可以在這個 download 目錄下來產生任何檔案了。我們將會在這裡產生一個 PDF.pdf 名稱的檔案,不過,該檔案內容僅是一個文字內容。
最後,我們使用相依性注入方法,取得了在 Android 平台下實作的 IOpenFileByName 物件,我們就可以針對該物件進行使用別的 App 來開啟這個檔案的動作了。
OpenPDFCommand = new DelegateCommand(async () =>
{
string filename = "PDF.pdf";
IFolder rootFolder = _publicFileSystem.PublicDownloadFolder;
IFile file = await rootFolder.CreateFileAsync(filename, CreationCollisionOption.OpenIfExists);
await file.WriteAllTextAsync("123");
_openFileByName.OpenFile(file.Path);
});
開啟 Downoad 目錄下的檔案
底下的程式碼將會需要在 Android 原生專案內實作,因為需要使用到各種 Android SDK API,我們將透過傳送過來的檔案完整路徑,建立一個 Java.IO.File 物件,接著檢查 TargetSDK 是否小於 24,若是大於等於 API Level 24,我們將會需要 這個方法,來取得該檔案的 URI : Android.Support.V4.Content.FileProvider.GetUriForFile(Android.App.Application.Context,Android.App.Application.Context.PackageName + ".fileprovider", file);
接著,當然需要建立一個 Intent 物件,最後,呼叫這個方法 Android.App.Application.Context.StartActivity(intent); 來開啟這個檔案。
很不幸的,看似一切完美,可以當您實際執行這個專案,並點下按鈕之後,您將會得到這個例外異常錯誤訊息 : Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
public void OpenFile(string fullFileName)
{
try
{
Java.IO.File file = new Java.IO.File(fullFileName);
file.SetReadable(true);
string application = "";
application = "application/pdf";
var targetSdk = ResolvePackageTargetSdkVersion();
if (targetSdk < 24)
{
Android.Net.Uri uri = Android.Net.Uri.FromFile(file);
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(uri, application);
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
try
{
Android.App.Application.Context.StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Android.App.Application.Context, "No Application Available to View this file.", ToastLength.Short).Show();
}
}
else
{
var foo = Android.App.Application.Context.PackageName + ".fileprovider";
Android.Net.Uri uri = Android.Support.V4.Content.FileProvider.GetUriForFile(
Android.App.Application.Context,
foo, file);
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(uri, application);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
intent.AddFlags(ActivityFlags.NoHistory);
intent.AddFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
try
{
Android.App.Application.Context.StartActivity(intent);
}
catch (Exception)
{
Toast.MakeText(Android.App.Application.Context, "No Application Available to View this file.", ToastLength.Short).Show();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
其他設定
- 請使用滑鼠雙擊您的 Android 專案 Properties 目錄,切換到 Android 資訊清單頁次,記錄下您這個 Android 專案的套件名稱。
- 展開 Android 專案的 Properties 節點,您將會看到 AndroidManifest.xml 檔案,請打開他
- 在 AndroidManifest.xml 檔案中加入底下的宣告
- 在 android:authorities 屬性中,請使用您實際專案的套件名稱,替換掉這個字串: [Android 專案的套件名稱]
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="[Android 專案的套件名稱].fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@layout/file_provider_path" />
</provider>
- 另外,我們需要建立一個 xml 檔案,在這裡,我們建立到 layout 目錄下,他的檔案內容如下:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="Download" path="Download/"/>
</paths>
好的,現在我們可以再度執行這個應用程式,當我們點選了 開啟 PDF 檔案,此時,螢幕最下方出現了 選擇開啟工具 對話窗,您可以選擇要使用哪個 App 來開啟這個檔案。