1. 程式人生 > >關於android6.0動態許可權造成的app crash問題

關於android6.0動態許可權造成的app crash問題

今天我們為公司內部員工開發的app出現了一個bug,因為我們的app要繫結imei所以我就讀取imei並且有個許可權READ_PHONE_STATE就是這個許可權出現了問題,我就納悶了怎麼會有問題呢,我已經在manifest上聲明瞭,然後我就看一下他的android版本6.0(什麼時候國產手機系統跟進竟然這麼快了!),我就去搜了一些相關資料才發現是android6.0涉及到隱私的許可權是動態的,也就是說你每次呼叫的方法如果涉及到隱私都需要檢查一下該許可權,因為使用者可以隨時取消你得相關授權。

許可權檢查

你可以通過ContextCompat.checkSelfPermission()方法來驗證你的應用是否擁有某個許可權。比如,下面的程式碼段是檢查是否有擁有寫日曆許可權:

// 假設 thisActivity 是當前的 Activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
  如果該應用已經獲取到該許可權,該方法返回PackageManager.PERMISSION_GRANTED並且程式可以繼續執行。如果該應用未被授予該許可權,這個方法會返回PERMISSION_DENIED,同時應用需要明確提示使用者該應用所需要的許可權。

請求許可權

如果你的應用需要敏感許可權並且這些敏感許可權已經在 manifest 檔案中宣告,一定要詢問使用者獲取許可權。Android 系統提供了幾種請求許可權的方法。呼叫這些方法後,系統會彈出一些 Dialog(無需使用者自定義)。


解釋需要許可權的原因

在某些情況下,你可能會想要向用戶解釋需要許可權的原因,比如我要打電話,但是你首先得讓我獲得你係統的聯絡人。

Android 系統提供了shouldShowRequestPermissionRationale()方法來幫助開發者判斷是否需要向用戶解釋需要許可權的原因。當某條許可權之前已經請求過,並且使用者已經拒絕了該許可權時,shouldShowRequestPermissionRationale ()方法返回的是 true

注意:如果使用者拒絕某條許可權,並且在提示授權的視窗中勾選了不再提示選項時,shouldShowRequestPermissionRationale ()的返回值為false.當某些裝置禁止應用程式獲取某些許可權時,shouldShowRequestPermissionRationale ()也會返回false

向用戶請求獲取應用程式需要的許可權

  如果你的應用程式沒有獲取到它需要的許可權,那麼應用程式需要呼叫該許可權對應的requestPermissions()方法,呼叫requestPermissions()方法時需要傳入一個請求碼(requestCode),這時系統會彈出一個對話方塊讓使用者選擇是否授權,使用者選擇後,在回撥方法onRequestPermissionsResult()中返回對應的請求碼(requestCode)和授權結果。

  下面這段程式碼 檢查應用程式是否有讀聯絡人許可權,在未獲取讀聯絡人授權時請求獲取該許可權(完整示例見Android_M_Permission):

// thisActivity 為當前 Activity
// 檢查是否已經授權該許可權
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // 判斷是否需要解釋獲取許可權原因
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {
        // 需要向用戶解釋
        // 此處可以彈窗或用其他方式向用戶解釋需要該許可權的原因
    } else {
        // 無需解釋,直接請求許可權
        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
        // MY_PERMISSIONS_REQUEST_READ_CONTACTS 是自定義的常量,在回撥方法中可以獲取到
    }
}
注意:當應用程式呼叫requestPermissions()方法時,系統會彈出一個對話方塊給使用者。應用程式不能設定或更改該對話方塊,如果應用程式需要提供一些資訊或者向用戶解釋,需要在呼叫requestPermissions()方法之前,如Explain why the app needs permissions所述。

處理請求許可權的結果

當應用程式請求獲取許可權時,系統會彈出一個對話方塊給使用者。當用戶點選某個選項時,系統會呼叫onRequestPermissionsResult()方法來傳遞使用者的選擇結果。應用程式需要重寫onRequestPermissionsResult()方法來判斷使用者是否對相應許可權授權。。這個回撥方法會傳遞一個與requestPermission()方法相同的requestCode.例如,應用程式請求READ_CONTACTS方法,它將會有如下的回撥方法:

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            //如果請求被取消,那麼 result 陣列將為空
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 已經獲取對應許可權
                // TODO 執行相應的操作聯絡人的方法
            } else {
                // 未獲取到授權,取消需要該許可權的方法
            }
            return;
        }
        // 檢查其他許可權......
    }
}  
授權的對話方塊顯示的是系統描述的許可權組(permission group),它沒有顯示列出詳細的許可權列表。比如,如果你請求READ_CONTACTS許可權,系統對話方塊只會提示使用者應用程式需要獲取聯絡人許可權,使用者只需要給每個許可權組授權一次。如果應用程式請求獲取一個許可權組的其他許可權(在 manifest 檔案中宣告的許可權),系統會自動授予該許可權。當你請求這個許可權時,系統會呼叫onRequestPermissionsResult()回撥方法並且傳遞PERMISSION_GRANTED,這跟使用者在彈窗中點選授予許可權的按鈕的流程是相同的。

注意:應用程式還是需要明確的請求它所需要的每個許可權,即使使用者已經授予了跟這個許可權在同一個permission group的其他許可權。除此之外,對某個許可權組的授權可能會改變。程式的程式碼不能依賴於使用者已經對某個許可權組授權的假設。

  例如,應用程式在 manifest 檔案用聲明瞭READ_CONTACTS和WRITE_CONTACTS許可權,如果應用程式請求了READ_CONTACTS許可權並且使用者授予了該許可權,那麼當應用程式請求WRITE_CONTACTS許可權時,系統會自動授予應用程式該許可權。

譯者注:READ_CONTACTS和WRITE_CONTACTS都屬於CONTACTS許可權組。更多關於許可權組資訊可以訪問permission group或直接看我的截圖:許可權和許可權組

  如果使用者拒絕了一個應用許可權請求,那麼應用程式應該進行適當的操作。例如:應用程式可以彈出一個對話方塊來解釋為什麼使用者不能執行需要該許可權的操作。

  當系統提示使用者給應用程式授權許可權時,會給使用者提供一個不再提示的選項來通知系統不再針對該許可權進行詢問。使用者勾選該選項後,當應用程式請求獲取對應許可權時,系統會立即拒絕授權。系統會呼叫onRequestPermissionResult()回撥方法並且傳遞PERMISSION_DENIED引數,就像使用者拒絕授權一樣。這意味著,當你呼叫requestPermissions()方法時,你不能假定應用程式會跟使用者直接互動。

相關參考:

http://kingideayou.github.io/2015/11/09/Android_M_permissions/