Android6.0動態權限框架

已經快有小兩年沒有寫過文章了,時間過的可真快,轉眼,18年又要過去了。 android

image.png

正好最近項目也在作targetSdkVersion升級到28,以前對6.0略微瞭解點,我的感受,動態權限的使用這裏不太友好,須要在Activity 或者 Fragment 中重寫onRequestPermissionsResult 方法,而後處理個個權限的申請結果,耦合性很高,因而,就寫了一個輕量級的權限申請框架,在這篇文章中分爲3個步驟爲你們講解。git

  • 1.權限的基本知識
  • 2.介紹一下框架的使用
  • 3.這個權限框架是怎麼實現的

1、權限的基本知識

google 從M版本(Android6.0,TargetSdkVersion 23)開始引入的動態權限,因此要想使用動態受權,請保證TargetSdkVersion 大於等於23。github

Google Android 6.0適配文檔api

以前TargetSdkVersion 小於23 時,app不須要動態受權,咱們能夠默默的搞事情,甚至在8.0的手機上也是默認授予權限的,如今GooglePlay 強制要求TargetSdkVersion 大於等於26,國內的應用市場明年也要開始效仿google,若是達不到規定的版本,app是不容許上架的。因此TargetSdkVersion升級,是遲早的事。數組

  • 特此說明一點:國外6.0如下的手機是沒有權限設置頁面的,只是國內的廠商自做聰明6.0如下加入了權限設置頁面,並且加入就加入吧,搞的他們自身都是bug,致使咱們使用正常的api去檢測國內廠商6.0如下手機時,檢測的都是錯誤的結果,因此6.0如下手機請經過,try catch 去捕獲異常,而後作特殊處理。
  • 權限檢查
PermissionChecker.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED
複製代碼

這裏用PermissionChecker檢查是否授予了某項權限,兼容性更好一點bash


  • 申請權限
requestPermissions(permissions, REQUEST_CODE);
複製代碼

permissions 是一個數組,能夠申請多個權限,REQUEST_CODE 爲請求碼用於在onRequestPermissionsResult中處理結果app


  • 處理權限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 //處理對應的權限結果
}
複製代碼

基本概念已經介紹完了,動態權限中使用到的就是這三個方法框架


那麼都什麼權限須要咱們去申請呢?ide

固然是涉及到用戶隱私的權限了,在google文檔中叫作危險權限 (Dangerous permissions and permission groups)這裏又涉及到了一個權限組的概念,咱們就拿 sdcard 爲例簡單說一下,READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE (讀寫sdcard)權限同屬於STORAGE的權限組,只要申請了其中一個權限,另外一個就沒必要再申請了,系統會默認授予這個權限組的全部權限。gradle

下面列出全部的危險權限與權限組

image.png

2、框架的使用

  • app下 build.gradle中
dependencies {
compile 'com.mj:dynamicpermission:1.0.0'
}
複製代碼
  • 或者直接下載源碼 copy 三個類到項目中就能夠,文章末尾會給出下載地址
    image.png
DynamicPermissionEmitter permissionEmitter = new DynamicPermissionEmitter(this);

permissionEmitter.emitterPermission(new DynamicPermissionEmitter.ApplyPermissionsCallback() {

            @Override
            public void applyPermissionResult(Map<String, DynamicPermissionEntity> permissionEntityMap) {
                DynamicPermissionEntity permissionEntity = permissionEntityMap.get(permissionName);
                if (permissionEntity.isGranted()) {
                    //權限容許,能夠搞事情了
                } else if (permissionEntity.shouldShowRequestPermissionRational()) {
                    //勾選不在提示,且點擊了拒絕,在這裏給用戶提示權限的重要性,給一個友好的提示
                } else {
                    //拒絕了權限,不能亂搞
                }
            }
        }, permissionName);
複製代碼

this 指:FragmentActivity 或 v4包下的 Fragment,爲何須要這個參數,後面講解實現的時候會作說明

