权限申请库:AndPermission(一)
在Android 6.0(也就是Android M)之前,权限在安装时全部授予,在保护隐私方面起到的作用有限;于是在Android 6.0及之后对权限进行了分类,涉及隐私等重要权限需要在运行时动态申请。另外,随着Android版本的更新迭代,有新的权限加入,也有旧的权限废弃。
关于权限的申请,之前就了解过一些优秀的库:通过注解申请权限的PermissionsDispatcher、阿里巴巴严振杰所写的AndPermission、以及集大成者RxPermission。
1、AndPermission介绍
本篇之所以选择AndPermission展开,因为看完源码后,发现其中有不少值得学习的地方。
GitHub:github.com/yanzhenjie/AndPermission
GitBook:yanzhenjie.com/AndPermission
1.1、简介
AndPermission是一个非常好用的权限申请开源库,至今一晃竟然有6年了,也算是安卓开源库中的元老,其类似Glide简洁的链式调用极大的简化了权限申请和回调。
此库已经近三年没有维护更新,issue多的离谱,所以不建议在项目中使用此库。尽管年久失修,但此库中的设计模式、权限管理、版本兼容做的都非常好。值得我们去阅读,学习源码中优秀的设计思路,对Android权限的理解很有帮助。
1.2、引入
使用AndPermission,在build.gradle中加入如下依赖即可:
dependencies {
implementation 'com.yanzhenjie:permission:2.0.2'
...
}
2、AndPermission使用
通常在Activity中通过requestPermissions()方法申请权限,然后在onRequestPermissionsResult()方法中处理权限申请结果,关于权限申请,另见Android权限检测申请源码流程分析一文。
有了AndPermission,申请权限操作一气呵成,通过设计良好的链式调用完成。后面详细阅读源码会知道,其实是借助BridgeActivity完成的。
2.1、申请权限
只需要下面几个简单的链式调用,即可完成权限申请、回调处理。with()方法的设计类似Glide库中的with(),可以在Fragment、Activity中调用。
AndPermission.with(this)
.runtime()
.permission(Permission.READ_CONTACTS)
//权限申请允许,或有权限时的回调
.onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> data) {
}
})
//权限申请被拒绝时
.onDenied(new Action<List<String>>() {
@Override
public void onAction(List<String> data) {
}
})
//无权限时,先回调这里。开发者进行下一步处理。
.rationale(new Rationale<List<String>>() {
@Override
public void showRationale(Context context, List<String> data, RequestExecutor executor) {
//可以调用executor.execute()申请权限,根据权限申请结果回调onDranted()或者onDenied()
//或者executor.cancel()放弃操作,会直接回调onDenied
}
})
//启动权限申请操作,最终通过BridgeActivity完成操作
.start();
2.2、权限判断
通过AndPermission的hasPermissions()方法判断应用有无某个权限:
/**
* Judgment already has the target permission.
*
* @param activity {@link Activity}.
* @param permissions one or more permissions.
* @return true, other wise is false.
*/
public static boolean hasPermissions(Activity activity, String... permissions) {
return PERMISSION_CHECKER.hasPermission(activity, permissions);
}
内部则是通过PermissionChecker检查权限, PermissionChecker有三种实现,分别是StandardChecker、StrictChecker以及DoubleChecker。
/**
* Classic permission checker.
*/
private static final PermissionChecker PERMISSION_CHECKER = new DoubleChecker();
而最后一种DoubleChecker则是前面标准权限检查和严格权限检查的双重检测:
public final class DoubleChecker implements PermissionChecker {
private static final PermissionChecker STANDARD_CHECKER = new StandardChecker();
private static final PermissionChecker STRICT_CHECKER = new StrictChecker();
@Override
public boolean hasPermission(Context context, String... permissions) {
return STRICT_CHECKER.hasPermission(context, permissions) &&
STANDARD_CHECKER.hasPermission(context, permissions);
}
@Override
public boolean hasPermission(Context context, List<String> permissions) {
return STRICT_CHECKER.hasPermission(context, permissions) &&
STANDARD_CHECKER.hasPermission(context, permissions);
}
}
3、其它用法
除了在权限方面的使用,AndPermission还有其它一些用法:install()、overlay()、notification()、setting()。它们的接口设计大都相似。
3.1、安装Apk
借助install(),可以执行安装apk文件。
/**
* 请求安装Apk文件
*/
AndPermission.with(this)
.install()
.file(apkFile)
.onDenied(new Action<File>() {
@Override
public void onAction(File data) {
//
}
})
.onGranted(new Action<File>() {
@Override
public void onAction(File data) {
//
}
})
.rationale(new Rationale<File>() {
@Override
public void showRationale(Context context, File data, RequestExecutor executor) {
//
}
})
.start();
使用该方法,必须要在AndroidManifest.xml中加上REQUEST_INSTALL_PACKAGES权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
而且,不是直接安装,需要用户授权后,才能调用PackageInstaller界面安装。
关于Apk的安装,另见Apk的安装过程探究一文。
3.2、系统设置
借助setting(),尝试执行写入系统设置的操作。似乎已经无法正常使用了。
/**
* 写入系统设置
*/
AndPermission.with(this)
.setting()
.write()
.onDenied(new Action<Void>() {
@Override
public void onAction(Void data) {
}
})
.onGranted(new Action<Void>() {
@Override
public void onAction(Void data) {
}
})
.rationale(new Rationale<Void>() {
@Override
public void showRationale(Context context, Void data, RequestExecutor executor) {
}
})
.start();
除了以上提到的三种用法,AndPermission还有其它一些用法, 这里没有一一尝试。
不推荐在项目上使用这个开源库,issue堆积如山,不少项目已经踩坑。Android原生的标准接口已经足够规范,使用原生方法即可。