Dangerous Permission — دستهای از مجوزها در Android است که نیاز به رضایت صریح کاربر از طریق دیالوگ runtime در حین اجرای برنامه دارند. طبق Android Developer Guide, 2024, مجوزهای خطرناک دارای ProtectionLevel dangerous هستند و به دادههای محرمانه: دوربین، میکروفون، موقعیت جغرافیایی و مخاطبان دسترسی میدهند. بدون رضایت صریح کاربر، برنامه نمیتواند از این قابلیتها استفاده کند.
نکات اصلی
Dangerous Permission — دستهای از مجوزهای سیستمی Android است که به دادههای محرمانه کاربر دسترسی میدهد. برخلاف مجوزهای عادی، مجوزهای خطرناک به طور خودکار هنگام نصب صادر نمیشوند — برنامه باید به صراحت در زمان اجرا از طریق مکانیزم runtime که در Android 6.0 Marshmallow (API 23) معرفی شده است، آنها را درخواست کند.
نیاز به درخواست صریح به دلیل ماهیت دادههایی است که این مجوزها محافظت میکنند: موقعیت جغرافیایی کاربر، مخاطبان شخصی، محتوای دوربین و میکروفون، تاریخچه تماسها و SMS. Android این دادهها را حساس میداند و نیاز به رضایت آگاهانه کاربر دارد. طبق Android Privacy Sandbox (2024), کاربران به طور متوسط حدود 30 درصد از درخواستهای runtime را رد میکنند.
ویژگی کلیدی Dangerous Permission — امکان لغو در هر زمان. کاربر میتواند به تنظیمات — برنامهها — مجوزها برود و کلید هر مجوز خطرناک را تغییر دهد. برنامه باید آماده باشد که مجوزی که اعطا شده است، ممکن است در هر زمان بدون راهاندازی مجدد لغو شود.
سطح حفاظت dangerous در تعاریف سیستمی مجوزها در سطح OS تنظیم میشود. وقتی برنامه uses-permission با چنین protectionLevel اعلام میکند، سیستم مجوز را به عنوان نیازمند درخواست runtime علامتگذاری میکند. برخلاف normal، مجوزهای dangerous همیشه در رابط کاربری سیستم مدیریت مجوزها نمایش داده میشوند و قابل لغو هستند.
همه مجوزهای خطرناک بر اساس ویژگی عملکردی در Permission Group گروهبندی شدهاند. به عنوان مثال، CAMERA و CAMERA2 در گروه CAMERA هستند، ACCESS_FINE_LOCATION و ACCESS_COARSE_LOCATION — در گروه LOCATION. اگر کاربر یک مجوز از گروه را اعطا کرده باشد، سایر مجوزهای همان گروه به طور خودکار بدون دیالوگ اضافی اعطا میشوند.
درخواست runtime — مکانیزمی است که در آن برنامه API سیستم را برای نمایش دیالوگ با درخواست مجوز فراخوانی میکند. کاربر یک پنجره modal با نام مجوز و دکمههای Allow و Deny میبیند. پس از پاسخ، سیستم callback onRequestPermissionsResult را با نتیجه فراخوانی میکند.
چرخه کامل شامل سه مرحله است: بررسی وضعیت از طریق checkSelfPermission، فراخوانی requestPermissions در صورت عدم وجود مجوز و پردازش نتیجه در onRequestPermissionsResult. بررسی وضعیت اجباری است، زیرا کاربر ممکن است مجوز را در هر زمان از طریق تنظیمات لغو کند و فراخوانی تابع بدون بررسی منجر به SecurityException خواهد شد.
fun checkAndRequestCameraPermission() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
else -> {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_CODE
)
}
}
}
پردازش نتیجه در ActivityResultLauncher یا onRequestPermissionsResult انجام میشود. رویکرد مدرن توصیهشده — استفاده از ActivityResultContracts.RequestPermission که API تمیزتری بدون کدهای درخواست صریح ارائه میدهد. این قرارداد Boolean بازمیگرداند — آیا مجوز اعطا شده است یا خیر.
مجوزهای خطرناک را دقیقاً در زمینه استفاده از قابلیت درخواست کنید، نه هنگام راهاندازی برنامه. اگر کاربر دکمه دوربین را فشار داده است — CAMERA را درخواست کنید. اگر نقشه را باز کرده است — LOCATION را درخواست کنید. درخواست زمینهای دو برابر بیشتر از درخواست همه مجوزها در اولین راهاندازی تأیید میگیرد. همچنین توصیه میشود در هر بار بیش از یک مجوز درخواست نکنید تا کاربر بفهمد کدام قابلیت نیاز به دسترسی دارد.
Android تعریف میکند چندین گروه مجوز خطرناک که هر کدام شامل یک تا چند ثابت هستند. کاملترین فهرست در کلاس Manifest.permission ارائه شده است. در زیر گروهها و مجوزهای اصلی مورد استفاده در توسعه آورده شده است.
| گروه Permission Group | مجوزها | API دسترسی |
|---|---|---|
| CAMERA | CAMERA | Camera API, CameraX |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION | FusedLocationProvider, Geofence |
| MICROPHONE | RECORD_AUDIO | MediaRecorder, AudioRecord |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | TelephonyManager |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | ContactsContract |
| SMS | READ_SMS, SEND_SMS, RECEIVE_SMS | SmsManager |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE | MediaStore, File API |
| CALENDAR | READ_CALENDAR, WRITE_CALENDAR | CalendarContract |
از Android 12 به بعد، Google الزامات برخی مجوزها را سختتر کرد. به عنوان مثال، BLUETOOTH_CONNECT و BLUETOOTH_SCAN خطرناک شدند و نیاز به درخواست runtime دارند. همچنین مجوز BODY_SENSORS_BACKGROUND برای دسترسی پسزمینه به حسگرها ظاهر شد. توسعهدهندگان باید targetSdkVersion را بهروز کنند و درخواستها را در نسخههای فعلی OS آزمایش کنند.
Android 13 (API 33) مجوزهای جدیدی برای اعلانها (POST_NOTIFICATIONS) و فایلهای رسانهای (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO) معرفی کرد که جایگزین READ_EXTERNAL_STORAGE عمومی شد. اکنون دسترسی به عکسها، ویدیوها و صدا به طور جداگانه از طریق مجوزهای تخصصی بدون یک دیالوگ واحد درخواست میشود.
Dangerous و Normal Permission اساساً از نظر روش اعطا، امکان لغو و UX تفاوت دارند. Normal به طور خودکار هنگام نصب صادر میشود، Dangerous نیاز به دیالوگ runtime صریح دارد. Normal از طریق تنظیمات قابل لغو نیست، Dangerous را میتوان در هر زمان خاموش کرد. این عدم تقارن الگوهای توسعه متفاوتی را ایجاد میکند.
از نظر کد، مجوزهای خطرناک به کار بیشتری نیاز دارند: checkSelfPermission, requestPermissions, مدیریت رد. برای Normal یک خط در AndroidManifest.xml کافی است. در عین حال، Dangerous Permission به کاربر کنترل میدهد که اعتماد را افزایش میدهد، به ویژه برای قابلیتهای حساس مانند دوربین یا موقعیت جغرافیایی.
انتخاب بین دستهها پیش روی توسعهدهنده نیست — توسط سیستم تعیین میشود. توسعهدهنده فقط uses-permission را اعلام میکند و سیستم بر اساس protectionLevel دسته را تعیین میکند. با این حال، استراتژی درخواست مجوزهای خطرناک بر تجربه کاربر تأثیر میگذارد: دیالوگهای مکرر یا نامناسب رتبه برنامه را کاهش میدهند.
روش مدرن درخواست مجوزها در Kotlin — استفاده از ActivityResultContracts.RequestMultiplePermissions یا RequestPermission. این قراردادها در کتابخانه androidx.activity قرار دارند و API تمیزی مبتنی بر لامبدا بدون نیاز به بازنویسی onRequestPermissionsResult ارائه میدهند.
class CameraActivity : AppCompatActivity() {
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
} else {
showPermissionDeniedMessage()
}
}
fun requestCamera() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED ->
openCamera()
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
) ->
showRationaleDialog()
else ->
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
وقتی برنامه به چند مجوز خطرناک به طور همزمان نیاز دارد، از RequestMultiplePermissions استفاده کنید. قرارداد Map<String, Boolean> بازمیگرداند که در آن کلید نام مجوز و مقدار نتیجه است. این برای اولین راهاندازی که نیاز به CAMERA و RECORD_AUDIO برای ضبط ویدیو است، راحت میباشد.
اگر کاربر درخواست را رد کرد، متد shouldShowRequestPermissionRationale true بازمیگرداند. این سیگنالی برای نشان دادن توضیح درباره نیاز به مجوز است. بهترین روش — نمایش یک دیالوگ سفارشی با توضیح و دکمه تکرار. اگر کاربر دوباره درخواست را با تیک Never Ask Again رد کرد، shouldShowRequestPermissionRationale false بازمیگرداند و باید به تنظیمات هدایت کرد.
Never Ask Again — پرچمی است که کاربر میتواند هنگام رد کردن دوباره دیالوگ runtime تنظیم کند. پس از آن، دیالوگ استاندارد برای این مجوز دیگر نمایش داده نمیشود. تنها راه اعطای دسترسی — هدایت کاربر به تنظیمات سیستم برنامهها.
توسعهدهنده باید دو سناریوی رد را تشخیص دهد: اول — وقتی shouldShowRequestPermissionRationale true بازمیگرداند (کاربر رد کرده اما دیالوگ هنوز قابل نمایش است) و دوم — وقتی متد false بازمیگرداند (Never Ask Again فعال است یا مجوز توسط سیاست مسدود شده است). در حالت دوم باید دکمه باز کردن تنظیمات را نشان داد.
fun handlePermissionDenied(permission: String) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
)) {
showRationaleDialog(permission)
} else {
showSettingsRedirectDialog(permission)
}
}
private fun showSettingsRedirectDialog(permission: String) {
AlertDialog.Builder(this)
.setTitle("دسترسی ممنوع است")
.setMessage(
"مجوز مسدود شده است. تنظیمات را باز کنید."
)
.setPositiveButton("تنظیمات") { _, _ ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts(
"package", packageName, null
)
)
startActivity(intent)
}
.show()
}
مهم است که اگر shouldShowRequestPermissionRationale false بازگردانده است، مجوز را دوباره درخواست نکنید. فراخوانی مکرر requestPermissions در این حالت دیالوگ را نشان نمیدهد — نتیجه بلافاصله با DENIED بدون توضیح میآید. کاربر با رفتاری نامفهوم مواجه میشود که بر تجربه استفاده از برنامه تأثیر منفی میگذارد.
سوالات متداول
Dangerous Permission شامل مجوزهای با ProtectionLevel dangerous است: CAMERA, RECORD_AUDIO, ACCESS_FINE_LOCATION, READ_CONTACTS, READ_SMS, READ_CALENDAR و موارد دیگر. فهرست کامل در کلاس Manifest.permission موجود است.
از ContextCompat.checkSelfPermission استفاده کنید، context و نام مجوز را ارسال کنید. متد PERMISSION_GRANTED یا PERMISSION_DENIED بازمیگرداند. بررسی باید قبل از هر فراخوانی API که نیاز به مجوز خطرناک دارد انجام شود.
Permission Group مجوزهای خطرناک مرتبط را گروهبندی میکند. اگر کاربر یک مجوز از گروه را اعطا کرده باشد، بقیه به طور خودکار اعطا میشوند. به عنوان مثال، LOCATION شامل ACCESS_FINE_LOCATION و ACCESS_COARSE_LOCATION است.
پس از رد، shouldShowRequestPermissionRationale را بررسی کنید. اگر متد false بازگرداند و مجوز هنوز اعطا نشده باشد — Never Ask Again فعال است. کاربر را از طریق Intent با ACTION_APPLICATION_DETAILS_SETTINGS به تنظیمات هدایت کنید.
بله، آنها اجباری باقی میمانند. در Android 13+ برخی مجوزها تغییر کردند: POST_NOTIFICATIONS به یک مجوز runtime جداگانه تبدیل شد و READ_EXTERNAL_STORAGE با READ_MEDIA_IMAGES برای دسترسی دقیق به فایلهای رسانهای جایگزین شد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید