Разрешения и запросы во время выполнения
Объявляйте опасные разрешения и запрашивайте их во время выполнения с помощью ActivityResultContracts, показывайте диалоги с объяснением и обрабатывайте постоянный отказ.
«Разрешения и запросы во время выполнения» — бесплатный урок Android Academy на CoddyKit. Это урок 7 из 7. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Android Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Android Academy содержит 7 уроков всего.
Обзор разрешений Android
Приложения Android должны объявлять, какие функции устройства им необходимы. Разрешения защищают конфиденциальность пользователя:
- Обычные разрешения — низкий риск, предоставляются автоматически (INTERNET, VIBRATE)
- Опасные разрешения — дают доступ к конфиденциальным данным и должны запрашиваться во время выполнения (CAMERA, LOCATION, READ_CONTACTS)
- Разрешения по подписи — только для приложений, подписанных тем же сертификатом
Объявление в манифесте
Сначала все разрешения необходимо объявить в AndroidManifest.xml:
<!-- AndroidManifest.xml -->
<manifest ...>
<!-- Normal: granted automatically -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Dangerous: must request at runtime -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application ...>
...
</application>
</manifest>Проверка предоставления разрешения
Перед использованием функции, требующей опасного разрешения, всегда проверяйте, предоставлено ли оно:
import androidx.core.content.ContextCompat
import android.content.pm.PackageManager
fun isCameraPermissionGranted(): Boolean {
return ContextCompat.checkSelfPermission(
this, // Context
android.Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
}Запрос разрешения с помощью ActivityResultLauncher
Используйте ActivityResultContracts.RequestPermission() — современный способ (без устаревшего onRequestPermissionsResult):
class CameraActivity : AppCompatActivity() {
private val requestCameraPermission = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
openCamera()
} else {
showPermissionDeniedMessage()
}
}
fun onTakePhotoClick(view: View) {
if (isCameraPermissionGranted()) {
openCamera()
} else {
requestCameraPermission.launch(android.Manifest.permission.CAMERA)
}
}
}Несколько разрешений одновременно
Запрашивайте несколько разрешений с помощью RequestMultiplePermissions:
private val requestMultiple = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val cameraGranted = permissions[android.Manifest.permission.CAMERA] ?: false
val locationGranted = permissions[android.Manifest.permission.ACCESS_FINE_LOCATION] ?: false
if (cameraGranted && locationGranted) {
startFeature()
} else {
showWhichPermissionsDenied(cameraGranted, locationGranted)
}
}
fun requestPermissions() {
requestMultiple.launch(arrayOf(
android.Manifest.permission.CAMERA,
android.Manifest.permission.ACCESS_FINE_LOCATION
))
}Обоснование: когда объяснять причину
shouldShowRequestPermissionRationale() возвращает true, если пользователь ранее отклонил разрешение. Перед повторным запросом покажите объяснение:
fun requestCameraWithRationale() {
when {
isCameraPermissionGranted() -> {
openCamera()
}
shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA) -> {
// Explain why we need it, then request
AlertDialog.Builder(this)
.setTitle("Camera needed")
.setMessage("We use the camera to take profile photos.")
.setPositiveButton("OK") { _, _ ->
requestCameraPermission.launch(android.Manifest.permission.CAMERA)
}
.show()
}
else -> {
requestCameraPermission.launch(android.Manifest.permission.CAMERA)
}
}
}Отклонено навсегда — переход к настройкам
Если пользователь нажмёт «Больше не спрашивать», shouldShowRequestPermissionRationale вернёт false, и повторно запросить разрешение нельзя. Направьте пользователя в настройки приложения:
fun openAppSettings() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
startActivity(intent)
}Разрешение на доступ к местоположению
Для доступа к местоположению есть два уровня — выберите подходящий для вашего сценария:
ACCESS_COARSE_LOCATION— точность до города (WiFi/вышки сотовой связи)ACCESS_FINE_LOCATION— точность GPSACCESS_BACKGROUND_LOCATION— начиная с Android 10 требуется отдельно для доступа к местоположению в фоновом режиме
Полный пример запроса разрешения на использование камеры
Полный поток, объединяющий проверку → обоснование → запрос:
class PhotoActivity : AppCompatActivity() {
private val cameraLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) openCamera() else showDenied()
}
private fun handleCameraClick() {
val permission = android.Manifest.permission.CAMERA
when {
ContextCompat.checkSelfPermission(this, permission) ==
PackageManager.PERMISSION_GRANTED -> openCamera()
shouldShowRequestPermissionRationale(permission) ->
showRationaleDialog()
else -> cameraLauncher.launch(permission)
}
}
private fun showDenied() {
Snackbar.make(binding.root, "Camera permission required", Snackbar.LENGTH_LONG)
.setAction("Settings") { openAppSettings() }.show()
}
}Рекомендации по работе с разрешениями
Основные правила для удобной работы с разрешениями:
- Запрашивайте разрешения только при необходимости (не при запуске приложения)
- Запрашивайте только минимально необходимые разрешения
- Всегда корректно обрабатывайте случай отклонения
- Не запрашивайте разрешение повторно после выбора «Больше не спрашивать»
- Объясняйте причину до системного диалогового окна, а не после отклонения
Детализированные разрешения на медиафайлы в Android 13+
Начиная с Android 13 (API 33), READ_EXTERNAL_STORAGE разделено на отдельные разрешения:
READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_AUDIO
Всегда проверяйте Build.VERSION.SDK_INT и запрашивайте разрешение, соответствующее версии OS.
Быстрая проверка
Когда следует показывать диалог с обоснованием перед запросом опасного разрешения?
Итоги: разрешения
Правильная работа с разрешениями во время выполнения:
- Объявляйте разрешения в
AndroidManifest.xml - Проверяйте их с помощью
ContextCompat.checkSelfPermission() - Запрашивайте через
registerForActivityResult(RequestPermission()) - Показывайте обоснование, когда
shouldShowRequestPermissionRationale()возвращает true - При окончательном отклонении направляйте пользователя в настройки
- Никогда не запрашивайте разрешения до того, как они понадобятся пользователю
Далее: сохранение данных локально с помощью DataStore.
Часто задаваемые вопросы
Урок «Разрешения и запросы во время выполнения» бесплатный?
Да — полный текст урока «Разрешения и запросы во время выполнения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Android Academy, подпишись на CoddyKit PRO. Курс Android Academy содержит 7 уроков всего.
Чему я научусь в уроке «Разрешения и запросы во время выполнения»?
Объявляйте опасные разрешения и запрашивайте их во время выполнения с помощью ActivityResultContracts, показывайте диалоги с объяснением и обрабатывайте постоянный отказ. Ты практикуешь Android Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Android Academy?
Предыдущий опыт не требуется. Android Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 7 из 7.
Сколько времени занимает урок «Разрешения и запросы во время выполнения»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Android Academy?
Да. Каждый урок Android Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Структура проекта и манифест
- Активности и жизненный цикл
- Макеты и представления
- Обработка ввода пользователя
- Намерения и навигация
- Фрагменты
- Разрешения и запросы во время выполнения