Android動(dòng)態(tài)權(quán)限申請(qǐng)簡(jiǎn)易且全面的講解及代碼

項(xiàng)目地址

github:PermissionsDemo

相關(guān)系統(tǒng)方法說(shuō)明

ActivityCompat.checkSelfPermission() :檢查用戶是否已經(jīng)授權(quán); ActivityCompat.requestPermissions() :申請(qǐng)權(quán)限; onRequestPermissionsResult():Activity/Fragment中的回調(diào),用于判斷申請(qǐng)結(jié)果; shouldShowRequestPermissionRationale() :判斷是否能彈出“允許、禁止且不再詢問(wèn)”提示框。

首先需要了解動(dòng)態(tài)權(quán)限申請(qǐng)總共有哪些現(xiàn)象

vivo IQOO3 請(qǐng)求權(quán)限為例

調(diào)用申請(qǐng)權(quán)限方法:ActivityCompat.requestPermissions()

第一次申請(qǐng)彈出:“允許、禁止”,點(diǎn)擊“禁止”;
14775500-efe86fa0723a174e.jpg

再次申請(qǐng)彈出:“允許、禁止且不再詢問(wèn)”;
14775500-48176b675ee84747.jpg

點(diǎn)擊“禁止且不再詢問(wèn)”,調(diào)用方法則不再?gòu)棿埃?/p>

再次調(diào)用申請(qǐng)方法,不再?gòu)棿?。Activity/Fragment的onRequestPermissionsResult方法中回調(diào):grantResults[i] == PackageManager.PERMISSION_DENIED

我們需要判斷以上三種場(chǎng)景狀態(tài)

相關(guān)方法:ActivityCompat.shouldShowRequestPermissionRationale

此方法僅能在申請(qǐng)權(quán)限,用戶選擇“禁止”之后,判斷是否能彈出“允許、禁止且不再詢問(wèn)”提示框; 在1、第一次申請(qǐng)權(quán)限;2、點(diǎn)擊“禁止且不再詢問(wèn)”。這兩種情形都是返回false。 此方法唯一作用是,判斷返回true時(shí),是可以彈出“允許、禁止且不再詢問(wèn)”提示框。返回false則多種情形都會(huì)出現(xiàn),無(wú)區(qū)別判斷意義。

其他方法

AppOpsManager相關(guān)權(quán)限API只能判斷是否有權(quán)限 MODE無(wú)效 反射也是返回值只有0、1,因此此API在此處無(wú)意義;

總結(jié)

并無(wú)完美方法判斷三種權(quán)限申請(qǐng)場(chǎng)景。

根據(jù)能判斷的情況分為3種場(chǎng)景類(lèi)型:

1、允許權(quán)限 2、禁止 禁止,但沒(méi)有選擇“以后不再詢問(wèn)”,以后申請(qǐng)權(quán)限,會(huì)繼續(xù)彈出提示 3、其他 場(chǎng)景一:選擇“禁止并不再詢問(wèn)”; 場(chǎng)景二:用戶點(diǎn)擊系統(tǒng)申請(qǐng)權(quán)限彈出框外部,使對(duì)話框消失; 場(chǎng)景三:再此之前已經(jīng)點(diǎn)擊過(guò)"禁止并不再詢問(wèn)",調(diào)用申請(qǐng)權(quán)限則直接回調(diào)到此處。

我們來(lái)看看處理方案

既無(wú)完美,始終要有方案處理。

1、網(wǎng)上常用方案

申請(qǐng)權(quán)限,在Activity/Fragment的onRequestPermissionsResult方法中回調(diào),判斷grantResults[i] == PackageManager.PERMISSION_GRANTED,則彈出跳往設(shè)置的提示框

在此會(huì)有兩種情形: 1、申請(qǐng)權(quán)限對(duì)話框彈出時(shí),用戶點(diǎn)擊“禁止”,彈出跳往設(shè)置提示框; 2、用戶已經(jīng)禁止詢問(wèn)時(shí),調(diào)用系統(tǒng)申請(qǐng)權(quán)限方法,直接彈出跳往設(shè)置提示框;

