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);
}
在类中添加对 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
状态,并要求用户手动启用。
如果使用 CheckStatusAsync
或 RequestAsync
,将返回 PermissionStatus
用于确定后续步骤:
- Unknown - 权限处于未知状态
- Denied - 用户拒绝了权限请求
- Disabled - 此功能在设备上是禁用的
- Granted - 用户已授予权限或权限已自动授予
- Restricted - 处于受限制状态
最佳做法是说明应用程序需要特定权限的原因。 在 iOS 上,必须指定向用户显示的字符串。 Android 没有此功能,并且还将权限状态默认为“已禁用”。 这样则无法了解用户是否拒绝了权限,也无法了解是否是首次提示用户。 可使用 ShouldShowRationale
方法确定是否应显示说明性 UI。 该方法返回 true
时,则是因为过去用户已拒绝或禁用该权限。 调用此方法时,其他平台始终会返回 false
。
Xamarin.Essentials 会尝试将尽可能多的权限抽象化。 但是,每个操作系统都有一组不同的运行时权限。 此外,在能否为某些权限提供单个 API 方面也存在差异。 下面是当前可用权限的指南:
图标指南:
- - 支持
- - 不支持/不需要
权限 | Android | iOS | UWP | watchOS | tvOS | Tizen |
---|---|---|---|---|---|---|
CalendarRead | ||||||
CalendarWrite | ||||||
照相机 | ||||||
ContactsRead | ||||||
ContactsWrite | ||||||
手电筒 | ||||||
LocationWhenInUse | ||||||
LocationAlways | ||||||
媒体 | ||||||
麦克风 | ||||||
电话 | ||||||
照片 | ||||||
提醒 | ||||||
传感器 | ||||||
Sms | ||||||
语音 | ||||||
StorageRead | ||||||
StorageWrite |
如果权限标有 ,则在检查或请求权限时始终返回 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 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 文档。