Камера, микрофон, местоположение — ко многим функциям телефона просто так не подступиться. Android требует явного согласия пользователя, и пока вы не научитесь правильно запрашивать разрешения, приложение будет выдавать ошибки или молча закрываться. В этом уроке мы разберём, как с помощью ActivityResultContracts и Kotlin сделать запрос разрешения простым и надёжным.
Зачем нужны разрешения и как они работают
Google защищает пользователя: приложение не может без спросу включить камеру или прочитать контакты. Поэтому придумали систему разрешений. Одни даются автоматически (интернет), другие требуют, чтобы вы попросили и пользователь нажал «Разрешить». Без такого диалога опасное действие просто не сработает. А если попытаться выполнить его без проверки, приложение упадёт с SecurityException.
Добавляем разрешение в манифест
Первым делом любое разрешение нужно объявить в AndroidManifest.xml. Без этой записи даже запрос не появится. Например, для доступа к камере добавьте внутрь тега <manifest>:
<uses-permission android:name="android.permission.CAMERA" />
После этого при установке приложения пользователь увидит, что вы хотите работать с камерой, но сам запрос ещё не сделан — его нужно выполнять отдельно во время работы программы.
Проверяем, дал ли пользователь разрешение
Перед запросом нужно убедиться, что разрешения ещё нет. Для этого вызываем ContextCompat.checkSelfPermission. Если метод вернул PERMISSION_GRANTED, значит всё в порядке, и можно сразу переходить к делу.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
// камера доступна
} else {
// будем запрашивать
}
Регистрируем контракт на запрос разрешения
Раньше использовали устаревший requestPermissions с колбэком в onRequestPermissionsResult. Современный Android Studio рекомендует Activity Result API — лаунчер, который вы объявляете один раз, а потом просто вызываете launch(). Для одного разрешения есть готовый контракт RequestPermission.
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
// разрешение получено
} else {
// пользователь отказал
}
}
Обратите внимание: лаунчер регистрируется до вызова onCreate, как свойство класса. Иначе при повороте экрана он потеряется.
Запрашиваем разрешение у пользователя
Когда нужно получить доступ, вызываем launch() с нужным разрешением. Система покажет стандартный диалог с кнопками «Разрешить» и «Отклонить».
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
Результат придёт в ту лямбду, которую вы передали при регистрации лаунчера. Там вы можете сразу открыть камеру или показать сообщение, что без разрешения нельзя продолжить.
Запрос нескольких разрешений сразу
Иногда нужны сразу два-три разрешения, например, для геолокации: и точное, и приближённое местоположение. Для этого есть контракт RequestMultiplePermissions. Он возвращает Map<String, Boolean>, где для каждого разрешения указан результат.
private val requestMultiplePermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val allGranted = permissions.values.all { it }
if (allGranted) {
// все разрешения получены
} else {
// хотя бы одно отклонено
}
}
// вызов
requestMultiplePermissions.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
Если пользователь отказал: объясняем зачем
Если пользователь нажал «Отклонить», повторный запрос можно выполнить, но после нескольких отказов система может пометить разрешение как «Больше не спрашивать». В этом случае диалог больше не появится, и пользователю придётся вручную зайти в настройки приложения. Чтобы этого избежать, перед повторным запросом покажите объяснение — метод shouldShowRequestPermissionRationale.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
// покажите диалог с объяснением, почему нужно разрешение
AlertDialog.Builder(this)
.setTitle("Доступ к камере")
.setMessage("Камера нужна для сканирования QR-кодов")
.setPositiveButton("Дать разрешение") { _, _ ->
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
.show()
} else {
// либо запрашиваем впервые, либо пользователь поставил "Больше не спрашивать"
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
Такой подход повышает шанс получить согласие и не раздражает пользователя пустыми запросами.
Полный пример: открытие камеры после согласия
Давайте объединим всё в одной Activity. При нажатии кнопки проверим разрешение, если его нет — запросим. Когда получен положительный ответ, откроем камеру через Intent.
class CameraActivity : AppCompatActivity() {
private val cameraLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) openCamera()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
btnOpenCamera.setOnClickListener {
when {
ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> openCamera()
ActivityCompat.shouldShowRequestPermissionRationale(
this, Manifest.permission.CAMERA
) -> showRationaleDialog()
else -> cameraLauncher.launch(Manifest.permission.CAMERA)
}
}
}
private fun openCamera() {
// запуск намерения камеры
}
private fun showRationaleDialog() {
AlertDialog.Builder(this)
.setMessage("Камера используется для фото")
.setPositiveButton("OK") { _, _ -> cameraLauncher.launch(Manifest.permission.CAMERA) }
.show()
}
}
Такой шаблон можно копировать для любых опасных разрешений: микрофон, контакты, местоположение.
Коротко об освоенном
- Опасные разрешения нужно объявлять в манифесте и запрашивать во время выполнения.
- ActivityResultContracts.RequestPermission — современный способ запроса одного разрешения.
- RequestMultiplePermissions — для нескольких разрешений сразу.
- Метод shouldShowRequestPermissionRationale помогает показать объяснение перед повторным запросом.
- Всегда проверяйте, дано ли уже разрешение, чтобы не вызывать диалог повторно.
Теперь вы умеете корректно запрашивать разрешения в приложении на Kotlin. Этот навык — один из обязательных для каждого разработчика. Сделайте учебное приложение, которое запрашивает доступ к камере и делает фотографию — так вы закрепите материал и получите готовый компонент для будущих проектов.