دسترسی زمان اجرا در برنامه‌نویسی اندروید

سلام. گوگل همزمان با معرفی اندروید مارشمالو (۶٫۰) از ویژگی تازه‌ای رونمایی کرد که امنیت کاربران رو می‌تونست بالا بره و البته عرصه رو برای مهاجمان تنگ‌تر بکنه؛ ویژگی جذابی به‌نام دسترسی زمان اجرا یا Runtime Permission. این ویژگی دردسرهای خودش رو داشت؛ چرا داشت؟ چون دیگه نداره!

مشکلات دسترسی زمان اجرا

گوگل طبق معمول آنچنان لقمه رو دور دهن مبارکش چرخونده که نفهمی چی به چیه! من بار اولی که می‌خواستم این ویژگی رو پیاده‌سازی کنم، وقتی مستندات گوگل رو دیدم، یه ساعت تو هپروت سیر می‌کردم 🙂 اما دسترسی زمان اجرا خیلی آسون پیاده‌سازی می‌شه!

دسترسی زمان اجرا برای کدام دسترسی‌ها؟

مهم‌ترین چیزی که برای پیاده‌سازی دسترسی زمان اجرا باید بدونید اینه که کدوم دسترسی‌ها رو باید زمان اجرای برنامه از کاربر بگیریم؛ دسترسی‌های اندروید رو می‌شه به سه دسته تقسیم کرد:

  1. دسترسی‌های عادی
  2. دسترسی‌های خطرناک
  3. دسترسی‌های سامانه‌ای (خیلی خطرناک)

دسترسی‌های عادی

این دسته از دسترسی‌ها، به‌صورت خودکار و هنگام نصب از طرف خود اندروید به برنامه داده می‌شه و نیازی به دریافت اجازه از کاربر نیست. در ادامه فهرستی از دسترسی‌های عادی رو می‌بینید:

WRITE_SYNC_SETTINGS
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CALL_COMPANION_APP
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
FOREGROUND_SERVICE
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MANAGE_OWN_CALLS
MODIFY_AUDIO_SETTINGS
NFC
NFC_TRANSACTION_EVENT
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_COMPANION_RUN_IN_BACKGROUND
REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
REQUEST_DELETE_PACKAGES
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
REQUEST_PASSWORD_COMPLEXITY
SET_ALARM
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_BIOMETRIC
USE_FINGERPRINT
USE_FULL_SCREEN_INTENT
WAKE_LOCK
WRITE_SYNC_SETTINGS

دسترسی‌های خطرناک

دستۀ دوم، دسترسی‌هایی هستند که در سطح بالاتری هستند و تا زمانی که کاربر اجازه نده، برنامه اون دسترسی رو نخواهد داشت.

دسترسی‌های خطرناک در ادامه فهرست شده‌اند:

ACCEPT_HANDOVER
ACCESS_BACKGROUND_LOCATION
ACCESS_COARSE_LOCATION
ACCESS_FINE_LOCATION
ACCESS_MEDIA_LOCATION
ACTIVITY_RECOGNITION
ADD_VOICEMAIL
ANSWER_PHONE_CALLS
BODY_SENSORS
CALL_PHONE
CAMERA
GET_ACCOUNTS
PROCESS_OUTGOING_CALLS
READ_PHONE_NUMBERS
READ_PHONE_STATE
READ_SMS
RECEIVE_SMS
RECEIVE_MMS
RECEIVE_WAP_PUSH
RECORD_AUDIO
USE_SIP
WRITE_CALENDAR
READ_CALENDAR
WRITE_CALL_LOG
READ_CALL_LOG
WRITE_CONTACTS
READ_CONTACTS
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

پیاده‌سازی دسترسی زمان اجرا

درخواست دسترسی به‌صورت تکی

اول از همه باید دسترسی(ها) رو توی Manifest تعریف کنیم:

<uses-permission android:name="android.permission.CAMERA"/>

خب حالا توی اکتیویتی که می‌خواین دسترسی رو بگرید، باید بررسی کنید که آیا این دسترسی به برنامه داده شده یا نه. اگه دسترسی داده شده بود، به کارش ادامه بده، اما اگه نه، پنجرۀ دریافت دسترسی باز بشه:

String[] requiredPermissions = new String[] {Manifest.permission.CAMERA};
int CAMERA_REQUEST_CODE = 100;
if (ContextCompat.checkSelfPermission(MainActivity.this,  requiredPermissions[0]) != PackageManager.PERMISSION_GRANTED) {
	// Permission denied, display permission request
} else {
	// Permission granted, enjoy programming!
}

حالا اگه دسترسی رو نداشتیم، باید از کاربر درخواست دسترسی کنیم، برای این کار، این کد رو توی عبارت if می‌نویسیم:

ActivityCompat.requestPermissions(MainActivity.this, requiredPermissions, CAMERA_REQUEST_CODE);

این متد سه پارامتر می‌گیره:

  1. کلاس اکتیویتی
  2. دسترسی موردنظر در قالب String[]
  3. یک کد جهت بررسی نتیجه درخواست (در این پارامتر هر عددی به دلخواه خودتون می‌تونید وارد کنید اما برای هر دسترسی باید متفاوت باشه)

کد کامل‌شدۀ عبارت شرطی:

String[] requiredPermissions = new String[] {Manifest.permission.CAMERA};
int CAMERA_REQUEST_CODE = 100;
if (ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[0]) != PackageManager.PERMISSION_GRANTED) {
	// Permission denied, display permission request
	ActivityCompat.requestPermissions(MainActivity.this, requiredPermissions, CAMERA_REQUEST_CODE);
} else {
	// Permission granted, enjoy programming!
}

درخواست دسترسی به‌صورت یکجا و همزمان

در بالا فقط یک دسترسی رو از کاربر گرفتیم، اما حالا می‌خوایم چندتا دسترسی رو با هم بگیریم.

اول از همه من دو تا دسترسی دیگه هم به Manifest اضافه می‌کنم:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

خب اینجا کافیه پارامترهای متد ActivityCompat.requestPermissions رو اینجوری ویرایش کنیم:

String[] requiredPermissions = new String[] {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
int PERMISSION_REQUEST_CODE = 100;
ActivityCompat.requestPermissions(MainActivity.this, requiredPermissions, PERMISSION_REQUEST_CODE);

اما در قسمت قبل ما در عبارت شرطی فقط بررسی کردیم که کاربر دسترسی دوربین رو داده یا نه، اما اینجا ما سه تا دسترسی رو درخواست می‌کنیم، پس باید سه تا عبارت شرطی هم براش تعریف کنیم:

if (ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[0]) != PackageManager.PERMISSION_GRANTED
	|| ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[1]) != PackageManager.PERMISSION_GRANTED
	|| ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[2]) != PackageManager.PERMISSION_GRANTED)

کد کامل‌شدۀ عبارت شرطی:

if (ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[0]) != PackageManager.PERMISSION_GRANTED
	|| ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[1]) != PackageManager.PERMISSION_GRANTED
	|| ContextCompat.checkSelfPermission(MainActivity.this, requiredPermissions[2]) != PackageManager.PERMISSION_GRANTED) {
		String[] requiredPermissions = new String[] {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
		int PERMISSION_REQUEST_CODE = 100;
		ActivityCompat.requestPermissions(MainActivity.this, requiredPermissions, PERMISSION_REQUEST_CODE);
}

دیدگاهتان را بنویسید