翻了翻簡書的文章動態(tài),已經(jīng)快有小兩年沒有寫過文章了钱烟,時間過的可真快晰筛,轉(zhuǎn)眼嫡丙,18年又要過去了。
正好最近項目也在做targetSdkVersion升級到28读第,之前對6.0略微了解點(diǎn)曙博,個人感覺,動態(tài)權(quán)限的使用這里不太友好怜瞒,需要在Activity 或者 Fragment 中重寫onRequestPermissionsResult 方法父泳,然后處理個個權(quán)限的申請結(jié)果,耦合性很高吴汪,于是惠窄,就寫了一個輕量級的權(quán)限申請框架,在這篇文章中分為3個步驟為大家講解漾橙。
- 1.權(quán)限的基本知識
- 2.介紹一下框架的使用
- 3.這個權(quán)限框架是怎么實(shí)現(xiàn)的
一杆融、權(quán)限的基本知識
google 從M版本(Android6.0,TargetSdkVersion 23)開始引入的動態(tài)權(quán)限,所以要想使用動態(tài)授權(quán)霜运,請保證TargetSdkVersion 大于等于23脾歇。
之前TargetSdkVersion 小于23 時,app不需要動態(tài)授權(quán)淘捡,我們可以默默的搞事情藕各,甚至在8.0的手機(jī)上也是默認(rèn)授予權(quán)限的,現(xiàn)在GooglePlay 強(qiáng)制要求TargetSdkVersion 大于等于26案淋,國內(nèi)的應(yīng)用市場明年也要開始效仿google,如果達(dá)不到規(guī)定的版本座韵,app是不允許上架的。所以TargetSdkVersion升級踢京,是早晚的事誉碴。
- 特此說明一點(diǎn):國外6.0以下的手機(jī)是沒有權(quán)限設(shè)置頁面的,只是國內(nèi)的廠商自作聰明6.0以下加入了權(quán)限設(shè)置頁面瓣距,而且加入就加入吧黔帕,搞的他們自身都是bug,導(dǎo)致我們使用正常的api去檢測國內(nèi)廠商6.0以下手機(jī)時,檢測的都是錯誤的結(jié)果蹈丸,所以6.0以下手機(jī)請通過成黄,try catch 去捕獲異常,然后做特殊處理逻杖。
- 權(quán)限檢查
PermissionChecker.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED
這里用PermissionChecker檢查是否授予了某項權(quán)限奋岁,兼容性更好一點(diǎn)
- 申請權(quán)限
requestPermissions(permissions, REQUEST_CODE);
permissions 是一個數(shù)組,可以申請多個權(quán)限荸百,REQUEST_CODE 為請求碼用于在onRequestPermissionsResult中處理結(jié)果
- 處理權(quán)限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//處理對應(yīng)的權(quán)限結(jié)果
}
基本概念已經(jīng)介紹完了闻伶,動態(tài)權(quán)限中使用到的就是這三個方法
那么都什么權(quán)限需要我們?nèi)ド暾埬兀?/strong>
當(dāng)然是涉及到用戶隱私的權(quán)限了,在google文檔中叫做危險權(quán)限 (Dangerous permissions and permission groups)這里又涉及到了一個權(quán)限組的概念够话,我們就拿 sdcard 為例簡單說一下蓝翰,READ_EXTERNAL_STORAGE 與WRITE_EXTERNAL_STORAGE (讀寫sdcard)權(quán)限同屬于STORAGE的權(quán)限組光绕,只要申請了其中一個權(quán)限,另一個就不必再申請了畜份,系統(tǒng)會默認(rèn)授予這個權(quán)限組的所有權(quán)限诞帐。
下面列出所有的危險權(quán)限與權(quán)限組
二、框架的使用
- app下 build.gradle中
dependencies {
compile 'com.mj:dynamicpermission:1.0.0'
}
-
或者直接下載源碼 copy 三個類到項目中就可以爆雹,文章末尾會給出下載地址
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()) {
//權(quán)限允許停蕉,可以搞事情了
} else if (permissionEntity.shouldShowRequestPermissionRational()) {
//勾選不在提示,且點(diǎn)擊了拒絕顶别,在這里給用戶提示權(quán)限的重要性谷徙,給一個友好的提示
} else {
//拒絕了權(quán)限,不能亂搞
}
}
}, permissionName);
this 指:FragmentActivity 或 v4包下的 Fragment,為什么需要這個參數(shù)驯绎,后面講解實(shí)現(xiàn)的時候會做說明
通過permissionEmitter發(fā)射權(quán)限,
@params1 傳入一個處理權(quán)限結(jié)果的回調(diào)
@params2 傳入需要申請的權(quán)限名稱谋旦,可以以數(shù)組的形式將權(quán)限名稱傳入剩失,支持多個權(quán)限
至此權(quán)限的使用就介紹完了,使用起來還是比較簡單的册着,而且已經(jīng)應(yīng)用到幾百萬日活的app中
三拴孤、如何實(shí)現(xiàn)的?
- 先貼一段DynamicPermissionEmitter 構(gòu)造方法大家就知道怎么回事了
/**
* 構(gòu)造方法
*
* @param activity fragmentActivity
*/
public DynamicPermissionEmitter(@NonNull FragmentActivity activity) {
try {
generateApplyPermissionFragment(activity.getSupportFragmentManager());
} catch (Exception e) {
handleFragmentException(activity, e);
}
}
/**
* 構(gòu)造方法
*
* @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;
}
}
}
}
/**
* 生成申請權(quán)限的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();
}
}
從上面代碼可以看出所有構(gòu)造方法都調(diào)用了generateApplyPermissionFragment方法甲捏,這個方法中生成了一個 與用戶無任何交互的Fragment 也就是用戶看不見的Fragment,我們的所有權(quán)限申請演熟、檢查、結(jié)果處理都是在這個Fragment中司顿。
這也能解釋出為什么使用的時候需要傳入FragmentActivity 或者 Fragment 芒粹,因為我們需要FragmentManager來加入一個看不見的Fragment 。
至此大家應(yīng)該了解了這個權(quán)限申請到底是怎么回事了大溜,DynamicPermissionFragment的代碼我就不貼出來了化漆,有興趣的可以下載源碼,去看钦奋,里邊就是用到了最基本的權(quán)限申請座云、權(quán)限檢查、onRequestPermissionsResult 處理結(jié)果付材,最后通過回調(diào)的形式返回的
歡迎star,或者大家有什么想法或問題朦拖,隨時聯(lián)系我,我們一起讓它變的更加強(qiáng)大