EasyPermissions Android權(quán)限適配(帶流程圖)

前言

閱讀前說明:

  • 所有系統(tǒng)均為Android原生系統(tǒng),其他國(guó)產(chǎn)ROM最后再討論。
  • 所有的申請(qǐng)都為主動(dòng)觸發(fā),即主動(dòng)點(diǎn)擊申請(qǐng)按鈕。
  • 申請(qǐng)時(shí),默認(rèn)是沒有權(quán)限的。
  • 流程圖中長(zhǎng)方形中為方法名。

流程圖

申請(qǐng)單個(gè)權(quán)限流程圖

img

申請(qǐng)權(quán)限組流程圖

img

申請(qǐng)混合權(quán)限(單個(gè)權(quán)限+權(quán)限組)流程圖

具體流程=單個(gè)權(quán)限流程圖+權(quán)限組流程圖
代碼中有例子,就不詳細(xì)說明了。

EasyPermissions使用

easypermissions

  1. 依賴
dependencies {
    implementation 'pub.devrel:easypermissions:1.2.0'
}
  1. 檢查權(quán)限并申請(qǐng)權(quán)限
    public static final int PERMISSION_STORAGE_CODE = 10001;
    public static final String PERMISSION_STORAGE_MSG = "此app需要獲取SD卡讀取權(quán)限";
    public static final String[] PERMISSION_STORAGE = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};

    public static boolean hasPermissions(Context context, String... permissions) {
        return EasyPermissions.hasPermissions(context, permissions);
    }


    /**
     * 是否有SD卡權(quán)限
     *
     * @param context
     * @return
     */
    public static boolean hasStoragePermission(Context context) {
        return hasPermissions(context, PERMISSION_STORAGE);
    }

    @AfterPermissionGranted(PERMISSION_STORAGE_CODE)
     public void initSimple() {
          if (hasStoragePermission(context)) {
             //有權(quán)限
         } else {
             //申請(qǐng)權(quán)限
             EasyPermissions.requestPermissions(context, PERMISSION_STORAGE_MSG, PERMISSION_STORAGE_CODE, PERMISSION_STORAGE);
         }
     }

  1. 實(shí)現(xiàn)EasyPermissions.PermissionCallbacks接口,直接處理權(quán)限是否成功申請(qǐng)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        // Forward results to EasyPermissions
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    //成功
    @Override
    public void onPermissionsGranted(int requestCode, List<String> list) {
        // Some permissions have been granted
        // ...
    }

    //失敗
    @Override
    public void onPermissionsDenied(int requestCode, List<String> list) {
        // Some permissions have been denied
        // ...
    }

Dailog說明

  1. RationaleDialog:申請(qǐng)權(quán)限的說明。

[圖片上傳失敗...(image-da33d8-1530149961979)]

EasyPermissions.requestPermissions(context, PERMISSION_STORAGE_MSG, PERMISSION_STORAGE_CODE, PERMISSION_STORAGE);

或者

EasyPermissions.requestPermissions(
        new PermissionRequest.Builder(this, RC_CAMERA_AND_LOCATION, perms)
                .setRationale(R.string.camera_and_location_rationale)
                .setPositiveButtonText(R.string.rationale_ask_ok)
                .setNegativeButtonText(R.string.rationale_ask_cancel)
                .setTheme(R.style.my_fancy_style)
                .build());

方法回調(diào)實(shí)現(xiàn)EasyPermissions.RationaleCallbacks接口:

   /**
     * dialog提醒點(diǎn)擊“確定”
     *
     * @param requestCode
     */
    @Override
    public void onRationaleAccepted(int requestCode) {
    }

    /**
     * dialog提醒點(diǎn)擊“取消”
     *
     * @param requestCode
     */
    @Override
    public void onRationaleDenied(int requestCode) {
    }

詳細(xì)使用參考:easypermissions

  1. AppSettingsDialog:跳轉(zhuǎn)setting頁(yè),申請(qǐng)被拒絕時(shí)使用。
AppSettingsDialog
 /**
     * 拒絕權(quán)限
     *
     * @param requestCode
     * @param perms
     */
    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            new AppSettingsDialog.Builder(this)
                    .setTitle("提醒")
                    .setRationale("此app需要這些權(quán)限才能正常使用")
                    .build()
                    .show();
        }
    }

方法回調(diào)

