XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2018/06/04

Xamarin.Android 執行時期的權限處理說明 3 使用手機內其他 PDF App 來開啟在 download 資料夾內的檔案

範例專案 : 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 來開啟這個檔案。
小米 Max 小米 Max



2018/06/01

Xamarin.Android 執行時期的權限處理說明 2 使用 Plugin.Permissions

這篇文章的說明範例專案,可以從 這裡 取得

了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
在上一篇文章 Xamarin.Android 執行時期的權限處理說明 1 最低的 Android 版本 / 目標 Android 版本 / 目標 Framework ,我們透過了事件聚合器 Event Aggregator 來呼叫 Android 原生的執行時期的權限檢查與授權工作,不過,這樣的處理方式會有些麻煩,因為,我們同時也需要時做出 iOS 上的相關動態權限檢查與請求授權,因此,在這篇文章中,我們將會透過了 Plugin.Permissions 這個 NuGet 套件,讓我們可以在 Xamarin.Forms 的 .NET Standard 專案中,來進行相關的權限檢查與授權需求。而更多關於這個套件的說明與使用注意事項,可以參考 GitHub Plugin.Permissions 文章說明

準備測試專案

  • 首先我們先使用 Prism Template Pack 幫助我們建立一個 Xamarin.Forms 的專案
  • 接著,請在 SCL .NET Standard 專案中,加入這個 Plugin.Permissions 套件
  • 滑鼠窗擊 Xamarin.Android 專案中的 Properties 節點,並且切換到 Android 資訊清單 標籤頁次,找到 目標 Android 版本,在此下拉選單中,選擇任何一個 API 層級大於 23 的版本
  • 打開 Android 專案中的 MainActivity.cs 檔案,使用底下程式碼取代
using Android.App;
using Android.Content.PM;
using Android.OS;
using Prism;
using Prism.Ioc;

[assembly: UsesPermission(Name = Android.Manifest.Permission.ReadExternalStorage)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.WriteExternalStorage)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.Camera)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.CallPhone)]
namespace XFPermPlugin.Droid
{
    [Activity(Label = "XFPermPlugin", Icon = "@mipmap/ic_launcher", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(new App(new AndroidInitializer()));
        }
        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [Android.Runtime.GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Plugin.Permissions.PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    public class AndroidInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IContainerRegistry container)
        {
            // Register any platform specific implementations
        }
    }
}
  • 在此,我們使用了 [assembly: UsesPermission(Name = Android.Manifest.Permission.WriteExternalStorage)] 宣告我們需要進行外部記憶卡的寫入需求
  • 接著 我們要在 OnCreate 方法中,使用 Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, bundle); 方法呼叫,進行這個套件初始化的動作。
  • 另外,我們也需要在 MainActivity 類別中,加入 OnRequestPermissionsResult 的方法覆寫。
  • 打開 MainPage.xaml 檔案,填入底下的 XAML 宣告
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFPermPlugin.Views.MainPage"
             Title="{Binding Title}">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
        <Label Text="Welcome to Xamarin Forms and Prism!" />
        <Button Text="Permission 檢查與授權" Command="{Binding CheckPermissionCommand}" />
    </StackLayout>

</ContentPage>
  • 在這個頁面中,宣告的 UI 相當的簡單,只有一個按鈕
  • 打開 MainPageViewModel.cs,填入底下的 C# 程式碼
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XFPermPlugin.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        public DelegateCommand CheckPermissionCommand { get; set; }
        public readonly IPageDialogService _dialogService;
        public MainPageViewModel(INavigationService navigationService,
            IPageDialogService dialogService) 
            : base (navigationService)
        {
            _dialogService = dialogService;
            Title = "Main Page";
            CheckPermissionCommand = new DelegateCommand(async () =>
            {
                var fooStatus = await Plugin.Permissions.CrossPermissions
                .Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);
                if (fooStatus != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
                {
                    if (await Plugin.Permissions.CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync
                    (Plugin.Permissions.Abstractions.Permission.Storage))
                    {
                        await _dialogService.DisplayAlertAsync("Need Storage", "Gunna need that Storage", "OK");
                    }

                    var results = await Plugin.Permissions.CrossPermissions.Current.RequestPermissionsAsync
                    (Plugin.Permissions.Abstractions.Permission.Storage);
                    //Best practice to always check that the key exists
                    if (results.ContainsKey(Plugin.Permissions.Abstractions.Permission.Storage))
                        fooStatus = results[Plugin.Permissions.Abstractions.Permission.Storage];
                }

                if (fooStatus == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
                {
                    await _dialogService.DisplayAlertAsync("Storage Allow", "You can continue to call any storage API.", "OK");
                }
                else if (fooStatus != Plugin.Permissions.Abstractions.PermissionStatus.Unknown)
                {
                    await _dialogService.DisplayAlertAsync("Storage Denied", "Can not continue, try again.", "OK");
                }
            });
        }
    }
}
  • 在這個 ViewModel 中,我們使用了 Plugin.Permissions.CrossPermissions.Current 取得了 IPermissions 這個實作物件,並且使用了 Plugin.Permissions.CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage) 敘述,來檢查現在正在執行的應用程式,是否已經取得使用者授權可以使用 Storage 的使用權限。
    若使用這已經授權使用 Storage 這個使用權限,則您會得到 Plugin.Permissions.Abstractions.PermissionStatus.Granted 值
    若使用者尚未授權,對於 Android 平台,我們需要顯示一段訊息,告知使用者我們需要這樣的權限,如此,應用程式方可正常運作。
    Android Permission
    接下來,我們使用了 Plugin.Permissions.CrossPermissions.Current.RequestPermissionsAsync(Plugin.Permissions.Abstractions.Permission.Storage) 方法,請求使用者授權這個應用程式,可以使用 Storage 的權限。
    Android Permission
    一旦此次請求授權的結果為 Plugin.Permissions.Abstractions.PermissionStatus.Granted ,您就可以開始進行相關 API 呼叫,否則,就不應該呼叫這些尚未授權 API 的呼叫。

