Run Time Permission در اندروید چیست؟
گوگل در معرفی خود از اندروید 6.0 یک مفهوم جدید از مدل permission را معرفی کرد. بر اساس این مفهوم جدید حالا اپلیکیشن ها در اندروید 6.0 به بعد می تواند در هر زمان از اجرای اپلیکیشن که به permission نیاز دارند ان را از کاربر درخواست کنند. که به این مفهوم جدید Run Time Permission می گویند.
این ویژگی در آخر برای کاربران بسیار مفید است زیرا خیال کاربران دستگاه های اندرویدی را از دسترسی هایی که به اپلیکیشن می دهد راحت می کند و امنیت ان را بالا تر می برد.
اما برای توسعه این مفهوم از permission نیاز به تلاش بیشتری برای توسعه دهندگان می باشد. همچنین در این مفهوم از permission امکان رد کردن در خواست توسط کاربر وجود دارد که توسعه دهنده باید احتمال به وجود آمدن این اتفاق را هم مدیریت کند. خوشبختانه درخواست run time permission آنقدرها هم که فکرش را می کنید سخت نیست و فقط با چند خط کد می توانید یک سیستم مدیریت permission تمام عیار برای اپلیکیشن خود بسازید. اما قبل از این نیاز است تا دقیقا مفهومRun Time Permission را درک کنید.
درک مفهوم مدل Run Time Permission در اندروید:
Android System Permission دارای دسته بندی های بسیار زیادی است. اما وقتی در اندروید 6.0 به بعد در زمان اجرای اپلیکیشن در خواست Permission را می دهید به دو دسته Normal و Dangerous تقسیم بندی می شود که شما می توانید به هر کدام از این دو دسته دسترسی داشته باشید. اولین قدم برای این کار بیان کردن آن در فایل manifest در پروژه خود می باشد. تفاوت بین این دو دسته در این می باشد که Dangerous Permissions فقط در زمان اجرا اپلیکیشن توسط کاربر اجازه داده می شود. در غیر این صورت ممکن است اپلیکیشن شما به علت مشکل امنیتی به اصطلاح دچار crash شود. به عبارت دیگر ما برای permission های دسته Normal نیاز به ارسال درخواست به کاربر در زمان اجرا اپلیکیشن نداریم.
<?xml version="1.0" encoding="utf-8"?> <manifest package="com.truiton.runtimepermissions" xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
در بالایِ Android manifest اولین permission که android.permission.INTERNET هست، جزو دسته normal Permission قرار می گیرد و بعدی android.permission.READ_CONTACT و android.permission.WRITE_EXTERNAL_STORAGE جزو دسته بندی dangerous permission قرار می گیرند . از این رو ما در مثال زیر می خواهیم به شما نشان دهیم که چگونه از run time permission در اپلیکیشن خود استفاده کنید.
درخواست Run Time Permission در اندروید:
از اندروید 6.0 به بعد، مشخص کردن permission ها در فایل manifest برای استفاده از permission ها دیگر کافی نیست. این روش فقط برای اطلاع دادن به سیستم که اپلیکیشن مورد نظر از این permission ها استفاده می کند، کاربرد دارد و برای استفاده از permission شما باید به صورت run time در خواست permission خود را ارسال کنید. در مثال زیر همانطور که در بالا تر گفتیم ما قصد استفاده از دو permission که شامل android.permission.READ_CONTACT و android.permission.WRITE_EXTERNAL_STORAGE است را داریم.
معمولا زمانی باید از permission استفاده کرد که به آن نیاز هست. از این رو زمانی که به یک permission نیاز دارید می توانید از کد زیر برای ارسال درخواست permission به صورت run time استفاده کنید.
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat .checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale (MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale (MainActivity.this, Manifest.permission.READ_CONTACTS)) { Snackbar.make(findViewById(android.R.id.content), "Please Grant Permissions", Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() { @Override public void onClick(View v) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission .WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_CONTACTS}, REQUEST_PERMISSIONS); } }).show(); } else { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission .WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_CONTACTS}, REQUEST_PERMISSIONS); } } else { //Call whatever you want myMethod(); }
در مثال بالا اگر شما permission مورد نظر خود را داشته باشید متود myMethod() فراخوانی می شود. اگر درخواست شما توسط کاربر رد یا تایید شود متود onRequestPermissionResult() فراخوانی می شود.
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_PERMISSIONS: { if ((grantResults.length > 0) && (grantResults[0] + grantResults[1]) == PackageManager.PERMISSION_GRANTED) { //Call whatever you want myMethod(); } else { Snackbar.make(findViewById(android.R.id.content), "Enable Permissions from settings", Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(Uri.parse("package:" + getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); startActivity(intent); } }).show(); } return; } } }
این یک متود اضافه است که شما نیاز دارید تا در activity خود ایجاد کنید ، تا پاسخ در خواست run time permission را دریافت کنید. اگر یک بار پاسخ در متود بالایی دریافت شود ، و اگر permission مورد نظر داده شود شما می توانید متود myMethod() را برای عملکرد دلخواه خود فراخوانی کنید. همچنین در متود بالایی ما این مورد که permission مورد نظر داده نشود را هم در نظر گرفتیم. در این حالت ما از کاربر در خواست می کنیم که به صفحه تنظیمات گوشی خود رفته و به صورت دستی permission مورد نظر را بدهد.
Run Time Permission در اندروید 6.0 – Design Pattern:
با توجه به کد ها و متود هایی که در بالا گفته ایم باید متوجه شده باشید که ارسال درخواست برای Run Time Permission بسیار ساده است. اما ایجاد این کد ها در کد های موجود خود، برای هر permission یک فعالیت بسیار وقت گیر می باشد. بنابرین به یک design pattern برای این کار نیاز دارید که کافیست یکبار ان را بنویسید و از ان بار ها و بار ها استفاده کنید.
برای این کار اجازه دهید تا یک کلاس Abstract activity طراحی کنیم که با متود onRequestPermissionResult() ایجاد می شود. همچنین شما می توانید با کمی تغییر در کد زیر از تحویل دادن یا ندادن پاسخ، اعطای permission به activity فرزند اطلاع پیدا کنید.
package ir.zerotohero.runtimepermissions; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.util.SparseIntArray; import android.view.View; /** * Created by MG on 03-04-2016. */ public abstract class RuntimePermissionsActivity extends AppCompatActivity { private SparseIntArray mErrorString; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mErrorString = new SparseIntArray(); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); int permissionCheck = PackageManager.PERMISSION_GRANTED; for (int permission : grantResults) { permissionCheck = permissionCheck + permission; } if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) { onPermissionsGranted(requestCode); } else { Snackbar.make(findViewById(android.R.id.content), mErrorString.get(requestCode), Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(Uri.parse("package:" + getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); startActivity(intent); } }).show(); } } public void requestAppPermissions(final String[] requestedPermissions, final int stringId, final int requestCode) { mErrorString.put(requestCode, stringId); int permissionCheck = PackageManager.PERMISSION_GRANTED; boolean shouldShowRequestPermissionRationale = false; for (String permission : requestedPermissions) { permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission); shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || ActivityCompat.shouldShowRequestPermissionRationale(this, permission); } if (permissionCheck != PackageManager.PERMISSION_GRANTED) { if (shouldShowRequestPermissionRationale) { Snackbar.make(findViewById(android.R.id.content), stringId, Snackbar.LENGTH_INDEFINITE).setAction("GRANT", new View.OnClickListener() { @Override public void onClick(View v) { ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode); } }).show(); } else { ActivityCompat.requestPermissions(this, requestedPermissions, requestCode); } } else { onPermissionsGranted(requestCode); } } public abstract void onPermissionsGranted(int requestCode); }
برای در خواست به run time permission در اندروید ما باید به Activity بالا متود requestAppPermissions() را اضافه کنیم. به مثال زیر دقت کنید.
package ir.zerotohero.runtimepermissions; import android.Manifest; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Toast; public class MainActivity extends RuntimePermissionsActivity { private static final int REQUEST_PERMISSIONS = 20; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { MainActivity.super.requestAppPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, R.string .runtime_permissions_txt , REQUEST_PERMISSIONS); } }); } @Override public void onPermissionsGranted(final int requestCode) { Toast.makeText(this, "Permissions Received.", Toast.LENGTH_LONG).show(); } }
نتیجه:
این روشِ پیاده سازی مدلِ Run Time Permission در اندروید از ورژن 6.0 به بعد پشتیبانی می شود، که در بالا یک کد کوچک شده از ان چیزی بود که شما نیاز دارید تا در activity خود به وجود بیاورید. برای در خواست permission می توانید با فراخوانی متود reqestAppPermission() و دریافت نتیجه این در خواست از متود onPermissionGranted() استفاده کنید.
امیدواریم که این اموزش برای شما مفید واقع شده باشد. با تیم Zero To Hero در اینده همراه باشید
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.