实现背景:
最近写项目有多处需要动态的申请权限,Android原生的权限申请方式虽然足够简单但是却并不是很方便。
比如首先要通过checkSelfPermission
去判断是否已经有权限,已经有权限则进行相应的业务处理,如果没有权限则通过requestPermissions
申请权限,并且在onRequestPermissionsResult
回调方法中再次进行判断,如果有权限再次调用业务代码。
也就是业务代码需要进行两次调用,所以想要把权限申请的部分进行封装,并且不需要在onRequestPermissionsResult
回调任何代码。
基本原理
首先调用requestPermissions
只有通过回调才能知道用户是不是对权限进行了授权,这点无法改变。但是我们可以通过一个维护一个临时的Fragment
添加到Activity
中,然后再调用此Fragment
的requestPermissions
方法去申请权限,这样用户进行操作后就会回调Fragment
中的onRequestPermissionsResult
(因为Fragment的生命周期与宿主Activity相同)。然后再Fragment中通过回调方法进行授权的结果判断。
具体实现
我把具体实现的代码放在了文末供大家参考。实现匆忙,仅为原理验证,所以尚有不足还望见谅。
使用方法
参考文末的代码,新建一个类,然后把代码复制到自己这个类中。
申请权限的方法
FastPermissions fastpermissions = new FastPermissions(this);
fastPermissions.need(Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe(new FastPermissions.Subscribe() {
@Override
public void onResult(int requestCode, boolean allGranted, String[] permissions) {
if (allGranted){
//权限允许后进行的操作
}else{
//权限拒绝后进行的操作
Toast.makeText(getActivity(), "权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}).request(1);
使用解释
简化一下其实就是这样
//实例化方法
FastPermissions fastpermissions = new FastPermissions(this);
fastpermission.need(/*这里设置需要的权限*/).subscribe(/* 设置回调 */).request(/*请求码*/);
@需要设置的权限 这里可以为单个权限也可以为权限字符串数组
@回调的方法
new FastPermissions.Subscribe() {
@Override
public void onResult(int requestCode, boolean allGranted, String[] permissions) {
if (allGranted){
//权限允许
}
else
{
//权限被拒绝
}
}
}
@请求码 多次调用请求的时候务必设置不同的请求码
使用注意
- 因为其原理是维护了一个临时的Fragment,所以从节省资源的角度考虑,一个Activity最多对FastPermission实例化一次。
- 实例化的时候传入的Activity必须继承自AppCompatActivity,不能继承Activity
完整代码
package cn.dingd.darkchat;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
public class FastPermissions {
private final String TAG = FastPermissions.class.getSimpleName();
private Activity activity;
private PermissionFragment permissionFragment;
/**
* 订阅回调接口
*/
public interface Subscribe {
void onResult(int requestCode, boolean allGranted, String[] permissions);
}
/**
* 内部回调使用,用户不应该调用或者实现此接口
*/
public interface Callback {
void onRequestPermissionsCallback(final int requestCode, String[] permissions, int[] grantResults);
}
static public class PermissionFragment extends Fragment {
private HashMap<Integer, Callback> callbacks = new HashMap<>();
private ArrayList<Runnable> runnables = new ArrayList<>();
public void registerCallback(int requestCode, Callback callback) {
callbacks.put(requestCode, callback);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
Log.d("PermissionFragment", "延迟执行");
while (!runnables.isEmpty())
runnables.remove(0).run();
}
public void postRequestPermissions(final String[] permissions, final int requestCode) {
if (isAdded()) {
requestPermissions(permissions, requestCode);
} else {
runnables.add(new Runnable() {
@Override
public void run() {
requestPermissions(permissions, requestCode);
}
});
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NotNull final String[] permissions, @NotNull final int[] grantResults) {
if (callbacks.containsKey(requestCode)) {
Callback callback = callbacks.get(requestCode);
if (callback != null)
callback.onRequestPermissionsCallback(requestCode, permissions, grantResults);
}
}
}
/**
* 快捷的进行权限申请,通过添加一个临时的Fragment来进行生命周期管理,因此
* 一个Activity请只初始化一个FastPermissions实例
*
* @param appCompatActivity 所在的activity,必须继承自AppCompatActivity
*/
public FastPermissions(AppCompatActivity appCompatActivity) {
if (appCompatActivity == null)
throw new IllegalArgumentException("Activity must not be null!");
permissionFragment = new PermissionFragment();
activity = appCompatActivity;
FragmentManager fragmentManager = appCompatActivity.getSupportFragmentManager();
fragmentTransaction(fragmentManager);
}
public FastPermissions(Fragment fragment) {
activity = fragment.getActivity();
if (activity == null)
throw new IllegalArgumentException("Activity must not be null!");
permissionFragment = new PermissionFragment();
FragmentManager fragmentManager = fragment.getChildFragmentManager();
fragmentTransaction(fragmentManager);
}
private void fragmentTransaction(FragmentManager fragmentManager) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(permissionFragment, PermissionFragment.class.getSimpleName());
fragmentTransaction.commit();
if (permissionFragment.isAdded()) {
Log.d(TAG, "已经被添加到Activity");
} else {
Log.d(TAG, "尚未添加到Activity");
}
}
/**
* 设置所需要申请的权限
*
* @param permission 需要申请的权限
* @return 返回一个RequestPermissionsResult实例用于进行后续操作
*/
public RequestPermissionsResult need(String permission) {
return need(new String[]{permission});
}
/**
* 设置所需要申请的权限
*
* @param permissions 需要申请的权限数组
* @return 返回一个RequestPermissionsResult实例用于进行后续操作
*/
public RequestPermissionsResult need(String[] permissions) {
return new RequestPermissionsResult(activity, permissions, permissionFragment);
}
static class RequestPermissionsResult implements Callback {
private Activity activity;
private String[] permissions;
private PermissionFragment permissionFragment;
private Subscribe subscribe;
private boolean showDialog = true;
RequestPermissionsResult(Activity activity, String[] permissions, PermissionFragment permissionFragment) {
this.activity = activity;
this.permissions = permissions;
this.permissionFragment = permissionFragment;
}
/**
* 设置当权限被拒绝的时候是否弹窗提示用户
*
* @param showDialog 为true则弹窗反之不弹窗 默认为true
* @return 返回RequestPermissionsResult
*/
public RequestPermissionsResult showDialog(boolean showDialog) {
this.showDialog = showDialog;
return this;
}
private boolean requestPermissions(String[] permissions, int requestCode) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(activity, permission)
== PackageManager.PERMISSION_DENIED) {
//注册回调
permissionFragment.registerCallback(requestCode, this);
permissionFragment.postRequestPermissions(permissions, requestCode);
return false;
}
}
return true;
}
/**
* 开始请求权限
*
* @param requestCode 请求号
*/
public void request(int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!requestPermissions(permissions, requestCode)) {
return;
}
}
//通知权限监听回调
publish(requestCode, true, permissions);
}
private void publish(int requestCode, boolean allGranted, String[] permissions) {
if (subscribe != null)
subscribe.onResult(requestCode, allGranted, permissions);
}
/**
* 设置订阅回调
*
* @param subscribe 权限被允许或者拒绝的时候会回调此实例
* 实例必须实现Subscribe方法
* @return 返回RequestPermissionsResult实例
*/
public RequestPermissionsResult subscribe(Subscribe subscribe) {
this.subscribe = subscribe;
return this;
}
/**
* 提供权限的回调接口 此方法为内部接口 用户不应该调用此方法
*
* @param requestCode 请求号
* @param permissions 权限
* @param grantResults 授权结果
*/
@Override
public void onRequestPermissionsCallback(final int requestCode, final String[] permissions, final int[] grantResults) {
//保证运行在主线程
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
onRequestPermissionsResult(requestCode, permissions, grantResults);
}
});
}
private void onRequestPermissionsResult(final int requestCode, @NotNull final String[] permissions, @NotNull final int[] grantResults) {
int i = 0;
for (int grant : grantResults) {
String permission = permissions[i];
if (grant == PackageManager.PERMISSION_DENIED) {
if (showDialog) {
showDialogTips(permission, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
publish(requestCode, false, permissions);
}
});
} else {
publish(requestCode, false, permissions);
}
return;
}
}
publish(requestCode, true, permissions);
}
private void showDialogTips(String permission, DialogInterface.OnClickListener onDenied) {
PackageManager packageManager = activity.getPackageManager();
String permissionName;
try {
PermissionInfo permissionInfo = packageManager.getPermissionInfo(permission, 0);
assert permissionInfo.group != null;
PermissionGroupInfo permissionGroupInfo =
packageManager.getPermissionGroupInfo(permissionInfo.group, 0);
permissionName = (String) permissionGroupInfo.loadLabel(packageManager);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
permissionName = "";
}
AlertDialog alertDialog = new AlertDialog.Builder(activity).setTitle("权限被禁用").setMessage(
String.format("您拒绝了相关权限,无法正常使用本功能。请前往 设置->应用管理->%s->权限管理中启用 %s 权限",
activity.getString(R.string.app_name),
permissionName
)).setCancelable(false).
setNegativeButton("返回", onDenied).
setPositiveButton("去设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent manageAppIntent = new Intent();
manageAppIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
//第二个参数为包名
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
manageAppIntent.setData(uri);
activity.startActivity(manageAppIntent);
}
}).create();
alertDialog.show();
}
}
}