Permission組件解析

Android 6.0之后,對于一些敏感的權限凫佛,需要我們手動請求讲坎,本文介紹一個權限組件Permisssion,主要是用于Android6.0以后(也就是API>23)的敏感權限請求御蒲,如果項目中的targetSdkVersion大于等于23衣赶,并且某個activity要需要一個或者多個危險權限的話可以用此組件進行判斷是否擁有權限以及請求權限。

組件的使用

1.在module的build.gradle 中增加: compile 'com.neteaseyx.permission:permission-lib:1.0.0'厚满,
2.創(chuàng)建PermissionManager對象府瞄,如果是在fragment中使用傳入參數是傳入 mFragment.getActivity()

 mPermissionManager = new PermissionManager(this);//創(chuàng)建PermissionManager對象

3.明確所需權限,可以是多個權限(哪些是危險權限都可以查得到)碘箍,這些權限都是用Manifest.permission.xxx聲明

 final String[] permissions = {
            Manifest.permission.CAMERA,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_FINE_LOCATION
    };

4.在需要請求權限的地方使用PermissionManager.requestPermissions 方法請求權限遵馆,第一個參數是請求碼,第二個參數是要請求的權限丰榴,第三個參數是請求結果的回調货邓,PermissionCallback里面有四個回調方法,onGranted_Third是回調所有允許的權限四濒,onExplanation是回調拒絕但是沒有勾選不再詢問的權限换况,onNormalDenied_Second是回調所有拒絕的權限,onNoMoreAskDenied_First是回調所有已經拒絕盗蟆,而且勾選了不再詢問的權限

mPermissionManager.requestPermissions(PERMISSION_REQ_CODE, permissions, new PermissionCallback() {

                @Override
                public void onGranted_Third(String... permissions) {    //回調所有允許的權限
                    for (String permission : permissions) {
                        addTextToResult(permission + "\n  -已批準\n", permission);
                    }
                }

                @Override
                public void onExplanation(String... permissions) {  //拒絕但沒有勾選不再詢問戈二,會通過這個方法回調
                    mPermissionManager.showRequestDialog(MainActivity.this, permissions, PERMISSION_REQ_CODE);
                }

                @Override
                public void onNormalDenied_Second(String... permissions) { //回調所有拒絕的權限
                    for (String permission : permissions) {
                        addTextToResult(permission + "\n  -已拒絕\n", permission);
                    }
                }

                @Override
                public void onNoMoreAskDenied_First(String... permissions) { //拒絕,而且勾選了不再詢問
                    for (String permission : permissions) {
                        addTextToResult(permission + "\n  -已永久拒絕\n", permission);
                    }
                }
            });

5.在 Activity 或者 Fragment 的 onRequestPermissionsResult 方法中調用 PermissionManager.onRequestPermissionResult, 否則不會有任何結果回調

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    mPermissionManager.onRequestPermissionResult(requestCode, permissions, grantResults);
}

組件內部實現

讓我們看看組件內部是怎么實現的喳资,首先是PermissionManager.requestPermissions 方法請求權限觉吭,它先判斷是否所有的請求都被批準了,如果都被批準了仆邓,直接回調onGranted_Third(permissions),回調所有允許的權限鲜滩,如果不是伴鳖,就遍歷權限集合,判斷是否要用戶選擇徙硅,將需要用戶選擇的權限添加到permissionsToExplainList集合里榜聂,并轉換成數組,如果數組不為空那么就彈出相應請求框

注意:這里callback.onExplanation(permissionsToExplain);一般情況是用戶上一次選擇了拒絕(沒有勾選不再詢問)嗓蘑,這次又重新請求峻汉,通常在此處還需要再次彈出請求對話框,而且這里不會自動出現權限請求彈窗, 需要在用戶處理完之前提到的 "解釋" 之后, 手動通過 PermissionManager.showRequestDialog 顯示彈窗

 /**
 * 請求權限
 *
 * @param requestCode 本次請求的唯一標識(不要過大脐往,最好小于999)
 * @param permissions 本次需要請求的權限,可以多個
 * @param callback    本次請求在用戶選擇完畢后的回調
 */
public void requestPermissions(int requestCode, String[] permissions, PermissionCallback callback) {
    mCallbackMap.put(requestCode, callback);
    if (!isPermissionsGranted(permissions)) {//是否所有的請求都被批準了扳埂,如果沒有被批準
        List<String> permissionsToExplainList = new ArrayList<>(3);
        for (String permission : permissions) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, permission)) {//判斷是否應該請求业簿,里面做了是否是危險權限的判斷
                permissionsToExplainList.add(permission);  //把應該請求的權限添加到permissionsToExplainList集合
            }
        }
        String[] permissionsToExplain = permissionsToExplainList.toArray(new String[permissionsToExplainList.size()]);//集合轉化為數組
        if (permissionsToExplain.length != 0) {
            callback.onExplanation(permissionsToExplain);
        } else {
            showRequestDialog(mActivity, permissions, requestCode);
        }
    } else {
        callback.onGranted_Third(permissions);//所有的請求都被批準
    }
}