經過permissionEmitter發射權限, @params1 傳入一個處理權限結果的回調 @params2 傳入須要申請的權限名稱,能夠以數組的形式將權限名稱傳入,支持多個權限

至此權限的使用就介紹完了,使用起來仍是比較簡單的,並且已經應用到幾百萬日活的app中


3、如何實現的?

  • 先貼一段DynamicPermissionEmitter 構造方法你們就知道怎麼回事了
/**
     * 構造方法
     *
     * @param activity fragmentActivity
     */
    public DynamicPermissionEmitter(@NonNull FragmentActivity activity) {
        try {
            generateApplyPermissionFragment(activity.getSupportFragmentManager());

        } catch (Exception e) {
            handleFragmentException(activity, e);
        }
    }

    /**
     * 構造方法
     *
     * @param fragment v4 包下的 fragment
     */
    @SuppressLint("LongLogTag")
    public DynamicPermissionEmitter(@NonNull Fragment fragment) {
        try {
            generateApplyPermissionFragment(fragment.getChildFragmentManager());
        } catch (Exception e) {
            Log.e(TAG, "DynamicPermissionEmitter fragment", e);
        }
    }


    /**
     *
     * @param activity fragment
     * @param e        exception
     */
    @SuppressLint("LongLogTag")
    private void handleFragmentException(@NonNull FragmentActivity activity, Exception e) {
        FragmentManager supportFragmentManager = activity.getSupportFragmentManager();
        if (supportFragmentManager != null) {
            List<Fragment> fragments = supportFragmentManager.getFragments();
            if (fragments != null) {
                for (int i = 0; i < fragments.size(); i++) {
                    Fragment fragment = fragments.get(i);
                    if (TAG.equals(fragment.getTag())) {
                        continue;
                    }
                    try {
                        generateApplyPermissionFragment(fragment.getChildFragmentManager());
                    } catch (Exception e1) {
                        Log.e(TAG, "DynamicPermissionEmitter activity", e);
                    }
                    break;
                }
            }
        }
    }

    /**
     * 生成申請權限的fragment
     *
     * @param fragmentManager fragmentManager
     */
    private void generateApplyPermissionFragment(@NonNull FragmentManager fragmentManager) throws Exception {
        this.fragmentManager = fragmentManager;
        Fragment mFragment = fragmentManager.findFragmentByTag(DYNAMIC_PERMISSION_FRAGMENT_TAG);
        // 保證一個activity 或 fragment 只添加一個permission fragment
        if (mFragment != null) {
            dynamicPermissionFragment = (DynamicPermissionFragment) mFragment;
        } else {
            dynamicPermissionFragment = DynamicPermissionFragment.newInstance();
            fragmentManager
                    .beginTransaction()
                    .add(dynamicPermissionFragment, DYNAMIC_PERMISSION_FRAGMENT_TAG)
                    .commitNow();
        }
    }
複製代碼
  • 從上面代碼能夠看出全部構造方法都調用了generateApplyPermissionFragment方法,這個方法中生成了一個 與用戶無任何交互的Fragment 也就是用戶看不見的Fragment,咱們的全部權限申請、檢查、結果處理都是在這個Fragment中。

  • 這也能解釋出爲何使用的時候須要傳入FragmentActivity 或者 Fragment ,由於咱們須要FragmentManager來加入一個看不見的Fragment 。

  • 至此你們應該瞭解了這個權限申請究竟是怎麼回事了,DynamicPermissionFragment的代碼我就不貼出來了,有興趣的能夠下載源碼,去看,裏邊就是用到了最基本的權限申請、權限檢查、onRequestPermissionsResult 處理結果,最後經過回調的形式返回的

歡迎star,或者你們有什麼想法或問題,隨時聯繫我,咱們一塊兒讓它變的更增強大

image.png

github下載地址

csdn下載地址

相關文章
相關標籤/搜索