2018/05/31

Xamarin.Android 執行時期的權限處理說明 1 最低的 Android 版本 / 目標 Android 版本 / 目標 Framework

這篇文章的說明範例專案,可以從 這裡 取得

了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
當我們在進行 Xamarin.Android 專案建置的時候,我們可以從 Android 專案內的 Properties 中,也就是這個專案的屬性視窗內,看到關於這三個名詞:最低的 Android 版本 / 目標 Android 版本 / 目標 Framework。若您想要更進一步的瞭解這三者的差異,可以參考 了解 Android API 層級 ,底下根據這篇文章內容,列出這三者的說明
  • 目標 Framework (也稱為 compileSdkVersion)
    是在建置階段編譯您的應用程式特定的 Android 架構版本 (API 層級)
  • 最低的 Android 版本 (也稱為 minSdkVersion)
    是 Android OS (亦即,最低 API 層級),可以安裝和執行應用程式的舊版本
  • Android 的版本為目標 (也稱為 targetSdkVersion)
    是應用程式開發介面層級的 Android 裝置,應用程式預期執行。
由於 從 2018年 8 月之後 ,Google Play Console 將會需要新的應用程式目標應用程式開發介面層級 26 (Android 8.0) 或更高版本,這裡所指的是 目標 Android 版本。 現有的應用程式必須以 API 層級 26 或更高版本。如需詳細資訊,請參閱 改善應用程式安全性和效能
因此,在這裡,我們要來做些小測試,了解如何進行執行時期的權限檢查與請求使用者授予使用這些權限的程式設計方法。

建立測試專案

  • 首先,使用 Xamarin.Forms for Prism 建立一個專案
  • 滑鼠雙擊 Android 專案內的 Properties 節點,此時,這個專案的屬性視窗會顯示出來
  • 請切換到 應用程式 標籤頁次,點選 使用下列 Android 版本編譯: (目標 Framework) 下拉選單,確定選擇的是 使用最新平台,這裡是會設定 compileSdkVersion
  • Android Target Version compileSdkVersion
    這裡是英文版的 Visual Studio 2017 看到的內容,我們可以看到這個欄位名稱為 Compile using Android version: (Target Framework)
    Android Target Version compileSdkVersion
  • 請切換到 Android 資訊清單 (Manifest) 標籤頁次,點選 目標 Android 版本 下拉選單,根據文件建議,請在這裡選擇最新的 SDK 版本,這裡是會設定 targetSdkVersion
  • Android Target Version compileSdkVersion
    這裡是英文版的 Visual Studio 2017 看到的內容,我們可以看到這個欄位名稱為 Target Android version
    Android Target Version compileSdkVersion
  • 請打開 Android 專案內的 MainActivity.cs 檔案,在組件層級,也就是命名空間之外,輸入底下程式碼,我們在這宣告了這個 Android 應用程式,需要使用這四種權限 Permission
