Xamarin.Essentials:权限

Permissions 类提供了检查和请求运行时权限的功能。

入门

若要开始使用此 API,请阅读 Xamarin.Essentials 的入门指南,确保在项目中正确安装和设置库。

此 API 在 Android 上使用运行时权限。 请确保 Xamarin.Essentials 已完全初始化,并且在你的应用中设置了权限处理。

在 Android 项目的 MainLauncher 或任何已启动的 Activity 中,必须在 OnCreate 方法中初始化 Xamarin.Essentials:

protected override void OnCreate(Bundle savedInstanceState) 
{
    //...
    base.OnCreate(savedInstanceState);
    Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
    //...
}    

若要处理 Android 上的运行时权限,Xamarin.Essentials 必须接收任何 OnRequestPermissionsResult。 将以下代码添加到所有 Activity 类:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
    Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

使用 Permissions

在类中添加对 Xamarin.Essentials 的引用:

using Xamarin.Essentials;

检查权限

若要检查权限的当前状态,请使用 CheckStatusAsync 方法以及要获取其状态的特定权限。

var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();

如果相应权限未声明,PermissionException 则会抛出。

在请求权限之前,最好先检查权限的状态。 如果系统从不提示用户,则每个操作系统会返回不同的默认状态。 iOS 会返回 Unknown,而其他系统返回 Denied。 如果状态为 Granted,则无需进行其他调用。 在 iOS 上,如果状态为 Denied,你应在设置中提示用户更改权限,而在 Android 上,可以调用 ShouldShowRationale 来检测用户过去是否已拒绝该权限。

请求权限

若要向用户请求权限,请使用 RequestAsync 方法以及要请求的特定权限。 如果用户先前已经授予了权限,并且没有撤销它,此方法会立即返回 Granted,而不会显示对话框。

var status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();

如果相应权限未声明,PermissionException 则会抛出。

请注意,在某些平台上,权限请求只能激活一次。 开发人员必须处理其他提示,以检查权限是否处于 Denied 状态,并要求用户手动启用。

权限状态

如果使用 CheckStatusAsyncRequestAsync,将返回 PermissionStatus 用于确定后续步骤:

  • Unknown - 权限处于未知状态
  • Denied - 用户拒绝了权限请求
  • Disabled - 此功能在设备上是禁用的
  • Granted - 用户已授予权限或权限已自动授予
  • Restricted - 处于受限制状态

说明为何需要权限

最佳做法是说明应用程序需要特定权限的原因。 在 iOS 上,必须指定向用户显示的字符串。 Android 没有此功能,并且还将权限状态默认为“已禁用”。 这样则无法了解用户是否拒绝了权限,也无法了解是否是首次提示用户。 可使用 ShouldShowRationale 方法确定是否应显示说明性 UI。 该方法返回 true 时,则是因为过去用户已拒绝或禁用该权限。 调用此方法时,其他平台始终会返回 false

可用权限

Xamarin.Essentials 会尝试将尽可能多的权限抽象化。 但是,每个操作系统都有一组不同的运行时权限。 此外,在能否为某些权限提供单个 API 方面也存在差异。 下面是当前可用权限的指南:

图标指南:

  • 完全支持 - 支持
  • 不支持 - 不支持/不需要
权限 Android iOS UWP watchOS tvOS Tizen
CalendarRead 支持 Android 支持 iOS 不支持 UWP 支持 watchOS 不支持 tvOS 不支持 Tizen
CalendarWrite 支持 Android 支持 iOS 不支持 UWP 支持 watchOS 不支持 tvOS 不支持 Tizen
照相机 支持 Android 支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 支持 Tizen
ContactsRead 支持 Android 支持 iOS 支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
ContactsWrite 支持 Android 支持 iOS 支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
手电筒 支持 Android 不支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 支持 Tizen
LocationWhenInUse 支持 Android 支持 iOS 支持 UWP 支持 watchOS 支持 tvOS 支持 Tizen
LocationAlways 支持 Android 支持 iOS 支持 UWP 支持 watchOS 不支持 tvOS 支持 Tizen
媒体 不支持 Android 支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
麦克风 支持 Android 支持 iOS 支持 UWP 不支持 watchOS 不支持 tvOS 支持 Tizen
电话 支持 Android 支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
照片 不支持 Android 支持 iOS 不支持 UWP 不支持 watchOS 支持 tvOS 不支持 Tizen
提醒 不支持 Android 支持 iOS 不支持 UWP 支持 watchOS 不支持 tvOS 不支持 Tizen
传感器 支持 Android 支持 iOS 支持 UWP 支持 watchOS 不支持 tvOS 不支持 Tizen
Sms 支持 Android 支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
语音 支持 Android 支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
StorageRead 支持 Android 不支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen
StorageWrite 支持 Android 不支持 iOS 不支持 UWP 不支持 watchOS 不支持 tvOS 不支持 Tizen

