已經快有小兩年沒有寫過文章了,時間過的可真快,轉眼,18年又要過去了。 android
正好最近項目也在作targetSdkVersion升級到28,以前對6.0略微瞭解點,我的感受,動態權限的使用這裏不太友好,須要在Activity 或者 Fragment 中重寫onRequestPermissionsResult 方法,而後處理個個權限的申請結果,耦合性很高,因而,就寫了一個輕量級的權限申請框架,在這篇文章中分爲3個步驟爲你們講解。git
google 從M版本(Android6.0,TargetSdkVersion 23)開始引入的動態權限,因此要想使用動態受權,請保證TargetSdkVersion 大於等於23。github
以前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_STORAGE 與WRITE_EXTERNAL_STORAGE (讀寫sdcard)權限同屬於STORAGE的權限組,只要申請了其中一個權限,另外一個就沒必要再申請了,系統會默認授予這個權限組的全部權限。gradle
下面列出全部的危險權限與權限組
dependencies {
compile 'com.mj:dynamicpermission:1.0.0'
}
複製代碼
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中
/**
* 構造方法
*
* @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,或者你們有什麼想法或問題,隨時聯繫我,咱們一塊兒讓它變的更增強大