/**
       /**
         * 設(shè)置頁(yè)面回調(diào)
         *
         * @param requestCode
         * @param resultCode
         * @param data
         */
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
                if (PermissionUtils.hasStoragePermission(context)){
                    //有權(quán)限
                }else{
                    //沒有權(quán)限
                }
            }
        }

國(guó)產(chǎn)ROM適配

國(guó)產(chǎn)ROM問題一直是最多的,申請(qǐng)權(quán)限的彈窗不按Android原生來,有時(shí)候允許權(quán)限了,回調(diào)卻是走失敗。
如果想適配國(guó)產(chǎn)ROM,我推薦 AndPermission

AndPermission概述

AndPermission可以簡(jiǎn)化在Android上請(qǐng)求權(quán)限的流程。

  • 在Android6.0或者更高版本的系統(tǒng)中請(qǐng)求運(yùn)行時(shí)權(quán)限。
  • 在Android7.0或者更高版本的系統(tǒng)中分享私有文件。
  • 在Android8.0或者更高版本的系統(tǒng)中安裝Apk文件。

請(qǐng)求流程

為了兼容一些特殊中國(guó)產(chǎn)手機(jī),AndPermission請(qǐng)求權(quán)限的流程是這樣的:

                      發(fā)起請(qǐng)求
                         │
              調(diào)用SDK Api判斷是否有權(quán)限
                         │
           ┌─────────────┴─────────────┐
         有權(quán)限                      沒權(quán)限
           │                           │
           │                  使用SDK Api請(qǐng)求權(quán)限
           │                           │
           │                    用戶授權(quán)或者拒絕
           └─────────────┬─────────────┘
                  執(zhí)行權(quán)限相關(guān)代碼
                 ┌───────┴───────┐
                正常            異常
                 │               │
             onGranted()      onDenied()
          ┌──────┴──────┐        │
         正常          異常───────┘

申請(qǐng)流程的釋義

可以看出AndPermission的申請(qǐng)流程和標(biāo)準(zhǔn)的申請(qǐng)流程大相徑庭,這樣做主要是因?yàn)橐韵聨c(diǎn)原因。

  • 兼容Android5.0的系統(tǒng)判斷是否有權(quán)限。
  • 部分設(shè)備上使用SDK的Api判斷是否有權(quán)限時(shí),無論是否有權(quán)限都返回true。
  • 部分設(shè)備上無論用戶點(diǎn)擊同意還是拒絕都返回true。
  • 部分設(shè)備在申請(qǐng)權(quán)限時(shí)并不會(huì)彈出授權(quán)Dialog,而是在執(zhí)行權(quán)限相關(guān)代碼時(shí)才會(huì)彈出授權(quán)Dialog。
特特特別注意:

因?yàn)椴糠謾?quán)限(例如發(fā)送短信、打電話、接聽/掛斷電話等),AndPermission不能執(zhí)行權(quán)限相關(guān)代碼做測(cè)試,所以對(duì)于這一類權(quán)限在執(zhí)行權(quán)限相關(guān)代碼步驟僅僅使用了AppOpsManager做檢測(cè)。因?yàn)闃O少部分國(guó)產(chǎn)機(jī)總是返回true,因此直接回調(diào)到onGranted()中讓開發(fā)者執(zhí)行相關(guān)代碼來輔助AndPermission的整個(gè)流程,如果onGranted()方法發(fā)生異常,那么則認(rèn)為是沒有權(quán)限,所以重新回調(diào)到onDenied()方法中,如果onGranted()方法正常執(zhí)行那么則認(rèn)為有權(quán)限。這樣一來剛好是一個(gè)完整的流程,也可以最大限度的兼容到更多異常的手機(jī)。

回調(diào)onGranted()時(shí)AndPermission對(duì)onGranted()方法做了try catch。這樣做可以保證兩點(diǎn),第一點(diǎn)是防止部分手機(jī)返回錯(cuò)誤狀態(tài)時(shí)回調(diào)了onGranted()后的崩潰,第二點(diǎn)是防止部分手機(jī)需要真正執(zhí)行權(quán)限相關(guān)代碼時(shí)觸發(fā)授權(quán)Dialog后被用戶拒絕后的崩潰。而這兩點(diǎn)都是沒有權(quán)限,因此會(huì)重新回調(diào)到onDenied()中讓開發(fā)者處理沒權(quán)限的情況。

綜上所述,如果onGranted()和onDenied()方法都被調(diào)用了,說明開發(fā)者的onGranted()方法發(fā)生了異常。

AndPermission詳細(xì)說明文檔

GitHub

GitHub

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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