Android 6.0 RuntimePermission

android6.0棉花糖,app將不會在安裝的時(shí)候授予權(quán)限。取而代之的是,app不得不在運(yùn)行時(shí)一個(gè)一個(gè)詢問用戶授予權(quán)限。

android {
    compileSdkVersion 23
    ...
  
    defaultConfig {
        ...
        targetSdkVersion 23
        ...
    }
}

如何app/build.gradle是23的話,在6.0上運(yùn)行一些權(quán)限,沒有做處理,會直接崩潰:

...
Caused by: java.lang.SecurityException: Permission Denial: 
opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord
{c3b3c66 16712:com.wuxiaolong.apksample/u0a62} (pid=16712, uid=10062)
requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
...

如果targetSdkVersion 22,就不會發(fā)生這樣的錯(cuò)誤,下面就來實(shí)踐下這個(gè)6.0運(yùn)行的權(quán)限。
效果預(yù)覽
按照慣例,先上效果圖:


說明:第一次請求授權(quán),是沒有“不再詢問”,拒絕后,再次請求授權(quán),就會出現(xiàn)“不再詢問”。

實(shí)踐

AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS" />
代碼調(diào)用

在需要使用到權(quán)限之前調(diào)用以下代碼:

private void mayRequestContacts() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            switch (checkSelfPermission(Manifest.permission.READ_CONTACTS)) {
                case PackageManager.PERMISSION_GRANTED:
                    // 已有授權(quán)
                    Log.i("wxl", "已有授權(quán)");
                    break;
                case PackageManager.PERMISSION_DENIED:
                    // 沒有權(quán)限:尚未請求過權(quán)限,
                    // 或者請求授權(quán)被拒絕,
                    // 或者曾經(jīng)授權(quán)過,但被用戶在設(shè)置中禁用權(quán)限
                    Log.i("wxl", "沒有權(quán)限:尚未請求過權(quán)限,或者請求授權(quán)被拒絕," +
                            "或者曾經(jīng)授權(quán)過, 但被用戶在設(shè)置中禁用權(quán)限");
                    /**
                     * 如果用戶勾上了“不再詢問”,這時(shí)候就不應(yīng)彈請求權(quán)限的對話框,
                     * 可以在請求權(quán)限之前用
                     * shouldShowRequestPermissionRationale判斷用戶是否拒絕過,
                     * 如果返回true,表示用戶拒絕過。
                     */
                    Log.i("wxl", "shouldShowRequestPermissionRationale==" 
                    + shouldShowRequestPermissionRationale(READ_CONTACTS));
                    if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
                        Snackbar.make(mEmailView, 
                        R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
                                .setAction(android.R.string.ok, new View.OnClickListener() {
                                    @Override
                                    @TargetApi(Build.VERSION_CODES.M)
                                    public void onClick(View v) {
                                        requestPermissions(new String[]{READ_CONTACTS}, 
                                        REQUEST_READ_CONTACTS);
                                    }
                                }).show();
                    } else {
                        requestPermissions(new String[]{READ_CONTACTS}, 
                        REQUEST_READ_CONTACTS);
                    }
                    break;
                default:
                    break;
            }
        }
    }

checkSelfPermission:檢查權(quán)限
requestPermissions:請求權(quán)限
shouldShowRequestPermissionRationale:判斷用戶是否拒絕過

授權(quán)回調(diào)

不管是允許或拒絕,都會回調(diào):

@Override
   public void onRequestPermissionsResult(int requestCode,
    @NonNull  String[] permissions,@NonNull  int[] grantResults) {
       if (requestCode == REQUEST_READ_CONTACTS) {
           if (grantResults.length == 1 &&
                   grantResults[0] == PackageManager.PERMISSION_GRANTED) {
               // 授權(quán)請求被通過,讀取通訊錄
               Log.i("wxl", "授權(quán)請求被通過,讀取通訊錄");
           } else {
               Log.i("wxl", "授權(quán)請求不被通過");
           }
       }
   }
多個(gè)權(quán)限
@TargetApi(Build.VERSION_CODES.M)
   private void checkPermissions() {
       List<String> permissionsNeeded = new ArrayList<>();
       final List<String> permissionsList = new ArrayList<>();
       if (deniedPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
           permissionsNeeded.add("GPS");
       if (deniedPermission(permissionsList, Manifest.permission.READ_CONTACTS))
           permissionsNeeded.add("Read Contacts");
       if (permissionsList.size() > 0) {
           if (permissionsNeeded.size() > 0) {
               // Need Rationale
               String message = "You need to grant access to " + permissionsNeeded.get(0);
               for (int i = 1; i < permissionsNeeded.size(); i++)
                   message = message + ", " + permissionsNeeded.get(i);
               requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), REQUEST_PERMISSIONS);
           }
       }
   }
   @TargetApi(Build.VERSION_CODES.M)
   private boolean deniedPermission(List<String> permissionsList, String permission) {
       if (checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED) {
           permissionsList.add(permission);
           // true,表示用戶拒絕過
           if (shouldShowRequestPermissionRationale(permission)) {
               return true;
           }
       }
       return false;
   }
   /**
    * Callback received when a permissions request has been completed.
    */
   @Override
   public void onRequestPermissionsResult(int requestCode,
                                          String[] permissions, int[] grantResults) {       
       if (requestCode == REQUEST_PERMISSIONS) {
           Map<String, Integer> perms = new HashMap<String, Integer>();
           // Initial
           perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
           perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
           // Fill with results
           for (int i = 0; i < permissions.length; i++)
               perms.put(permissions[i], grantResults[i]);
           // Check for ACCESS_FINE_LOCATION
           if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                   && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
               // All Permissions Granted
               Log.i("wxl", "授權(quán)請求被通過");
           } else {
               // Permission Denied
               Log.i("wxl", "授權(quán)請求不被通過");
           }
       }
   }

權(quán)限分組
權(quán)限那么多,如果一個(gè)個(gè)判斷,豈不是會瘋掉,如圖:

同一組的任何一個(gè)權(quán)限被授權(quán)了,其他權(quán)限也自動被授權(quán)。例如,一旦WRITE_CONTACTS被授權(quán)了,app也有READ_CONTACTS和GET_ACCOUNTS了。

附錄

Android M 新的運(yùn)行時(shí)權(quán)限開發(fā)者需要知道的一切
Android Runtime Permission測試

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容