2、簡(jiǎn)易方案

相關(guān)工具方法,Demo示例,github:PermissionsDemo

申請(qǐng)權(quán)限,在Activity/Fragment的onRequestPermissionsResult方法中回調(diào),通過(guò)定義requestCode來(lái)判斷哪次申請(qǐng),再判斷。

可以自行根據(jù)細(xì)分場(chǎng)景處理。

if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
    //處理允許權(quán)限后的操作
    retrun;
}
String permission = permissions[i];
boolean shouldShow = ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
if (shouldShow) {
    //禁止,但沒(méi)有選擇“以后不再詢問(wèn)”,以后申請(qǐng)權(quán)限,會(huì)繼續(xù)彈出提示
    //處理用戶點(diǎn)擊禁止后的操作
} else {
    //場(chǎng)景一:選擇“禁止并不再詢問(wèn)”;場(chǎng)景二:用戶點(diǎn)擊系統(tǒng)申請(qǐng)權(quán)限彈出框外部,使對(duì)話框消失;場(chǎng)景三:再此之前已經(jīng)點(diǎn)擊過(guò)"禁止并不再詢問(wèn)",調(diào)用申請(qǐng)權(quán)限則直接回調(diào)到此處。
   //Toast提示用戶前往設(shè)置允許權(quán)限
}

3、使用比較流行的框架 RxPermission

優(yōu)點(diǎn):可以直接拿到回調(diào) 缺點(diǎn):需要在FragmentActivity 、Fragment中使用 注意:使用時(shí)傳入的FragmentActivity 或Fragment中,onRequestPermissionsResult方法的父類(lèi)方法不能刪除,否則影響rxPermission的回調(diào)

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        //父類(lèi)方法不能刪除,否則影響rxPermission的回調(diào)
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
使用步驟:
1)引用依賴

project中g(shù)radle添加

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

app中g(shù)radle添加

dependencies {
    /*  需要多加對(duì)應(yīng)版本的rxjava,0.12對(duì)應(yīng)rxjava3   */
    // RxJava
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
    //rxpermissions
    implementation 'com.github.tbruyelle:rxpermissions:0.12'
    //如果想要嘗試使用 RxView 時(shí)
    implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
}

如果項(xiàng)目中使用的是rxjava2,則使用

 // RxJava
    implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    //如果想要嘗試使用 RxView 時(shí)
    implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
    //rxpermissions
    implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
2)gradle報(bào)錯(cuò)處理

Android Studio錯(cuò)誤提示Duplicate class android.support.v4.app.INotificationSideChannel found

需要在gradle.properties中添加下面兩行代碼 這是因?yàn)榛旌现С謳?kù)。通過(guò)添加這些行選擇androidX作為支持庫(kù)

android.useAndroidX=true
android.enableJetifier=true
3)以下我們梳理下使用的場(chǎng)景,完整封裝請(qǐng)?jiān)赿emo(PermissionsDemo)中查看:
A、簡(jiǎn)單回調(diào)處理,只回調(diào)允許或者拒絕

permissions.request(permissionstr)方法參數(shù)為可變參數(shù),如果是多個(gè)權(quán)限,則是所有權(quán)限都通過(guò)才回調(diào)true

        String[] permissionstr = {
                        Manifest.permission.RECORD_AUDIO};

        RxPermissions permissions = new RxPermissions(activity);
        permissions.setLogging(true);
        permissions.request(permissionstr).subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) {
            
            }
        });
B、區(qū)分三種場(chǎng)景回調(diào)處理

