Ответ
Работа с разрешениями — одна из ключевых платформенно-зависимых задач. Во Flutter мы используем пакет permission_handler, но важно понимать различия в поведении ОС.
Android:
- Объявление в манифесте: Все разрешения должны быть объявлены в
android/app/src/main/AndroidManifest.xml. - Runtime-запрос: "Опасные" разрешения (камера, контакты, местоположение, хранилище) требуют запроса во время работы приложения. Пользователь может ответить "Разрешить" или "Запретить".
- Scoped Storage (Android 10+): Доступ к общему хранилищу сильно ограничен. Для выбора файлов используется системный пикер (
file_picker), а для папок может потребоваться специальное разрешениеMANAGE_EXTERNAL_STORAGE.
iOS:
- Объявление в Info.plist: Необходимо добавить соответствующие ключи (например,
NSLocationWhenInUseUsageDescription) вios/Runner/Info.plistс описанием причины запроса. - Runtime-запрос: Запрос происходит один раз при первом обращении к функционалу. Пользователь может выбрать "Разрешить один раз", "Разрешить при использовании приложения" или "Запретить".
- Повторный запрос: Если пользователь запретил доступ, приложение может только перенаправить его в настройки системы (
openAppSettings()).
Пример кода с permission_handler:
import 'package:permission_handler/permission_handler.dart';
Future<bool> requestCameraPermission() async {
// Проверяем статус
var status = await Permission.camera.status;
if (status.isDenied) {
// Запрашиваем разрешение (на iOS может показать диалог, на Android — системное окно)
status = await Permission.camera.request();
}
if (status.isPermanentlyDenied) {
// Пользователь нажал "Не спрашивать снова" (Android) или запретил (iOS)
// Открываем настройки приложения
await openAppSettings();
}
return status.isGranted;
}
Ключевое отличие: На Android логика "разрешить один раз" отсутствует, а управление разрешениями более детализировано (например, можно запросить доступ только к фотографиям, а не ко всему хранилищу). На iOS критически важно заполнить Info.plist, иначе разрешение не будет запрошено, а функционал просто не сработает.
Ответ 18+ 🔞
А, ну это ж классика, ебать мои старые костыли! Смотри, с разрешениями в мобилке — это вообще отдельная песня, где каждый куплет тебе в душу мать. Берёшь пакет permission_handler, думаешь: «Ну сейчас всё по-быстрому сделаю». А нихуя! Тут два зверя, Android и iOS, и у них в голове, прости господи, хуй с винтом.
Android, этот хитрая жопа:
- Манифест — святое. Если не прописал разрешение в
AndroidManifest.xml, то можешь хоть обоссысь, запросить его в рантайме не получится. Это как прийти в клуб без штанов — тебя просто нахуй пошлют. - Запрос на лету. Опасные штуки вроде камеры или локации надо спрашивать у юзера, когда приложение уже работает. Он может кивнуть или послать тебя. Стандартно.
- Scoped Storage (Android 10+). Вот тут начинается пиздец, Карл! Раньше ты мог шариться по всей памяти телефона как у себя дома. А теперь тебе сказали: «Хуй с горы, дружок». Для выбора файла юзаешь системный пикер (
file_picker), а чтобы получить доступ ко всему хранилищу, нужно выпрашивать особое разрешениеMANAGE_EXTERNAL_STORAGE, и тебя ещё будут смотреть как на полупидора. Шансов — ноль ебать.
iOS, эта мартышлюшка:
- Info.plist — твой пропуск. Не добавил ключик с внятным описанием (типа
NSLocationWhenInUseUsageDescription) вInfo.plist? Поздравляю, твоя фича просто не сработает, и ты будешь месяц искать баг, пока не охуеешь. Описание — обязательно, иначе система даже не чихнет в твою сторону. - Запрос один раз. Спросил — и живи с ответом. Пользователь может выбрать «Разрешить один раз», «Только когда приложение открыто» или «Иди нахуй». И это навсегда. Ну или почти.
- Повторный запрос? Не, не слышал. Если юзер запретил, то твой код может только вежливо предложить ему пойти в настройки системы и там всё поправить. Через
openAppSettings(). А сам — ни хуя не может.
Вот, смотри, как это в коде выглядит, типа:
import 'package:permission_handler/permission_handler.dart';
Future<bool> requestCameraPermission() async {
// Сначала проверяем, что там уже
var status = await Permission.camera.status;
if (status.isDenied) {
// Ну всё, просим. На iOS вылезет окошко, на Android — системное.
status = await Permission.camera.request();
}
if (status.isPermanentlyDenied) {
// Вот это прикол: юзер ткнул «Не спрашивать больше» (на Android) или просто запретил (на iOS).
// Твоя единственная надежда — открыть настройки и молиться.
await openAppSettings();
}
return status.isGranted; // Вернёт true, только если доступ дали.
}
А главная разница, ёпта, в чём? На Android нету варианта «разрешить один раз», зато там можно ковыряться в разрешениях точечнее. А на iOS — если забыл про Info.plist, то вся твоя работа насмарку, доверия к системе — ноль ебать. Так что держи ухо востро, чувак, тут овердохуища подводных камней.