Android6.0運行時權(quán)限申請

1.簡介

在Android6.0之前版本看疙,權(quán)限請求較為簡單豆拨,僅在用戶安裝app時將自己需要使用的所有權(quán)限列出來告知用戶直奋,若用戶授權(quán),則app安裝后可隨時使用該權(quán)限施禾。自6.0開始脚线,一些涉及用戶隱私的敏感權(quán)限需在使用時動態(tài)申請,且用戶可選擇授權(quán)或拒絕弥搞。當然邮绿,權(quán)限的改進對用戶而言是好事,畢竟更能保護用戶隱私拓巧。但對于開發(fā)者而言斯碌,也多了一項動態(tài)權(quán)限申請的工作

2.權(quán)限分類

對開發(fā)者而言,權(quán)限則主要分為以下兩類:
1)普通權(quán)限(normal permissions): 只需在manifest中注冊
2)危險權(quán)限(dangerous permissions):仍需在manifest中注冊肛度,但具體授權(quán)分以下幾種情況

targetSdk<23 targetSdk>=23
手機系統(tǒng)<23 安裝時默認獲得權(quán)限且用戶無法在安裝后取消權(quán)限 安裝時默認獲得權(quán)限且用戶無法在安裝后取消權(quán)限
手機系統(tǒng)>=23 安裝時默認獲得權(quán)限,但用戶可在安裝后取消授權(quán)( 取消時手機會提示用戶該APP是為舊版手機打造投慈,讓用戶謹慎操作 ) 安裝時不會獲得權(quán)限而需在運行時向用戶動態(tài)申請承耿。用戶授權(quán)后仍可在設置界面中取消,取消授權(quán)后在app運行過程中可能會出現(xiàn)crash

由上表可知當APP的targetSdk>=23且運行在Android>=6.0(API23)的手機上時必須使用動態(tài)申請權(quán)限


具體危險權(quán)限如下:

危險權(quán)限.png

3.運行時權(quán)限申請(使用系統(tǒng)提供的API)

1)權(quán)限檢查

對于權(quán)限檢查伪煤,Android提供了以下3種方式
1.ContextCompat#checkSelfPermission
2.Context#checkSelfPermission
3.PermissionChecker#checkSelfPermission

需注意的是若應用targetSdk<23加袋,則第1、2種方式返回的永遠是PERMISSION_GRANTED抱既,即永遠返回已授權(quán)职烧。根據(jù)本文上面內(nèi)容知當targetSdk<23時,應用雖在安裝時就獲得授權(quán)防泵,但若運行在>=Android6.0的手機上時蚀之,用戶可在安裝后取消授權(quán),此時就不能使用第1捷泞、2種方式來檢查權(quán)限足删,而需使用第3種

public static boolean checkSelfPermission(String permission, Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        //getTargetVersion是判斷app的targetSdk的方法
        if (getTargetVersion(context) >= Build.VERSION_CODES.M) { 
            //應用的targetSdk>=23則使用Context#checkSelfPermission(permission)        
            return context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
        } else {
            //若targetSdk<23則使用PermissionChecker#checkSelfPermission
            return PermissionChecker.checkSelfPermission(context, permission) == PermissionChecker.PERMISSION_GRANTED;
        }
    } else {//手機版本低于6.0的,安裝后即授權(quán)且用戶無法取消
        return true;
    }
}

2)請求權(quán)限

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 
requestCode);

注意:1.Fragment中請求需使用自己的requestPermissions方法

3)處理請求結(jié)果

請求權(quán)限后系統(tǒng)會回調(diào)申請權(quán)限的Activity的onRequestPermissionsResult()锁右,若使用的是Fragment的requestPermissions方法失受,則回調(diào)對應Fragment的onRequestPermissionsResult()

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode != this.requestCode || grantResults.length = 0) {
            return;
        }
        for (int i = 0; i < grantResults.length; i++) {
            String permission = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, permission + "已被授權(quán)", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, permission + "已被拒絕", Toast.LENGTH_SHORT).show();
                if (shouldShowRequestPermissionRationale(permission)) {
                    //請求被用戶拒絕但用戶未勾選不再詢問框,可繼續(xù)請求權(quán)限
                } else {
                    //請求被用戶拒絕且用戶勾選了不再詢問框咏瑟,需要用戶前往設置中授權(quán)
                }
            }
        }
    }

4)總結(jié)