RxPermissions.requestEach 方法參數(shù)為可變參數(shù),可傳單個(gè)或者多個(gè)String,或者String[]。 多個(gè)權(quán)限則通過(guò)方法 permission.name.equalsIgnoreCase() 來(lái)區(qū)分

        String[] permissionstr = {
                Manifest.permission.RECORD_AUDIO}
        RxPermissions permissions = new RxPermissions(activity);
        permissions.setLogging(true);
        permissions.requestEach(permissionStr)
                .subscribe(new Consumer<Permission>() {
                    @Override
                    public void accept(Permission permission) throws Exception {
                        if (permission.name.equalsIgnoreCase(Manifest.permission.RECORD_AUDIO)) {
                            if (permission.granted) {
                                //處理允許權(quán)限后的操作
                                return;
                            }
                            if (permission.shouldShowRequestPermissionRationale) {
                                //禁止,但沒(méi)有選擇“以后不再詢問(wèn)”,以后申請(qǐng)權(quán)限,會(huì)繼續(xù)彈出提示
                                //處理用戶點(diǎn)擊禁止后的操作
                                return;
                            }

                            //場(chǎng)景一:選擇“禁止并不再詢問(wèn)”;
                            //場(chǎng)景二:用戶點(diǎn)擊系統(tǒng)申請(qǐng)權(quán)限彈出框外部,使對(duì)話框消失;
                            //場(chǎng)景三:再此之前已經(jīng)點(diǎn)擊過(guò)"禁止并不再詢問(wèn)",調(diào)用申請(qǐng)權(quán)限則直接回調(diào)到此處。
                            //Toast提示用戶前往設(shè)置允許權(quán)限
                        }
                    }
                });
C、區(qū)分三種場(chǎng)景回調(diào),多個(gè)權(quán)限申請(qǐng),合并結(jié)果處理。
        RxPermissions permissions = new RxPermissions(activity);
        permissions.setLogging(true);
        permissions.requestEachCombined(permissionStr)
                .subscribe(new Consumer<Permission>() {
                    @Override
                    public void accept(Permission permission) throws Exception {
                        if (permission.granted) {
                            //處理允許權(quán)限后的操作
                            return;
                        }
                        if (permission.shouldShowRequestPermissionRationale) {
                            //禁止,但沒(méi)有選擇“以后不再詢問(wèn)”,以后申請(qǐng)權(quán)限,會(huì)繼續(xù)彈出提示
                            //處理用戶點(diǎn)擊禁止后的操作
                            return;
                        }

                        //場(chǎng)景一:選擇“禁止并不再詢問(wèn)”;
                        //場(chǎng)景二:用戶點(diǎn)擊系統(tǒng)申請(qǐng)權(quán)限彈出框外部,使對(duì)話框消失;
                        //場(chǎng)景三:再此之前已經(jīng)點(diǎn)擊過(guò)"禁止并不再詢問(wèn)",調(diào)用申請(qǐng)權(quán)限則直接回調(diào)到此處。
                        //Toast提示用戶前往設(shè)置允許權(quán)限
                    }
                });

其他問(wèn)題

獲取權(quán)限名稱

網(wǎng)上方法PermissionInfo .loadLabel(pm).toString(),無(wú)法獲得權(quán)限名稱。 需自己做個(gè)定義來(lái)獲取權(quán)限名稱,在PermissionsDemo中已經(jīng)寫(xiě)好工具類(lèi)com.hero.simplepermissionsdemo.PermissionNameEnum,直接使用即可。

給小白的提示

系統(tǒng)權(quán)限分為兩類(lèi):正常權(quán)限和危險(xiǎn)權(quán)限。

正常權(quán)限:不會(huì)直接給用戶隱私權(quán)帶來(lái)風(fēng)險(xiǎn)。如果您的應(yīng)用在其清單中列出了正常權(quán)限,系統(tǒng)將自動(dòng)授予該權(quán)限。

危險(xiǎn)權(quán)限:會(huì)授予應(yīng)用訪問(wèn)用戶機(jī)密數(shù)據(jù)的權(quán)限。如果您的應(yīng)用在其清單中列出了正常權(quán)限,系統(tǒng)將自動(dòng)授予該權(quán)限。如果您列出了危險(xiǎn)權(quán)限,則用戶必須明確批準(zhǔn)您的應(yīng)用使用這些權(quán)限。

記得在在AndroidManifest.xml中添加所需權(quán)限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hero.simplepermissionsdemo">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.SimplePermissionsDemo">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
</manifest>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容