close

2016-02-21 15:29:16 +00001

Android M 的 Permission 處理方式開始走向和 iOS 類似的模式,
App 在使用到需要某些特定權限的功能時,
需要動態向使用者要求授予。
這樣子的好處是使用者不用在第一次安裝 App 時,
就一股腦的將所有權限都给了 App。

但對開發者就必需開始著手處理這樣子的動態權限模式。
基本上,
只有 Android 認為屬於危險群組的權限才需要進行動態要求。
有哪些請參照 http://developer.android.com/intl/zh-tw/guide/topics/security/permissions.html#normal-dangerous

現在已經有很多第三方程式庫幫忙處理權限問題,
請參考 https://gist.github.com/dlew/2a21b06ee8715e0f7338

不過如果我們想要手刻動態權限處理的話,
老實說也不會太難。

我做了一個簡單的手刻範例程式:https://github.com/ddsakura/AndroidRuntimePermissionExample

以下為其中要點:

1. 本範例以危險權限 WRITE_EXTERNAL_STORAGE 為例,請先在 AndroidManifest.xml 中宣告

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

2. 善用 Support Lib 來幫助我們 確認是否使用者有給予我們這個權限

private boolean hasExternalStoragePermission() {
return ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}

3. 如果沒有權限,我們可以利用以下 code 要求使用者給予我們權限

ActivityCompat.requestPermissions(MainActivity.this, new String[] {
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CODE_ASK_WRITE_EXTERNAL_STORAGE_PERMISSIONS);

4. 當使用者第一次被要求,會看到如下畫面

2016-02-21 15:29:16 +00001

5. 如果使用者直接按下 ALLOW 就天下太平,但如果按下 DENY,那麼下次我們再要求權限時,Google 希望我們能給使用者一些為什麼要權限的說明,但要怎麼知道我們是第一次要權限還是第 N 次要呢?請使用 shouldShowRequestPermissionRationale 方法,當回傳 true 就是系統希望我們給使用者些說明,也就是第 N 次要權限的狀態。

if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Snackbar.make(view, "This is explanation: Please give us permission", Snackbar.LENGTH_LONG)
.setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
requestExternalStoragePermission();
}
}).show();
}

6. 在我的範例中,使用者會因此看到下方畫面

2016-02-21 15:29:42 +00001

7. 當點下 OK 按鈕就會再次彈出系統要求權限的畫面,但是跟第一次要求權限時稍有不同,多了 Never ask again 選項

2016-02-21 15:29:47 +00001 

8. 如果使用者點選 ALLOW,一樣天下太平;點選 DENY,我們還是可以回到第 5 步,再次跟使用者解釋為什麼我們要權限,並請他們給予。

9. 最怕使用者選取 Never ask again 並點 DENY

2016-02-21 15:30:14 +00001

10. 如此一來,當我們再次在 app 中向使用者要求權限,Android 會直接跟我們說沒有要到權限,但是所有要求權限的系統視窗通通不會出現了!

11.但是我們還是很想要這個權限呀!目前唯一的方法就是請使用者到 Android 系統的 App setting 手動將權限給予 app。

2016-02-21 15:30:33 +00001

12. 在程式中我們要如何處理這種狀態呢?其實當呼叫完第 3 步的要求權限方法,我們都可以得到一個回呼函式 onRequestPermissionsResult ,當使用者按下 ALLOW,大致可以用以下程式處理:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

switch (requestCode) {
case REQUEST_CODE_ASK_WRITE_EXTERNAL_STORAGE_PERMISSIONS:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted!
if (mFab != null) {
Snackbar.make(mFab, "We just got this runtime permission :)", Snackbar.LENGTH_LONG).show();
}
}
...
}
}

13. 當我們拿不到使用者授權時,亦可以透過這個回呼得到狀況,此時我們同樣可以透過 shouldShowRequestPermissionRationale 方法,來幫助我們確認使用者是否有選取 Never ask again,如果是 false,表示我們不需要再給使用者說明了!我猜測 Google 的思維是使用者不想再看到 app 要求權限,所以也就不用再跟使用者說明為什麼要權限了!

BUT 山不轉人轉,既然知道這個狀況,我們就可彈出類似 Snackbar 的訊息引導使用者到 app setting page 給予權限。

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

switch (requestCode) {
case REQUEST_CODE_ASK_WRITE_EXTERNAL_STORAGE_PERMISSIONS:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
...
} else {
if (!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (mFab != null) {
Snackbar.make(mFab,
"On no, user deny to grant this runtime permission, and also check never ask again!",
Snackbar.LENGTH_LONG)
.setAction("Go to App Setting to grant permission", new View.OnClickListener() {
@Override
public void onClick(View view) {
...
}
}).show();
}
}
}
break;
...
    }
}

14. 我們可以透過以下語法將使用者導到 App setting page

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", getPackageName(), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

15. 但很遺憾的只能到以下這頁,沒辦法指定到 Permissions 的頁面。我們必需在 app 中說明清楚,不然使用者可能到這頁也不知道要做什麼。

2016-02-21 15:30:29 +00001

以上是目前,
我覺得手刻動態權限,
比較完整的處理方式。
如果有錯誤、遺漏或可以加強的地方,
歡迎留言跟我說:)

Reference:
a. http://android-developers.blogspot.tw/2015/08/building-better-apps-with-runtime.html
b. https://developer.android.com/intl/zh-tw/training/permissions/index.html
c. https://www.google.com/design/spec/patterns/permissions.html
d. https://guides.codepath.com/android/Understanding-App-Permissions
 

 

arrow
arrow
    全站熱搜

    賽拉維‧柯南 發表在 痞客邦 留言(0) 人氣()