0Pricing
Android Academy · Урок

Разрешения и запросы во время выполнения

Объявляйте опасные разрешения и запрашивайте их во время выполнения с помощью 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 — точность GPS
  • ACCESS_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_IMAGES
  • READ_MEDIA_VIDEO
  • READ_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 — локальная установка не требуется.

Все уроки этого курса

  1. Структура проекта и манифест
  2. Активности и жизненный цикл
  3. Макеты и представления
  4. Обработка ввода пользователя
  5. Намерения и навигация
  6. Фрагменты
  7. Разрешения и запросы во время выполнения
← Назад к Android Academy