Как работать с платформенными разрешениями (permissions)?

Работа с платформенными разрешениями (permissions) в Xamarin и Xamarin.Forms — важная часть мобильной разработки, особенно при доступе к чувствительным функциям устройства, таким как камера, микрофон, геолокация, хранилище и т.д. Каждая мобильная ОС (Android, iOS) требует явного запроса разрешений от пользователя на выполнение таких операций. Xamarin предлагает удобные инструменты и подходы для управления разрешениями, включая кроссплатформенную библиотеку Xamarin.Essentials.

Основы разрешений

Разрешения делятся на две группы:

  1. Разрешения на уровне манифеста (compile-time) — указываются в AndroidManifest.xml или Info.plist.

  2. Runtime-разрешения — требуют запроса у пользователя во время работы приложения (особенно важно для Android 6.0+ и iOS 10+).

Работа с разрешениями через Xamarin.Essentials

Xamarin.Essentials содержит API Permissions, который предоставляет удобный способ проверки и запроса разрешений на различных платформах.

Установка:

Install-Package Xamarin.Essentials

Использование:

var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
}
if (status == PermissionStatus.Granted)
{
// Разрешение предоставлено  выполняем действие
}
else
{
// Разрешение не предоставлено  выводим сообщение
}

Список доступных разрешений в Xamarin.Essentials

  • Permissions.Camera

  • Permissions.LocationWhenInUse

  • Permissions.LocationAlways

  • Permissions.StorageRead

  • Permissions.StorageWrite

  • Permissions.ContactsRead

  • Permissions.ContactsWrite

  • Permissions.Sms

  • Permissions.Microphone

  • Permissions.Photos

  • Permissions.CalendarRead

  • Permissions.CalendarWrite

  • Permissions.Sensors

  • и другие

Каждое разрешение реализуется как подкласс Permissions.BasePermission.

Пример: Запрос доступа к геолокации

var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
}
if (status == PermissionStatus.Granted)
{
var location = await Geolocation.GetLastKnownLocationAsync();
}

Android: Добавление разрешений в AndroidManifest.xml

Пример:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Эти строки помещаются в файл Properties/AndroidManifest.xml.

Дополнительно:

  • Для Android 10+ может потребоваться разрешение ACCESS_BACKGROUND_LOCATION.

  • С Android 11 (API 30) доступ к хранилищу стал более ограниченным (Scoped Storage).

iOS: Добавление разрешений в Info.plist

Пример:

<key>NSCameraUsageDescription</key>
<string>Приложению нужен доступ к камере</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Приложению нужен доступ к вашей геолокации</string>
<key>NSMicrophoneUsageDescription</key>
<string>Приложению нужен доступ к микрофону</string>

Без добавления этих ключей приложение вылетит при попытке доступа к соответствующим API.

Обработка отказа в разрешении

Если пользователь отказался от разрешения, можно:

  • Предложить объяснение, зачем нужен доступ.

  • Направить пользователя в настройки.

Пример:

if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.Android)
{
// Пользователь отказался  предложить перейти в настройки
await Launcher.OpenAsync(Android.Provider.Settings.ActionApplicationDetailsSettings);
}

Пользовательский интерфейс при запросе разрешений

Важно учитывать:

  • Запрашивать разрешения только при необходимости, а не при запуске приложения.

  • Объяснять пользователю, зачем нужен доступ, особенно если отказ ранее был.

Пример UI-объяснения перед запросом:

bool result = await DisplayAlert("Доступ к камере",
"Для сканирования документов приложению нужен доступ к камере", "ОК", "Отмена");
if (result)
{
var permissionStatus = await Permissions.RequestAsync<Permissions.Camera>();
// ...
}

Собственная реализация запроса разрешений (без Xamarin.Essentials)

Если не используется Xamarin.Essentials, разрешения можно запрашивать напрямую:

Android (через ActivityCompat):

ActivityCompat.RequestPermissions(this,
new string\[\] { Manifest.Permission.Camera },
0);

Результат нужно обрабатывать в OnRequestPermissionsResult.

Проверка разрешений при запуске

Для предотвращения ошибок, вызванных отсутствием разрешений:

  1. Проверяйте разрешения перед вызовом любого API.

  2. Не полагайтесь только на Manifest — Android 6+ требует runtime-разрешения.

  3. Для iOS важно наличие ключей в Info.plist.

Примеры комбинаций разрешений

  • Камера и хранилище — для фото и видео:

    • Permissions.Camera

    • Permissions.StorageRead / Permissions.StorageWrite

  • Геолокация — для карт и трекинга:

    • Permissions.LocationWhenInUse / LocationAlways
  • Микрофон — для записи звука:

    • Permissions.Microphone
  • Bluetooth — может требовать дополнительные разрешения с Android 12+:

    • BLUETOOTH_CONNECT, BLUETOOTH_SCAN

Пример универсального метода запроса разрешения

public async Task<bool> RequestPermission<T>() where T : Permissions.BasePermission, new()
{
var status = await Permissions.CheckStatusAsync<T>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<T>();
}
return status == PermissionStatus.Granted;
}
Использование:
bool cameraOk = await RequestPermission<Permissions.Camera>();

Платформенные особенности

Особенность Android iOS
Необходимость в runtime-разрешении С Android 6.0 (API 23) С iOS 10
--- --- ---
Обязательные описания в манифесте AndroidManifest.xml Info.plist
--- --- ---
Настройки вручную Можно открыть через Intent Через UIApplication.OpenUrl
--- --- ---
Отказ навсегда Нельзя снова запросить Можно открыть настройки
--- --- ---

Работа с разрешениями требует внимательности, так как их неправильное управление приводит к сбоям в приложении или отказу пользователей. Хорошая практика — спрашивать разрешения только тогда, когда они действительно нужны, а также грамотно информировать пользователя о причинах запроса.