如果权限标有 不支持,则在检查或请求权限时始终返回 Granted

常规使用情况

下面的代码提供了用于确定是否已授予权限并发出权限请求(如果未授予权限)的常规使用模式。 此代码使用 Xamarin.Essentials 版本1.6.0 或更高版本中提供的功能。

public async Task<PermissionStatus> CheckAndRequestLocationPermission()
{
    var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
    
    if (status == PermissionStatus.Granted)
        return status;        
    
    if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.iOS)
    {
        // Prompt the user to turn on in settings
        // On iOS once a permission has been denied it may not be requested again from the application
        return status;
    }
    
    if (Permissions.ShouldShowRationale<Permissions.LocationWhenInUse>())
    {
        // Prompt the user with additional information as to why the permission is needed
    }   

    status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();

    return status;
}

每个权限类型都能创建实例,可以对其直接调用方法。

public async Task GetLocationAsync()
{
    var status = await CheckAndRequestPermissionAsync(new Permissions.LocationWhenInUse());
    if (status != PermissionStatus.Granted)
    {
        // Notify user permission was denied
        return;
    }

    var location = await Geolocation.GetLocationAsync();
}

public async Task<PermissionStatus> CheckAndRequestPermissionAsync<T>(T permission)
            where T : BasePermission
{
    var status = await permission.CheckStatusAsync();
    if (status != PermissionStatus.Granted)
    {
        status = await permission.RequestAsync();
    }

    return status;
}

扩展 Permissions

Permissions API 灵活且可扩展,可用于需要额外验证或权限的应用程序,而这些验证或权限未包含在 Xamarin.Essentials 中。 新建继承自 BasePermission 的类,并实现相应抽象方法。

public class MyPermission : BasePermission
{
    // This method checks if current status of the permission
    public override Task<PermissionStatus> CheckStatusAsync()
    {
        throw new System.NotImplementedException();
    }

    // This method is optional and a PermissionException is often thrown if a permission is not declared
    public override void EnsureDeclared()
    {
        throw new System.NotImplementedException();
    }

    // Requests the user to accept or deny a permission
    public override Task<PermissionStatus> RequestAsync()
    {
        throw new System.NotImplementedException();
    }
}

在特定平台中实现权限时,可以继承自 BasePlatformPermission 类。 这提供了额外的平台帮助程序方法,用于自动检查声明。 这在创建自定义权限来进行分组时很有用。 例如,可以使用以下自定义权限请求对 Android 上存储的读写访问权限。

public class ReadWriteStoragePermission : Xamarin.Essentials.Permissions.BasePlatformPermission
{
    public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)>
    {
        (Android.Manifest.Permission.ReadExternalStorage, true),
        (Android.Manifest.Permission.WriteExternalStorage, true)
    }.ToArray();
}

然后,你可从 Android 项目请求新权限。

await Permissions.RequestAsync<ReadWriteStoragePermission>();

如果要从共享代码调用此 API,可创建一个接口,并使用依赖项服务来注册和获取该实现。

public interface IReadWritePermission
{        
    Task<PermissionStatus> CheckStatusAsync();
    Task<PermissionStatus> RequestAsync();
}

然后在平台项目中实现该接口:

public class ReadWriteStoragePermission : Xamarin.Essentials.Permissions.BasePlatformPermission, IReadWritePermission
{
    public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)>
    {
        (Android.Manifest.Permission.ReadExternalStorage, true),
        (Android.Manifest.Permission.WriteExternalStorage, true)
    }.ToArray();
}

接着可注册特定实现:

DependencyService.Register<IReadWritePermission, ReadWriteStoragePermission>();

再从共享项目中解析并使用它:

var readWritePermission = DependencyService.Get<IReadWritePermission>();
var status = await readWritePermission.CheckStatusAsync();
if (status != PermissionStatus.Granted)
{
    status = await readWritePermission.RequestAsync();
}

平台实现细节

Permissions 必须在 Android 清单文件中设置匹配的属性。 权限状态默认为“已拒绝”。

有关详细信息,请参阅 Xamarin.Android 中的 Permissions 文档。

API

第 9 频道YouTube 上查找更多 Xamarin 视频。