用系統(tǒng)提供的api進行申請步驟較為繁瑣拂到,且請求和處理代碼不在相同位置,代碼量多了的話可讀性變差码泞。那有沒有什么好的方法既能簡化流程提高可讀性又能避免以上第二種情況呢兄旬?答案是肯定的,著名基佬交流網(wǎng)站github上就有豐富的權(quán)限請求庫供各位客官享用浦夷!

4.使用EasyPermissions進行權(quán)限申請

1)特點

  • 鏈式操作
  • 請求前會自動檢查是否已被授予 (這樣在請求前就不必再進行權(quán)限檢查了)
  • 若請求的權(quán)限未在manifest中注冊辖试,將拋出明確的異常 (請求未在manifest注冊的權(quán)限將導致不彈出dialog而直接返回false辜王,有時我們可能對此十分懵逼,因為這既不報錯也不彈出dialog代碼也OK就是請求失敗罐孝,可能要很久才反應過來忘了在manifest中注冊)
  • 自動重試(可配置項)呐馆,配置該選項后若請求被拒但用戶未勾選不再提示框時會自動重試直到用戶授權(quán)或勾選不再提示框

2)依賴

A.在項目根build.gradle中

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

B.添加依賴

dependencies {
    implementation 'com.github.Ficat:EasyPermissions:v2.1.0'
}

3)使用

//requestEach方式
EasyPermissions
   .with(activity)
   .requestEach(Manifest.permission.CAMERA)
   .result(new RequestEachExecutor.ResultReceiver() {
       @Override
       public void onPermissionsRequestResult(Permission permission) {
           String name = permission.name;
           if (permission.granted) {
               //name權(quán)限被授予
           } else {
               if (permission.shouldShowRequestPermissionRationale) {
                   //name權(quán)限被拒絕但用戶未勾選不再提示框,可繼續(xù)請求
               } else {
                   //name權(quán)限被拒絕且用戶勾選了不再提示框
                   //此時不能再次請求了莲兢,而需要user前往設置界面手動授權(quán)
                   EasyPermissions.goToSettingsActivity(activity);
               }
           }
       }
   });


//request方式汹来,請求的所有權(quán)限被用戶授權(quán)后返回true,否則返回false  
EasyPermissions
    .with(activity)
    .request(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    .autoRetryWhenUserRefuse(true, new BaseRequestExecutor.RequestAgainListener() {//是否自動重試
        @Override
        public void requestAgain(String[] needAndCanRequestAgainPermissions) {
            //該監(jiān)聽回調(diào)中傳入的是再次請求的權(quán)限改艇,用以在重新請求時彈出說明框等信息(如
            //向用戶說明為何要使用該權(quán)限)
            for (String s : needAndCanRequestAgainPermissions) {
                Log.e("TAG", "request again permission = "+s);
            }
        }
    })
    .result(new RequestExecutor.ResultReceiver() {
        @Override
        public void onPermissionsRequestResult(boolean grantAll, List<Permission> results) {
            if (grantAll) {
                Toast.makeText(MainActivity.this, "request permissions success!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "request permissions fail!", Toast.LENGTH_SHORT).show();
            }
        }
    });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末收班,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子谒兄,更是在濱河造成了極大的恐慌摔桦,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件承疲,死亡現(xiàn)場離奇詭異邻耕,居然都是意外死亡,警方通過查閱死者的電腦和手機燕鸽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門兄世,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啊研,你說我怎么就攤上這事御滩。” “怎么了党远?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵削解,是天一觀的道長。 經(jīng)常有香客問我麸锉,道長钠绍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任花沉,我火速辦了婚禮柳爽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碱屁。我一直安慰自己磷脯,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布娩脾。 她就那樣靜靜地躺著赵誓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俩功,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天幻枉,我揣著相機與錄音,去河邊找鬼诡蜓。 笑死熬甫,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蔓罚。 我是一名探鬼主播椿肩,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼豺谈!你這毒婦竟也來了郑象?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤茬末,失蹤者是張志新(化名)和其女友劉穎厂榛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丽惭,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡噪沙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吐根。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡辐马,死狀恐怖拷橘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喜爷,我是刑警寧澤冗疮,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站檩帐,受9級特大地震影響术幔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜湃密,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一诅挑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泛源,春花似錦拔妥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春硬纤,著一層夾襖步出監(jiān)牢的瞬間解滓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工筝家, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洼裤,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓肛鹏,卻偏偏與公主長得像逸邦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子在扰,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容