在執(zhí)行完 PermissionManager.requestPermissions 后, 如果有權限請求需要用戶選擇, 系統會彈出相應請求框
如果沒有權限需要用戶選擇(所有權限或是已經允許, 或是已經拒絕, 或是永久拒絕), 直接回調相應結果
接下來我們來看看回調結果

* @param requestCode  請求的唯一標識
 * @param permissions  請求的權限
 * @param grantResults 請求的結果
 */
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
    PermissionCallback callback = mCallbackMap.get(requestCode);
    if (callback != null) {
        List<String> grantedList = new ArrayList<>(3);//用戶同意的權限
        List<String> normalDeniedList = new ArrayList<>(3);//用戶拒絕的權限,但是沒有勾選不再詢問
        List<String> noMoreAskDeniedList = new ArrayList<>(3);//用戶拒絕的權限阳懂,而且勾選了不再詢問
        for (int i = 0; i < permissions.length; i++) {
            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                grantedList.add(permissions[i]);
            } else {
                if (!ActivityCompat.shouldShowRequestPermissionRationale(mActivity, permissions[i])) {
                    noMoreAskDeniedList.add(permissions[i]);
                } else {
                    normalDeniedList.add(permissions[i]);
                }
            }
        }
        callback.onNoMoreAskDenied_First(noMoreAskDeniedList.toArray(new String[noMoreAskDeniedList.size()]));
        callback.onNormalDenied_Second(normalDeniedList.toArray(new String[normalDeniedList.size()]));
        callback.onGranted_Third(grantedList.toArray(new String[grantedList.size()]));
    }
}

首先定義了三個數組梅尤,以個是表示用戶同意的權限,一個是用戶拒絕的權限岩调,但是沒有勾選不再詢問巷燥,一個是用戶拒絕的權限而且勾選了不再詢問,然后開始遍歷權限數組号枕,將用戶選擇之后的權限分成三份缰揪,放在對應的結合里,然后調用回調葱淳,傳到相應的activity中钝腺,在activity中的callback里就可以知道哪些權限是用戶拒絕或者同意了的,還可以對相應的權限進行操作赞厕。

注意:PermissionCallback里的各種結果的回調有個先后順序:

  • onExplanation 如果有權限 "上一次選擇了拒絕, 但沒有勾選不再詢問", 最開始會通過此方法回調
  • onNoMoreAskDenied_First 然后回調所有 "不再詢問 且 勾選拒絕" 的權限
  • onNormalDenied_Second 然后回調所有 "拒絕" 的權限
  • onGranted_Third 最后回調所有 "允許" 的權限
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末艳狐,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子皿桑,更是在濱河造成了極大的恐慌毫目,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诲侮,死亡現場離奇詭異镀虐,居然都是意外死亡,警方通過查閱死者的電腦和手機浆西,發(fā)現死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門粉私,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人近零,你說我怎么就攤上這事诺核〕ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵窖杀,是天一觀的道長漓摩。 經常有香客問我,道長入客,這世上最難降的妖魔是什么管毙? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮桌硫,結果婚禮上夭咬,老公的妹妹穿的比我還像新娘。我一直安慰自己铆隘,他們只是感情好卓舵,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膀钠,像睡著了一般掏湾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肿嘲,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天融击,我揣著相機與錄音,去河邊找鬼雳窟。 笑死尊浪,一個胖子當著我的面吹牛,可吹牛的內容都是我干的封救。 我是一名探鬼主播际长,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼兴泥!你這毒婦竟也來了工育?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤搓彻,失蹤者是張志新(化名)和其女友劉穎如绸,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體旭贬,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡怔接,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了稀轨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扼脐。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出瓦侮,到底是詐尸還是另有隱情艰赞,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布肚吏,位于F島的核電站方妖,受9級特大地震影響,放射性物質發(fā)生泄漏罚攀。R本人自食惡果不足惜党觅,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斋泄。 院中可真熱鬧杯瞻,春花似錦、人聲如沸炫掐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卒废。三九已至,卻和暖如春宙地,著一層夾襖步出監(jiān)牢的瞬間摔认,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工宅粥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留参袱,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓秽梅,卻偏偏與公主長得像抹蚀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子企垦,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容