AndroidManifest Permissions са декларации за разрешения във файла AndroidManifest.xml, които определят до кои системни ресурси и данни приложението има достъп. Android изисква всяко разрешение да бъде посочено в манифеста преди използване на съответния API: от камера и геолокация до изпращане на SMS и достъп до контакти. Според Android Developer Documentation всяко разрешение се разделя на едно от четирите нива на защита: normal, dangerous, signature и special.
Основни точки
AndroidManifest Permissions е механизмът за сигурност на Android, който контролира достъпа на приложенията до защитени данни и системни функции. Всяко приложение трябва да декларира необходимите разрешения във файла AndroidManifest.xml с помощта на елемента <uses-permission>. Без декларация извикването на съответния API ще завърши с грешка за сигурност SecurityException.
Моделът на разрешения на Android премина през няколко етапа на еволюция. Преди Android 6.0 (API 23) всички разрешения се предоставяха при инсталиране — потребителят виждаше пълния списък и приемаше или отказваше инсталирането на приложението. От Android 6.0 нататък разрешенията от ниво dangerous се изискват по време на изпълнение (Runtime Permissions), което дава на потребителя по-гъвкав контрол.
Разрешенията се делят на четири нива на защита: normal (автоматично се предоставят при инсталиране), dangerous (изискват заявка по време на изпълнение), 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 | Всички разрешения се предоставят при инсталиране (install-time) |
| Android 6.0 (API 23) | Въвеждане на Runtime Permissions за ниво dangerous |
| Android 10 (API 29) | Scoped Storage — ограничен достъп до файловата система |
| Android 11 (API 30) | Автоматично нулиране на разрешения — неизползваните разрешения се нулират |
| Android 14 (API 34) | Runtime разрешения за медиен достъп (снимки, видео, аудио) |
Android определя четири нива на защита (protection levels) за разрешения, всяко със собствени правила за предоставяне. Нека разгледаме всяко ниво подробно.
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 съдържа елемента <uses-permission> за всяко разрешение, което приложението използва. Разрешенията се декларират на ниво <manifest> преди елемента <application>.
Всяко разрешение се декларира като отделен елемент <uses-permission> с атрибут android:name, указващ пълното име на разрешението. За разрешения, появили се в определени версии на Android, използвайте атрибута maxSdkVersion, за да ограничите декларацията само до необходимите версии — това подобрява съвместимостта.
Например разрешението 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>
Елементът <uses-feature> указва, че приложението изисква определен хардуер (камера, GPS, NFC). Атрибутът android:required=„false” позволява инсталиране на приложението на устройства без този хардуер — проверката за наличност се извършва в кода. Ако required=„true”, Google Play филтрира приложението и то става недостъпно за неподходящи устройства.
Препоръчително е за всички хардуерни функции да посочите 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също