談談Android 6.0運行時權限理解[轉]

談談Android 6.0運行時權限理解

前言

 谷歌在2015年8月份時候,發佈了Android 6.0版本,代號叫作「棉花糖」(Marshmallow ),其中的很大的一部分變化,是在用戶權限受權上,或許是感受以前默認受權的不合理,如今6.0出來,使得用戶權限受權變得合理。這可能也是參考IOS系統的,只有在用戶須要使用權限的時候,纔去受權請求,這樣作的目的是提升用戶體驗,固然,用戶感受好了,受苦的是咱們開發人員,原來的規則不適用了,如今咱們去適應新的規則,畢竟是靠谷歌這顆大樹吃飯的嘛。html

原來權限模型

 在Android 6.0版本以前,權限都是一條龍服務的,只要用戶安裝完AndroidManifest清單上申請的權限都會被系統默認受權,而且受權後也撤銷不了。這樣的弊端在哪裏呢?有些權限可能用戶以爲不須要,好比他不想有通知的權限,不想受到通知的干擾,那麼他就不能屏蔽通知,就是不須要的權限,他去不掉,自主權不在他那邊。還有一些狀況是,一些惡意程序,會利用這個權限默認受權,進行惡意獲取用戶數據和攻擊。因此Android 6.0版本,一方面讓用戶更加容易的控制本身的隱私,一方面須要從新適配應用權限。android

Android 6.0權限模型

  採用新的權限模型,只有在須要權限的時候,才告知用戶是否受權,是在runtime時候受權,而不是在原來安裝的時候 ,同時默認狀況下每次在運行時打開頁面時候,須要先檢查是否有所須要的權限申請。這樣的用戶的自主性提升不少,好比用戶能夠給APP賦予攝像的權限,可是能夠拒絕記錄設備位置的權限,就是怕位置信息上傳等等。git

權限流程

  在API 23中,權限知足的標準流程:github

但這裏有個問題,那就是在系統受權彈窗環節,提醒框會有個再也不提示的複選框,若是用戶點擊不太提示,並拒絕受權,那麼再下次受權的時候,系統受權彈窗的提示框就不會在提示,因此咱們頗有必要須要自定義權限彈窗提示框,那麼流程圖就變成以下了。app

 

權限類型

 在圖中,咱們能夠看到整個權限裏,能夠分爲系統權限和特殊權限受權。系統權限中,又分爲normal和dangerous類型。async

 normal:這個權限類型並不直接威脅到用戶的隱私,能夠直接在manifest清單裏註冊,系統會幫咱們默認受權的。ide

 dangerous:這個能夠直接給app訪問用戶一些敏感的數據,不只須要在manifest清單裏註冊,同時在使用的時候,須要向系統請求受權。ui

 值得注意一點,這裏有特殊權限受權的區別,分別是SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,雖然這兩個權限也是屬於dangerous權限類型,可是這兩個受權請求方式和其餘dangerous權限是不同的,須要特殊處理 。this

   normal列表:spa

 

dangerous列表:

 

Permission Group Permissions
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

 

版本兼容

 固然,谷歌也是考慮到若是是以API 23以前的版本編譯的APP,在6.0的系統上運行,仍是能兼容的。若是是23以前的版本編譯的APP,則權限模型走的是老的模式,也就是在一條龍的模式,在manifest清單註冊,系統會幫咱們默認受權,而且也能運行。

   但若是是以API 23的版本編譯的APP,那走的的必須是新的權限模型,在遇到dangerous權限的時候,必須進行受權的,若是沒有進行受權話,系統則會提示崩潰信息。因此,基於6.0系統的開發的程序, 在打開頁面的時候,必需要考慮這個頁面是否用到須要受權的權限,頁面檢測是否已經受權過了沒。

 

實現方式

   第一步:檢測權限

// Assume thisActivity is the current activityint permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

    第二步:請求權限

複製代碼

// Here, thisActivity is the current activityif (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)        != PackageManager.PERMISSION_GRANTED) {    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {        // Show an expanation to the user *asynchronously* -- don't block        // this thread waiting for the user's response! After the user        // sees the explanation, try again to request the permission.
    } else {        // No explanation needed, we can request the permission.
        ActivityCompat.requestPermissions(thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an        // app-defined int constant. The callback method gets the        // result of the request.    }
}

複製代碼

 第三步:處理權限請求結果

複製代碼

@Overridepublic void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {    switch (requestCode) {        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // permission was granted, yay! Do the                // contacts-related task you need to do.
            } else {                // permission denied, boo! Disable the                // functionality that depends on this permission.            }            return;
        }        // other 'case' lines to check for other        // permissions this app might request    }
}

複製代碼

 

其中要特別注意的是,若是是針對

「android.permission.SYSTEM_ALERT_WINDOW」
「android.permission.WRITE_SETTINGS」

這兩個權限,實現方式跟上以前在工做中,碰到一種狀況,若是是運行在6.0的版本上是須要走新的權限模型,若是是運行在老的版本上,則須要進行一個判斷,此時碰到一個問題是,在谷歌官方推薦中,在判斷app運行的系統是否在Android M上時,它的判斷是以下:  Build.VERSION.CODENAME.equals("MNC"); 但是在我實際適配中,發現這句卻無效的,就改用Build.VERSION.SDK_INT >= 23。的,須要另外特殊處理。

針對SYSTEM_ALERT_WINDOW權限,須要向系統發送一個ACTION_MANAGE_OVERLAY_PERMISSION.這樣一個動做,同時能夠用Settings.canDrawOverlays() 方法進行判斷以前是否已經受權過了。

針對WRITE_SETTINGS權限,須要向系統發送一個ACTION_MANAGE_WRITE_SETTINGS 這樣一個動做,同時能夠用Settings.System.canWrite().方法進行判斷以前是否已經受權過了。

具體代碼:

Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

注意點

 以前在工做中,碰到一種狀況,若是是運行在6.0的版本上是須要走新的權限模型,若是是運行在老的版本上,則須要進行一個判斷,此時碰到一個問題是,在谷歌官方推薦中,在判斷app運行的系統是否在Android M上時,它的判斷是以下:  Build.VERSION.CODENAME.equals("MNC"); 但是在我實際適配中,發現這句卻無效的,就改用Build.VERSION.SDK_INT >= 23。

 

 

 總結

  1. 首先要知道6.0版本權限模型跟原來版本是不一樣的,再也不是統一在manifest中默認系統受權,而是有須要的時候,向系統請求受權,提升用戶體驗。

  2. 瞭解權限檢測流程,一點注意點是若是系統權限彈窗提示框被再也不提醒了,須要咱們自定義提示彈窗,引導用戶去受權。

  3. 明白權限類型,分爲normal和dangerous類型,同時,在dangerous中還須要注意一點,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS這兩個特殊受權請求方式,跟通常受權請求方式不一樣。

  4. 在判斷APP是否運行在Android M上,能夠用版本號來判斷,能夠準確點。

 參考

    有個具體demo:https://github.com/SpikeKing/wcl-permission-demo

    流程圖:http://blog.csdn.net/caroline_wendy/article/details/50587230

相關文章
相關標籤/搜索