這篇文章的說明範例專案,可以從 這裡 取得
了解更多關於 [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 平台,我們需要顯示一段訊息,告知使用者我們需要這樣的權限,如此,應用程式方可正常運作。接下來,我們使用了 Plugin.Permissions.CrossPermissions.Current.RequestPermissionsAsync(Plugin.Permissions.Abstractions.Permission.Storage) 方法,請求使用者授權這個應用程式,可以使用 Storage 的權限。一旦此次請求授權的結果為 Plugin.Permissions.Abstractions.PermissionStatus.Granted ,您就可以開始進行相關 API 呼叫,否則,就不應該呼叫這些尚未授權 API 的呼叫。