1. 简述
AndPermission是一个运行权限管理库,兼容6.0以下版本。它采用链式调用方式,一句话申请所需权限,并且提供对拒绝过的权限自定义RationaleDailog来展示。它还可以方便的跳转到权限设置页面,尽大可能的兼容不同的手机系统。
2. 使用及分析
AndPermission的调用非常简单,比如申请最简单的存储权限
AndPermission.with(context)
.runtime()
.permission(Permission.Group.STORAGE)
.onGranted(new Action<List<String>>() {
@Override public void onAction(List<String> data) {
// Storage permission are allowed.
}
})
.onDenied(new Action<List<String>>() {
@Override public void onAction(List<String> data) {
// Storage permission are not allowed.
}
})
.start();
这边的onGranted和onDenied直接可以得到申请结果,而且他的调用不限制在Activity和Fragment内,随处可以调用,与原生的权限申请相比优势显得很明显。那它是如何办到的呢?我们一起来看它的源代码。
/**
* With {@link Fragment}.
*
* @param fragment {@link Fragment}.
* @return {@link Options}.
*/
public static Options with(Fragment fragment) {
return new Options(new SupportFragmentSource(fragment));
}
/**
* With {@link android.app.Fragment}.
*
* @param fragment {@link android.app.Fragment}.
* @return {@link Options}.
*/
public static Options with(android.app.Fragment fragment) {
return new Options(new FragmentSource(fragment));
}
/**
* With context.
*
* @param context {@link Context}.
* @return {@link Options}.
*/
public static Options with(Context context) {
return new Options(new ContextSource(context));
}
这边作者针对不同的环境,生成Options,而Options的构造参数Source在不同的环境下实现具有差异,主要的几个抽象方法
public abstract void startActivity(Intent intent);
public abstract void startActivityForResult(Intent intent, int requestCode);
//获取权限申请是否被拒绝过但仍然可以申请
public abstract boolean isShowRationalePermission(String permission);
再来看到Options内,这边需要调用runtime()
/**
* Handle runtime permissions.
*/
public Runtime runtime() {
return new Runtime(mSource);
}
生成Runtime,在看permission方法
public class Runtime {
private static final PermissionRequestFactory FACTORY;
...
static {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
FACTORY = new MRequestFactory();
} else {
FACTORY = new LRequestFactory();
}
}
...
/**
* One or more permissions.
*/
public PermissionRequest permission(String... permissions) {
checkPermissions(permissions);
return FACTORY.create(mSource).permission(permissions);
}
...
}
这边会根据不同的API使用不同的PermissionRequestFactory实现,我们重点先看MRequestFactory
public class MRequestFactory implements Runtime.PermissionRequestFactory {
@Override
public PermissionRequest create(Source source) {
return new MRequest(source);
}
它的create生成了MRequest,最后执行请求操作就是在这个MRequest
class MRequest implements PermissionRequest, RequestExecutor, PermissionActivity.RequestListener {
...
private String[] mPermissions;
//默认的mRationale,其实就是执行execute方法
private Rationale<List<String>> mRationale = new Rationale<List<String>>() {
@Override
public void showRationale(Context context, List<String> data, RequestExecutor executor) {
executor.execute();
}
};
...
@Override
public PermissionRequest permission(String... permissions) {
this.mPermissions = permissions;
return this;
}
...
@Override
public void start() {
List<String> deniedList = getDeniedPermissions(STANDARD_CHECKER, mSource, mPermissions);
mDeniedPermissions = deniedList.toArray(new String[deniedList.size()]);
if (mDeniedPermissions.length > 0) {
List<String> rationaleList = getRationalePermissions(mSource, mDeniedPermissions);
if (rationaleList.size() > 0) {
mRationale.showRationale(mSource.getContext(), rationaleList, this);
} else {
execute();
}
} else {
dispatchCallback();
}
}
@Override
public void execute() {
PermissionActivity.requestPermission(mSource.getContext(), mDeniedPermissions, this);
}
...
/**
* Get denied permissions.
*/
private static List<String> getDeniedPermissions(PermissionChecker checker, Source source, String... permissions) {
List<String> deniedList = new ArrayList<>(1);
for (String permission : permissions) {
if (!checker.hasPermission(source.getContext(), permission)) {
deniedList.add(permission);
}
}
return deniedList;
}
/**
* Get permissions to show rationale.
*/
private static List<String> getRationalePermissions(Source source, String... permissions) {
List<String> rationaleList = new ArrayList<>(1);
for (String permission : permissions) {
if (source.isShowRationalePermission(permission)) {
rationaleList.add(permission);
}
}
return rationaleList;
}
重点观察start()这个方法
@Override
public void start() {
//获取所申请的权限中未获得的
List<String> deniedList = getDeniedPermissions(STANDARD_CHECKER, mSource, mPermissions);
mDeniedPermissions = deniedList.toArray(new String[deniedList.size()]);
//如果有未获得的(需要申请)
if (mDeniedPermissions.length > 0) {
//找到那些申请被拒绝过的权限,如果有就需要特殊处理
List<String> rationaleList = getRationalePermissions(mSource, mDeniedPermissions);
if (rationaleList.size() > 0) {
//可以自定义mRationale对被拒绝过的权限处理,默认方式和下面一下,直接execute();
mRationale.showRationale(mSource.getContext(), rationaleList, this);
} else {
//去申请了
execute();
}
}
//没有未获得的,那就是全部申请过了,直接返回成功
else {
dispatchCallback();
}
}
重点来看到execute的处理
@Override
public void execute() {
PermissionActivity.requestPermission(mSource.getContext(), mDeniedPermissions, this);
}
直接启动了一个PermissionActivity!!!!并且我们发现这个PermissionActivity其实没有页面。
public final class PermissionActivity extends Activity {
private static RequestListener sRequestListener;
/**
* Request for permissions.
*/
public static void requestPermission(Context context, String[] permissions, RequestListener requestListener) {
PermissionActivity.sRequestListener = requestListener;
Intent intent = new Intent(context, PermissionActivity.class);
intent.putExtra(KEY_INPUT_OPERATION, VALUE_INPUT_PERMISSION);
intent.putExtra(KEY_INPUT_PERMISSIONS, permissions);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
int operation = intent.getIntExtra(KEY_INPUT_OPERATION, 0);
switch (operation) {
case VALUE_INPUT_PERMISSION: {
String[] permissions = intent.getStringArrayExtra(KEY_INPUT_PERMISSIONS);
if (permissions != null && sRequestListener != null) {
requestPermissions(permissions, VALUE_INPUT_PERMISSION);
} else {
finish();
}
break;
}
case VALUE_INPUT_PERMISSION_SETTING: {
if (sRequestListener != null) {
RuntimeSettingPage setting = new RuntimeSettingPage(new ContextSource(this));
setting.start(VALUE_INPUT_PERMISSION_SETTING);
} else {
finish();
}
break;
}
...
}
...
//申请权限的回调函数
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (sRequestListener != null) {
sRequestListener.onRequestCallback();
}
finish();
}
...
}
OK,如此简单。PermissionActivity的作用就是承担一个中间者的作用,不管你要请求什么权限,都从PermissionActivity发起,并且使用静态变量,在PermissionActivity的回调结果给外部。另外这个库还处理了,浮窗权限申请,安装回调,跳转设置页面的处理,同样都是在PermissionActivity中完成。