AndroidManifest Permissions — це декларації дозволів у файлі AndroidManifest.xml, які визначають, до яких системних ресурсів і даних має доступ застосунок. Android вимагає вказувати кожен дозвіл у маніфесті перед використанням відповідного API: від камери та геолокації до надсилання SMS і доступу до контактів. Згідно з Android Developer Documentation, кожен дозвіл поділяється на один із чотирьох рівнів захисту: normal, dangerous, signature та special.
Головне
AndroidManifest Permissions — це механізм безпеки Android, який контролює доступ застосунків до захищених даних і системних функцій. Кожен застосунок повинен декларувати необхідні дозволи у файлі AndroidManifest.xml за допомогою елемента
Модель дозволів Android пройшла кілька етапів еволюції. До Android 6.0 (API 23) всі дозволи надавалися під час встановлення — користувач бачив повний список і погоджувався або відмовлявся від встановлення застосунку. Починаючи з Android 6.0, дозволи рівня dangerous запитуються під час виконання (Runtime Permissions), що дає користувачеві більш гнучкий контроль.
Дозволи поділяються на чотири рівні захисту: normal (автоматично надаються під час встановлення), dangerous (вимагають runtime-запиту), signature (доступні лише застосункам, підписаним тим самим сертифікатом) та special (вимагають окремого ввімкнення в налаштуваннях). Кожен рівень має свій механізм надання та відкликання.
За даними Google I/O 2024, Android 15 планує впровадити більш деталізовані дозволи — користувач зможе надавати доступ лише до певних файлів у медіатеці, а не до всієї бібліотеки. Це продовжує тенденцію Android до мінімізації обсягу даних, що надаються за замовчуванням.
На відміну від iOS, де всі дозволи запитуються під час виконання (runtime), Android поділяє дозволи на ті, що встановлюються (install-time), і ті, що виконуються (runtime). Рівень normal надається автоматично під час встановлення без повідомлення користувача. Рівень dangerous вимагає явного діалогу, як у iOS.
Ще одна відмінність: в Android дозволи об’єднані в групи (permission groups). Якщо користувач погодився на доступ до камери, застосунок автоматично отримує доступ до мікрофона — вони в одній групі MICROPHONE. У iOS кожен дозвіл запитується окремо незалежно від групи.
| Версія Android | Зміна в моделі дозволів |
|---|---|
| Android 1.0–5.x | Всі дозволи надаються під час встановлення |
| Android 6.0 (API 23) | Введення Runtime Permissions для рівня dangerous |
| Android 10 (API 29) | Scoped Storage — обмежений доступ до файлової системи |
| Android 11 (API 30) | Автоскидання дозволів — невикористовувані дозволи скидаються |
| Android 14 (API 34) | Runtime дозволи для медіа-доступу (фото, відео, аудіо) |
Android визначає чотири рівні захисту для дозволів, кожен з власними правилами надання. Розглянемо кожен рівень докладно.
Normal дозволи надаються автоматично під час встановлення застосунку без повідомлення або запиту до користувача. Вони покривають доступ до низькоризикових функцій, які не загрожують приватності користувача: INTERNET, ACCESS_NETWORK_STATE, VIBRATE, BLUETOOTH. Користувач не бачить діалогу згоди — дозвіл вважається наданим за фактом встановлення.
Розробнику не потрібно обробляти запит у коді для normal дозволів — достатньо оголосити їх у маніфесті. Однак в Android 12+ під час встановлення з Google Play користувач бачить вкладку «Дозволи» з переліком усіх normal дозволів, що підвищує прозорість. Згідно з Statista (2024), понад 90% застосунків у Google Play використовують INTERNET як найпоширеніший normal дозвіл.
Dangerous дозволи покривають доступ до даних і функцій, які можуть порушити приватність: камера, мікрофон, геолокація, контакти, SMS, телефон, календар, датчики тіла. Ці дозволи вимагають двоетапного механізму: декларація в маніфесті + запит під час виконання через ActivityCompat.requestPermissions().
Користувач може відмовити в наданні dangerous дозволу, і застосунок повинен коректно обробити цей сценарій. В Android 11+ якщо користувач двічі відмовив, наступні запити не показують системний діалог — система автоматично повертає DENIED. У цьому випадку потрібно направляти користувача в налаштування.
Рівень signature — дозвіл надається автоматично, якщо застосунок підписано тим самим сертифікатом, що й система або інший застосунок, який визначив дозвіл. Використовується для системних і корпоративних застосунків. Приклад: BIND_ACCESSIBILITY_SERVICE — доступно лише системним застосункам.
Рівень special (SYSTEM_ALERT_WINDOW, WRITE_SETTINGS, REQUEST_INSTALL_PACKAGES, MANAGE_EXTERNAL_STORAGE) — вимагає окремої дії користувача через системні налаштування. Застосунок може відкрити сторінку налаштувань за допомогою Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION). Google Play обмежує використання special дозволів і вимагає обґрунтування у формі під час публікації.
Починаючи з Android 6.0, всі dangerous дозволи вимагають запиту під час виконання. Розглянемо повний цикл роботи з runtime permissions на Kotlin.
Перед викликом API, що вимагає dangerous дозволу, завжди перевіряйте поточний статус через ContextCompat.checkSelfPermission(). Якщо статус PERMISSION_GRANTED — можна викликати API. Якщо PERMISSION_DENIED — потрібно запитати дозвіл через ActivityResultContract RequestPermission (AndroidX) або застарілий requestPermissions().
Рекомендується використовувати ActivityResultContracts.RequestMultiplePermissions для запиту кількох дозволів одночасно. Google рекомендує групувати пов’язані дозволи (наприклад, камера + мікрофон для відеозапису) в один діалог, щоб користувач бачив повний контекст запиту.
import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
class CameraActivity : AppCompatActivity() {
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
} else {
explainWhyPermissionNeeded()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkCameraPermission()
}
private fun checkCameraPermission() {
when {
ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
shouldShowRequestPermissionRationale(
Manifest.permission.CAMERA
) -> {
showRationale()
}
else -> {
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
}
Якщо користувач двічі відмовив, Android переводить запит у стан «Never ask again». У цьому випадку shouldShowRequestPermissionRationale() повертає false, і системний діалог не буде показано. Застосунок повинен направити користувача в системні налаштування через Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).
Важливо: не показуйте діалог із пропозицією відкрити налаштування одразу після першої відмови — це сприймається як агресивна поведінка. Використовуйте shouldShowRequestPermissionRationale() для визначення, чи потрібно показувати пояснення. Material Design Guidelines рекомендують показувати екран із поясненням цінності доступу, а не просто кнопку «Відкрити налаштування».
private fun openAppSettings() {
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
).also { intent ->
startActivity(intent)
}
}
private fun showPermissionSettings() {
AlertDialog.Builder(this)
.setTitle("Доступ до камери")
.setMessage("Дозвольте доступ до камери в Налаштуваннях, "
+ "щоб робити фото для профілю")
.setPositiveButton("Відкрити налаштування") { _, _ ->
openAppSettings()
}
.setNegativeButton("Скасувати", null)
.show()
}
Файл AndroidManifest.xml містить елемент
Кожен дозвіл оголошується окремим елементом
Наприклад, дозвіл WRITE_EXTERNAL_STORAGE не потрібен на Android 10+ (Scoped Storage), тому вказуйте maxSdkVersion="28" (Android 9). Це запобігає зайвим питанням від користувачів на нових версіях. Android Studio попереджає про рекомендовані maxSdkVersion через Lint.
<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Normal permissions (install-time) -->
<uses-permission
android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Dangerous permissions (runtime) -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Legacy storage permission limited to API 28 and below -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<application>
<!-- ... -->
</application>
</manifest>
Елемент
Рекомендується для всіх апаратних функцій вказувати required="false" і перевіряти доступність програмно через PackageManager.hasSystemFeature(). Це розширює аудиторію вашого застосунку. Єдиний виняток — якщо функція критична для роботи застосунку (застосунок для замовлення таксі без GPS не має сенсу).
Правильна робота з дозволами — ключовий аспект якості Android-застосунку. Розглянемо основні рекомендації та типові помилки.
Запитуйте лише ті дозволи, які дійсно необхідні для роботи застосунку. Кожен зайвий дозвіл знижує конверсію встановлень і збільшує кількість відмов. Google Play Console показує, скільки користувачів відмовилися від встановлення через набір дозволів. За даними AppBrain (2024), застосунки з 10+ dangerous дозволами мають на 35% менше встановлень.
Регулярно переглядайте список дозволів. Видаляйте невикористовувані, особливо під час переходу на нові версії Android, де деякі дозволи стали необов’язковими. Наприклад, з появою фото-пікера (ActivityResultContracts.PickVisualMedia) в Android 13+ доступ до медіатеки можна отримувати без dangerous дозволу READ_MEDIA_IMAGES.
Перед запитом dangerous дозволу покажіть користувачеві екран із поясненням, навіщо потрібен цей дозвіл і яку цінність він дає. Material Design рекомендує використовувати bottom sheet або діалог з іконкою, коротким текстом і кнопкою «Продовжити». Rationale підвищує згоду на 20-30% порівняно з прямим запитом.
Перевіряйте shouldShowRequestPermissionRationale() перед викликом launch(). Якщо true — покажіть rationale. Якщо false — або дозвіл уже надано, або користувач відмовився назавжди (never ask again). В останньому випадку покажіть кнопку «Відкрити налаштування», а не повторюйте запит.
Протестуйте всі можливі сценарії: надання дозволу, відмова, відмова назавжди, відкликання дозволу в налаштуваннях, скидання дозволів (Android 11+ auto-reset). Кожен сценарій повинен оброблятися без крашу та без втрати даних. Android Testing Guide рекомендує використовувати бібліотеку TestPermission для автоматизації тестування.
Особливу увагу приділіть сценарію, коли користувач відкликав дозвіл під час роботи застосунку (згорнутий застосунок → Налаштування → відкликання). При поверненні в застосунок перевірте всі дозволи в onResume(). Не покладайтеся на кешування статусу дозволів — користувач може змінити їх у будь-який момент.
Часті запитання
Так, якщо SDK включає у свій маніфест дозвіл, він об’єднується з маніфестом застосунку під час збірки. Ви можете вимкнути непотрібний дозвіл SDK за допомогою tools:node="remove" в AndroidManifest.xml.
Виклик API без дозволу викличе SecurityException, що призведе до крашу застосунку. Завжди перевіряйте статус дозволу перед використанням відповідного API та обробляйте відмову коректно.
У налаштуваннях пристрою: Налаштування → Застосунки → [ваш застосунок] → Дозволи. Для скидання всіх дозволів використовуйте adb команду: adb shell pm reset-permissions.
Так, за допомогою ActivityResultLauncher у Fragment або Service. Однак діалог запиту завжди вимагає UI-контексту Activity. Для Service ви можете показати Notification з Intent, що відкриває Activity із запитом.
Наприклад, WRITE_EXTERNAL_STORAGE не потрібен на Android 10+ (Scoped Storage). Вказавши android:maxSdkVersion="28", ви виключаєте декларацію дозволу на нових версіях, що покращує сумісність і зменшує список дозволів, що запитуються.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також