[assembly: UsesPermission(Name = Android.Manifest.Permission.ReadExternalStorage)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.WriteExternalStorage)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.Camera)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.CallPhone)]
  • 現在,請開始執行這個專案,您可以使用 Android SDK 6.0 以上的模擬器或者是實體手機來進行測試。
  • 當這個應用程式執行完成後,請中止執行,並且在 Android 裝置或模擬器上,打開設定中的應用程式頁面,請在清單中找到您剛剛執行成功的應用程式名稱,並且點選它
  • 當這個應用程式打開之後,您會看到這個應用程式明細頁面中,有個 Permissions 選項,請點選它,接著您就會發現到,這裡有三個 Permissions,不過,他們都是沒有被啟用的。
    Visual Studio for Android Emulator Visual Studio for Android Emulator
    Visual Studio for Android Emulator Visual Studio for Android Emulator
  • 此時,若您的應用程式中,剛好有執行與使用到這三個權限相關的 API,不幸的是,您的應用程式,就會造成閃退的問題。

加入執行時期的所需權限檢查

  • 建立一個 RuntimePermissionEvent 類別,用來定義 事件聚合器需要訂閱的事件類別
public class RuntimePermissionEvent : PubSubEvent<RuntimePermissionPayload>
{

}

public class RuntimePermissionPayload
{

}
  • 請將測試頁面的 XAML 修改成為如下
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFRunPermission.Views.MainPage"
             Title="{Binding Title}">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
        <Label Text="Welcome to Xamarin Forms and Prism!" />
        <Button Text="Permission 檢查與授權" Command="{Binding CheckPermissionCommand}" />
    </StackLayout>

</ContentPage>
  • 請將該頁面的 ViewModel,修改成為底下 C# 程式碼
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XFRunPermission.Events;

namespace XFRunPermission.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        private readonly IEventAggregator _eventAggregator;
        public DelegateCommand CheckPermissionCommand { get; set; }
        public MainPageViewModel(INavigationService navigationService,
            IEventAggregator eventAggregator) 
            : base (navigationService)
        {
            _eventAggregator = eventAggregator;
            CheckPermissionCommand = new DelegateCommand(() =>
            {
                _eventAggregator.GetEvent<RuntimePermissionEvent>().Publish(
                    new RuntimePermissionPayload());
            });
            Title = "Main Page";
        }
    }
}
  • 在 Android 專案內找到 MainActivity.cs 節點,將這個檔案內的內容,使用底下程式碼來替換
using Android.App;
using Android.Content.PM;
using Android.OS;
using Prism;
using Prism.Events;
using Prism.Ioc;
using XFRunPermission.Events;

[assembly: UsesPermission(Name = Android.Manifest.Permission.ReadExternalStorage)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.WriteExternalStorage)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.Camera)]
[assembly: UsesPermission(Name = Android.Manifest.Permission.CallPhone)]
namespace XFRunPermission.Droid
{
    [Activity(Label = "XFRunPermission", Icon = "@mipmap/ic_launcher", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        IEventAggregator fooIEventAggregator;
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(new App(new AndroidInitializer()));

            var fooContainer = ((App.Current) as Prism.Unity.PrismApplication).Container;
            fooIEventAggregator = fooContainer.Resolve<IEventAggregator>();
            fooIEventAggregator.GetEvent<RuntimePermissionEvent>().Subscribe(x =>
            {
                CheckPermissions();
            });
        }

        void CheckPermissions()
        {
            if ((int)Build.VERSION.SdkInt < 23)
            {
                return;
            }

            var fooRead = CheckSelfPermission(Android.Manifest.Permission.ReadExternalStorage);
            var fooWrite = CheckSelfPermission(Android.Manifest.Permission.WriteExternalStorage);
            if ((fooRead == (int)Permission.Granted) && (fooWrite == (int)Permission.Granted))
            {
                var foo = 0;
            }
            else
            {
                Android.Support.V4.App.ActivityCompat.RequestPermissions(this,
                    new string[] { Android.Manifest.Permission.ReadExternalStorage, Android.Manifest.Permission.WriteExternalStorage,
                    Android.Manifest.Permission.CallPhone, Android.Manifest.Permission.Camera}, 4);
            }
        }
        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
        {
            var foo = 1;
        }
    }

    public class AndroidInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IContainerRegistry container)
        {
            // Register any platform specific implementations
        }
    }
}

開始進行測試

  • 請再度執行這個專案,這個時候,首頁會看到這個畫面,請點選螢幕上的按鈕
    Visual Studio for Android Emulator
  • 當按鈕按下去之後,您將會看到了下圖畫面,系統將會要求您同意授權給予三種應用程式使用權限,在這裡,請在第一個權限使用授權點選 DENY,另外兩個,可以點選 ALLOW
  •  Visual Studio for Android Emulator Visual Studio for Android EmulatorVisual Studio for Android Emulator
  • 完成後,您就可以關閉這個應用程式,回到 設定 > 應用程式,來查看這個應用程式可以使用權限的說明,現在,我們可以看到這個應用程式,經過使用者授權,已經可以使用 Camera & Phone 兩種 Permission 了。
  •  Visual Studio for Android Emulator