前言
前一段时间看了郭霖前辈的一个关于运行时权限封装的视频,现在写一篇文章总结一下我在这个视频里学到的知识。
首先讲一下运行时权限的基本使用:
if (ContextCompat.checkSelfPermission(MainActivity.this, "权限名") != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, "权限名", 1);
}
/**
* @param requestCode 请求码,用于标识请求者
* @param permissions 请求的权限列表
* @param grantResults 请求的权限是否成功的列表
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//申请成功
} else {
//申请失败或被拒绝
}
break;
}
}
首先用checkSelfPermission()方法(接收两个参数,活动的实例和权限名)判断你需要的权限有没有被授权过,如果没有授权就通过requestPermissions()方法(接收三个参数,活动的实例、权限名和请求码)申请权限。然后重写Activity里的onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法,这个方法有三个参数,第一个requestCode就是requestPermissions()方法里的第三个参数,第二个数组是你请求的权限列表,第三个参数是你请求的权限是否授权的列表,第二个和第三个参数是对应的,permissions[0]里的权限对应grantResults[0]。
封装
现在进入正题,运行时权限的封装的难点在于回调的onRequestPermissionsResult()方法,这个方法是Activity和Fragment类里的方法,只能在继承这两个类的类中重新这两个方法。也就是说运行时权限只能封装在继承这两个类的类里面。
运行时权限的封装已知的方法有三种:
- 第一种方法是建立一个透明的Activity,将代码封装在这个Activity中,在这个Activity上申请权限,这样用户觉察不到这个Activity,但是却能实现我们的功能。
- 第二种方法是将运行时权限封装在fragment中,使用时将这个fragment添加到当前的Activity中,由于这个fragment是没有界面的,所以屏幕不会有任何变化,但是已经实现我们的功能了。
- 第三种方法是最简单的,建立一个BaseActivity继承AppCompatActivity,然后将运行时权限写在BaseActivity中,再让所有的活动都继承BaseActivity,这样就可以直接申请权限了。
第一种和第二种就不详细讲了,第二种有一个框架可以直接使用https://github.com/tbruyelle/RxPermissions
第三种着重讲一下:
首先新建一个ActivityCollector类:
public class ActivityCollector {
private static List<Activity> activityList = new ArrayList<Activity>();
public static void addActivity(Activity activity){
activityList.add(activity);
}
public static void removeActivity(Activity activity){
activityList.remove(activity);
}
public static Activity getTopActivity(){
if (activityList.isEmpty()) {
return null;
} else {
return activityList.get(activityList.size() - 1);
}
}
}
这是一个活动管理类,每个活动启动后都添加到这个管理类中,使用这个类的好处是可以在任何地方获取活动示例,从而在任何地方都可以请求权限。
然后新建一个PermissionListener接口:
public interface PermissionListener {
void onGranted();
void onDenied(List<String> deniedPermission);
}
这个接口定义了两个方法,分别是权限申请成功和失败的方法,用于回调;
最后在新建一个BaseActivity类:
public class BaseActivity extends AppCompatActivity {
private static PermissionListener permissionListener;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
public static void requestRuntimePermissions(String[] permissions, PermissionListener listener) {
permissionListener = listener;
Activity topActivity = ActivityCollector.getTopActivity();
if (topActivity == null) {
return;
}
List<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(topActivity, permission) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(permission);
}
}
if (!permissionList.isEmpty()) {
ActivityCompat.requestPermissions(topActivity, permissionList.toArray(new String[permissionList.size()]), 1);
} else {
listener.onGranted();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
List<String> deniedPermission = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
int grantResult = grantResults[i];
String permission = permissions[i];
if (grantResult != PackageManager.PERMISSION_GRANTED) {
deniedPermission.add(permission);
}
}
if (deniedPermission.isEmpty()) {
permissionListener.onGranted();
} else {
permissionListener.onDenied(deniedPermission);
}
}
break;
}
}
}
在这个类中重写了onCreate、onDestroy和onRequestPermissionsResult三个方法,新建了一个requestRuntimePermissions静态方法;在onCreate和onDestroy中向ActivityCollector里添加和删除活动实例,在requestRuntimePermissions中添加请求权限的逻辑,定义成静态可以在任何地方调用,onRequestPermissionsResult是重写的请求的回调,还记得我们定义的那个接口吗,在申请成功或失败后回调这个接口。
最后我们只需使用下面的代码调用就可以了:
BaseActivity.requestRuntimePermissions(new String[]{"Permissions"}, new PermissionListener() {
@Override
public void onGranted() {
//申请成功
}
@Override
public void onDenied(List<String> deniedPermission) {
//申请失败,以及失败的权限列表
}
});
到这里运行时权限的封装就完成了。
我专门写了一个开源框架,里面就是我说的第三种方法,大家不想打代码的可以直接去使用
https://github.com/mashanshui/MssPermission