Как работать с разрешениями в Android 6.0+?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Работа с разрешениями в Android 6.0+
Начиная с Android 6.0 (API 23), Google ввела модель Runtime Permissions (разрешения во время выполнения). Это фундаментальное изменение, призванное повысить безопасность и прозрачность — пользователь предоставляет доступ к чувствительным данным (контакты, местоположение, камера и т.д.) не при установке приложения, а непосредственно в момент необходимости, прямо во время работы приложения.
Основные принципы новой модели
Все опасные разрешения (определяемые как dangerous в манифесте) теперь делятся на группы разрешений. Предоставление одного разрешения из группы автоматически даёт доступ ко всем остальным в этой группе (хронить на это не стоит, логика может измениться).
Весь процесс работы строится на использовании методов Activity Result API, который пришёл на смену устаревшему подходу с переопределением onRequestPermissionsResult.
Пошаговая реализация
1. Объявление разрешений в AndroidManifest.xml
Даже в новой модели разрешения необходимо декларировать в манифесте. Это информирует систему и магазины приложений о потребностях вашего приложения.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<!-- Запрашиваем разрешение на доступ к камере -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- Запрашиваем разрешение на доступ к точному местоположению -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application ...>
...
</application>
</manifest>
2. Проверка статуса разрешения
Перед выполнением операции, требующей разрешения, необходимо проверить его текущий статус.
import android.content.pm.PackageManager
// ...
private fun checkPermission(permission: String): Boolean {
return ContextCompat.checkSelfPermission(
this, // Context (например, Activity)
permission
) == PackageManager.PERMISSION_GRANTED
}
// Пример использования
val isCameraGranted = checkPermission(Manifest.permission.CAMERA)
3. Запрос разрешения у пользователя
Если разрешение не предоставлено, его нужно запросить. Используйте registerForActivityResult с контрактом ActivityResultContracts.RequestPermission() (для одного разрешения) или RequestMultiplePermissions() (для нескольких).
Пример запроса одного разрешения:
import androidx.activity.result.contract.ActivityResultContracts
class MainActivity : AppCompatActivity() {
// 1. Регистрируем контракт на получение результата запроса
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
// 2. Колбэк, вызываемый после ответа пользователя
if (isGranted) {
// Разрешение предоставлено. Запускаем операцию.
openCamera()
} else {
// Разрешение отклонено. Объясняем пользователю последствия.
showPermissionDeniedDialog()
}
}
fun onCameraButtonClicked() {
when {
// 3. Проверяем, есть ли уже разрешение
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
// 4. Проверяем, нужно ли показать объяснение (rationale)
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// Пользователь ранее отклонял запрос. Нужно объяснить, зачем нужно разрешение.
showRationaleDialogForCamera()
}
else -> {
// 5. Запрашиваем разрешение. Система отобразит стандартное диалоговое окно.
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
private fun openCamera() {
// Логика работы с камерой
}
}
Пример запроса нескольких разрешений:
private val requestMultiplePermissionsLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissionsMap: Map<String, Boolean> ->
permissionsMap.entries.forEach { entry ->
val permissionName = entry.key
val isGranted = entry.value
// Обрабатываем результат для каждого разрешения
if (isGranted) {
when (permissionName) {
Manifest.permission.CAMERA -> openCamera()
Manifest.permission.RECORD_AUDIO -> startRecording()
}
} else {
// Можно проверить shouldShowRequestPermissionRationale для каждого
}
}
}
fun requestLocationAndCamera() {
requestMultiplePermissionsLauncher.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.CAMERA
)
)
}
4. Обработка сценария "Больше не спрашивать"
Если пользователь отклонил запрос и поставил галочку "Больше не спрашивать" (Don't ask again), метод shouldShowRequestPermissionRationale() вернёт false. В этом случае стандартное системное диалоговое окно больше не появится. Вам необходимо:
- Вежливо объяснить пользователю, что функция недоступна без разрешения.
- Предоставить кнопку-ссылку для перехода в настройки приложения, где разрешение можно включить вручную.
private fun showPermissionDeniedDialog() {
AlertDialog.Builder(this)
.setTitle("Требуется разрешение")
.setMessage("Для работы этой функции необходим доступ к камере. Вы можете предоставить его в настройках приложения.")
.setPositiveButton("Открыть настройки") { _, _ ->
// Интент для открытия экрана настроек конкретного приложения
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.fromParts("package", packageName, null)
startActivity(intent)
}
.setNegativeButton("Отмена", null)
.show()
}
Важные рекомендации и лучшие практики
- Запрашивайте разрешения контекстно. Не спрашивайте все разрешения при старте приложения. Просите доступ в тот момент, когда пользователь инициировал действие, требующее этого разрешения (например, нажал кнопку "Сделать фото").
- Всегда проверяйте наличие разрешения перед использованием API. Даже если вы его уже запрашивали, пользователь может отозвать его в настройках в любой момент.
- Объясняйте пользу (Rationale). Если
shouldShowRequestPermissionRationaleвозвращаетtrue, покажите пользователю простое объяснение, зачем вашему приложению нужен этот доступ. Это повышает вероятность одобрения. - Уважайте отказ. Если пользователь окончательно запретил доступ, не заставляйте его — дайте возможность использовать остальной функционал приложения.
- Для фонового доступа к местоположению (Android 10+) и доступа ко всем файлам (Android 11+) существуют специальные, более строгие разрешения, требующие дополнительных действий в манифесте и, иногда, ручного перехода в настройки.
Использование Activity Result API делает код более модульным, тестируемым и избавляет от запутанной логики в onRequestPermissionsResult, что является современным и рекомендованным Google подходом к работе с разрешениями.