6.0權限申請巧遇問題

小序

原本以爲這次項目完成得不錯,結果測試妹子在禪道上又提了些BUG,大多涉及到6.0權限的問題。這就比較尷尬了,畢竟是一開始並沒有顧慮的。而關於權限申請,其實際上已經有很多前輩提供過相應的解決辦法,在此謝過。

正文

1. 需動態申請的權限

權限的申請依據谷歌的分類來講,一類屬於普通的權限申請,與往常一樣可直接在 AndroidManifest.xml 註冊就可以了;另一類則需要在應用程序使用的地方執行動態申請,該類權限屬危險權限(組),當然前提也得先在 AndroidManifest.xml 下注冊聲明。這裏僅羅列需要動態申請的權限內容(摘自這裏)。

權限組 權限
CALENDAR 日曆 android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
CAMERA 相機 android.permission.CAMERA
CONTACTS 聯繫人 android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS
LOCATION 位置 android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
MICROPHONE 麥克風 android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS
PHONE 電話 android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS
SENSORS 傳感器 android.permission.BODY_SENSORS
SMS 短信 android.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.READ_CELL_BROADCASTS
STORAGE 存儲 android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE

2. 具體實現

瞭解完需要申請的權限之後,需要根據實際項目當中需要用到的相關權限,在相應的位置開始我們的權限申請。申請過程主要包括以下兩個操作,另外也有人封裝了些簡單易用的依賴庫,有興趣的親也可瞭解下。

/**
 * 以定動態申請位權限爲例
 */
public void handPermission() {
    // 定位權限組
    String[] mPermissionGroup = new String[]{
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION};

    // 過濾已持有的權限
    List<String> mRequestList = new ArrayList<>();
    for (String permission : mPermissionGroup) {
        if ((ContextCompat.checkSelfPermission(getActivity(), permission)
                != PackageManager.PERMISSION_GRANTED)) {
            mRequestList.add(permission);
        }
    }

    // 申請未持有的權限
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !mRequestList.isEmpty()) {
        ActivityCompat.requestPermissions(mActivity, mRequestList.toArray(
                new String[mRequestList.size()]), 100);
    } else {
        // 權限都有了,就可以繼續後面的操作
    }
}
/**
 * 回調權限申請結果
 *
 * @param requestCode
 * @param permissions
 * @param grantResults
 */
@Override
public void onRequestPermissionsResult(
        int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 100: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 同意權限申請,就可以繼續後面的操作
            } else {
                // 拒絕權限申請,提示申請權限的重要性
            }
        }
        break;
    }
}

3. 巧遇問題

a. 反覆申請

“重複申請”是不合理的,這樣會嚴重影響到用戶的體驗。最好是在用戶拒絕權限的申請用給予用戶用好提示,或本次應用開啓權限僅申請一次,不通過提示爲授權之類的。

部分機子系統需要特別注意,因爲它們整個應用的申請僅提示一次,如最爲熟悉的小米/紅米。無論之後再怎麼requestPermissions也無濟於事,到頭來還得提示用戶到應用設置手動啓動權限。這算是比較噁心的一個事情,且其他機子上如果用戶勾選了不再提示也是一樣的。

建議權限申請不要再onResume()的生命週期中執行,因爲權限申請操作後會再次調用onResume(),個人在小米/紅米機子上測試出現過該問題。

b. 多權限申請帶來的問題

String[] mPermissionGroup = new String[]{
            Manifest.permission.CAMERA
            Manifest.permission.ACCESS_COARSE_LOCATION};

// 注意:這樣的多權限申請是存在問題的
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        ActivityCompat.requestPermissions(mActivity, mPermissionGroup, 100);
    }

如上面所見,我定義了一個需要權限請求的數組。裏面包括了兩個權限組,一個是照相機的權限,另一個則是定位的權限(權限組當中的任意成員被授予權限,相當於權限組內的各個權限都將被授予權限)。那麼在實際執行當中會是什麼效果呢?

多權限申請效果1

經上面圖示效果可以看到,多權限申請的時候每一個權限組的申請都被單獨開來了。那麼問題來了,因爲權限的申請是我們主動發出的,並且一個應用當中往往不止一個地方需要權限申請。簡單的說如果你已經執行百度定位授予了定位權限了。那麼你下次就應該先判斷定位權限是否已被授權再加入到多權限申請單中。

那麼有人就要問了,即使一開始不判斷是否授權。在申請授權的回調過程中不也能自己判斷麼?嗯,確實是這樣沒錯。但那只是針對mPermissionGroup這個整體,即如果當中有部分權限已經被授予,而剩下的未授予,將全部被重新申請

E/SQLiteDatabase: Failed to open database ‘/storage/emulated/0/emlibs/libs/monitor.db’
E/SQLiteDatabase: Failed to open database ‘/storage/emulated/0/baidu/tempdata/ls.db’

以上列舉兩種異常,主要在小米/紅米機子上測試出現,其他機子未測試確認。出現該問題的罪魁禍首就是,在多權限申請當中將原已授權的權限拒絕了,且該權限剛好正被使用。解決以上原因只需要一步“過濾”,遍歷mPermissionGroup集合當中每個成員的授權狀態再執行多權限申請(如第2點當中寫到的)

發佈了50 篇原創文章 · 獲贊 4 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章