Xamarin.Essentials:Разрешения

Класс Permissions позволяет проверять и запрашивать разрешения среды выполнения.

Начать

Чтобы начать использовать этот API, ознакомьтесь с руководством по началу работы с Xamarin.Essentials, чтобы правильно настроить и установить библиотеку в проектах.

Этот API использует разрешения среды выполнения для Android. Убедитесь, что набор Xamarin.Essentials полностью инициализирован и в вашем приложении настроена обработка разрешений.

В MainLauncher проекта Android или в любом запущенном действии Activity необходимо инициализировать Xamarin.Essentials в методе OnCreate:

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. Если метод возвращает true, значит пользователь отклонил или отключил разрешение в прошлом. На других платформах при вызове этого метода всегда возвращается false.

Доступные разрешения

Xamarin.Essentials пытается абстрагировать максимально возможное число разрешений. Однако каждая операционная система имеет свой набор разрешений среды выполнения. Кроме того, есть различия при использовании одного API для некоторых разрешений. Ниже приведено руководство по доступным сейчас разрешениям:

Условные обозначения:

  • Full Support -Поддерживается
  • Not Supported — не поддерживается или требуется
Разрешение Android iOS UWP watchOS tvOS Tizen
CalendarRead Android supported iOS supported UWP not supported watchOS supported tvOS not supported Tizen not supported
CalendarWrite Android supported iOS supported UWP not supported watchOS supported tvOS not supported Tizen not supported
Камера Android supported iOS supported UWP not supported watchOS not supported tvOS not supported Tizen supported
ContactsRead Android supported iOS supported UWP supported watchOS not supported tvOS not supported Tizen not supported
ContactsWrite Android supported iOS supported UWP supported watchOS not supported tvOS not supported Tizen not supported
Flashlight Android supported iOS not supported UWP not supported watchOS not supported tvOS not supported Tizen supported
LocationWhenInUse Android supported iOS supported UWP supported watchOS supported tvOS supported Tizen supported
LocationAlways Android supported iOS supported UWP supported watchOS supported tvOS not supported Tizen supported
Средства массовой информации Android not supported iOS supported UWP not supported watchOS not supported tvOS not supported Tizen not supported
Микрофон Android supported iOS supported UWP supported watchOS not supported tvOS not supported Tizen supported
Номер телефона Android supported iOS supported UWP not supported watchOS not supported tvOS not supported Tizen not supported
Photos Android not supported iOS supported UWP not supported watchOS not supported tvOS supported Tizen not supported
Напоминания Android not supported iOS supported UWP not supported watchOS supported tvOS not supported Tizen not supported
Датчики Android supported iOS supported UWP supported watchOS supported tvOS not supported Tizen not supported
SMS Android supported iOS supported UWP not supported watchOS not supported tvOS not supported Tizen not supported
Речь Android supported iOS supported UWP not supported watchOS not supported tvOS not supported Tizen not supported
StorageRead Android supported iOS not supported UWP not supported watchOS not supported tvOS not supported Tizen not supported
StorageWrite Android supported iOS not supported UWP not supported watchOS not supported tvOS not supported Tizen not supported

Если разрешение помечается как not supported всегда возвращается 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;
}

Расширение разрешений

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();
}

Особенности реализации для платформ

У разрешений должны быть соответствующие атрибуты, заданные в файле манифеста Android. Состояние разрешения по умолчанию — "Отклонено".

Дополнительные сведения см. в статье Разрешения в Xamarin.Android.

API

Другие видео о Xamarin см. на Channel 9 и YouTube.