Как работать с платформенными разрешениями (permissions)?
Работа с платформенными разрешениями (permissions) в Xamarin и Xamarin.Forms — важная часть мобильной разработки, особенно при доступе к чувствительным функциям устройства, таким как камера, микрофон, геолокация, хранилище и т.д. Каждая мобильная ОС (Android, iOS) требует явного запроса разрешений от пользователя на выполнение таких операций. Xamarin предлагает удобные инструменты и подходы для управления разрешениями, включая кроссплатформенную библиотеку Xamarin.Essentials.
Основы разрешений
Разрешения делятся на две группы:
-
Разрешения на уровне манифеста (compile-time) — указываются в AndroidManifest.xml или Info.plist.
-
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.
Проверка разрешений при запуске
Для предотвращения ошибок, вызванных отсутствием разрешений:
-
Проверяйте разрешения перед вызовом любого API.
-
Не полагайтесь только на Manifest — Android 6+ требует runtime-разрешения.
-
Для 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 |
--- | --- | --- |
Отказ навсегда | Нельзя снова запросить | Можно открыть настройки |
--- | --- | --- |
Работа с разрешениями требует внимательности, так как их неправильное управление приводит к сбоям в приложении или отказу пользователей. Хорошая практика — спрашивать разрешения только тогда, когда они действительно нужны, а также грамотно информировать пользователя о причинах запроса.