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) | مجوزهای زمان اجرا برای دسترسی به رسانه (عکس، ویدیو، صدا) |
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 از طریق Lint در مورد maxSdkVersion توصیهشده هشدار میدهد.
<!-- 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٪ در مقایسه با درخواست مستقیم افزایش میدهد.
قبل از فراخوانی launch()، shouldShowRequestPermissionRationale() را بررسی کنید. اگر true است — rationale را نشان دهید. اگر false است — یا مجوز قبلاً داده شده یا کاربر برای همیشه رد کرده (never ask again). در حالت آخر دکمه «باز کردن تنظیمات» را نشان دهید، نه اینکه درخواست را تکرار کنید.
همه سناریوهای ممکن را تست کنید: اعطای مجوز، رد، رد برای همیشه، لغو مجوز در تنظیمات، بازنشانی مجوزها (Android 11+ auto-reset). هر سناریو باید بدون crash و بدون از دست دادن داده مدیریت شود. Android Testing Guide استفاده از کتابخانه TestPermission را برای خودکارسازی تست توصیه میکند.
به سناریویی توجه ویژه داشته باشید که کاربر مجوز را در حین کار برنامه لغو میکند (برنامه کوچکشده → تنظیمات → لغو). پس از بازگشت به برنامه، همه مجوزها را دوباره از طریق onResume() بررسی کنید. به کش کردن وضعیت مجوزها اعتماد نکنید — کاربر میتواند آنها را در هر زمان تغییر دهد.
سوالات متداول
بله، اگر SDK مجوزی را در مانیفست خود قرار دهد، هنگام ساخت با مانیفست برنامه ادغام میشود. میتوانید مجوز غیرضروری SDK را با tools:node=«remove» در AndroidManifest.xml غیرفعال کنید.
فراخوانی API بدون مجوز باعث SecurityException میشود که منجر به crash برنامه میگردد. همیشه قبل از استفاده از 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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید