组件化: Android动态权限

权限组件设计背景

历史版本权限组件使用的是AndPermission,长期无人维护,历史代码臃肿,不便拓展,考虑使用PermissionsDispatcher,但是PermissionsDispatcher APT插件会影响编译效率,easypermissions侵入性太强,会影响整个工程,RxPermissions 貌似是最佳选择,但是RxPermissions需要高度自定义符合自己项目特色的UI,所以干脆自己写个权限组件好了,希望大家喜欢

权限组件设计需求

自定义炫酷权限弹框

不入侵工程Activity

权限注入符合自定义规则

权限组件设计原理

检查所提供的权限是否被申请

  1. 检查此设备上是否可能缺少权限
  2. 如果 Activity 或 Fragment 有权访问所有给定的权限,不处理
  3. 如果API在23以下,检测到了,你也没有主动的触发手段,就不处理,否则检测到了,否则弹窗
  4. 如果当前权限被拒绝了,那么触发了权限申请就进入setting页面
  5. 在构建DialogFragment 的 onRequestPermissionsResult 方法里面去做权限申请工作,申请完毕需要移除Fragment
  6. requestCode 回调 交给 DialogFragment 处理, DialogFragment 负责权限赋权工作

权限组件兼容问题

未全方面测试,出现的问题未能及时定位,希望各位朋友能帮忙定位

权限组件实现步骤

1. 将权限接口化管理
public interface oMKPermissionListener {

    /**
     * 权限申请回调
 *  * @param requestCode Activity 回调返回码  * @param permissions 权限列表  */  void onMKGranted(int requestCode, String[] permissions);   /**  * 权限拒绝回调  *  * @param requestCode Activity 回调返回码  * @param result 权限拒绝结果集  */  void onMKDenied(int requestCode, Map<String, Integer> result);    /**  * 权限不再询问回调  *  * @param requestCode Activity 回调返回码  * @param result 权限不再询问结果集  */  void onMKNeverAsk(int requestCode, Map<String, Integer> result);   } 
2. 检查所提供的权限是否被申请,如果 Activity 或 Fragment 有权访问所有给定的权限,则返回 true。
public class MkPermissionUtil {

 
    private static final SimpleArrayMap<String, Integer> MIN_SDK_PERMISSIONS;
    private static volatile int targetSdkVersion = -1;
  static {  MIN_SDK_PERMISSIONS = new SimpleArrayMap<>(8);  MIN_SDK_PERMISSIONS.put(permission.ADD_VOICEMAIL, VERSION_CODES.ICE_CREAM_SANDWICH);  MIN_SDK_PERMISSIONS.put(permission.BODY_SENSORS, VERSION_CODES.KITKAT_WATCH);  MIN_SDK_PERMISSIONS.put(permission.READ_CALL_LOG, VERSION_CODES.JELLY_BEAN);  MIN_SDK_PERMISSIONS.put(permission.READ_EXTERNAL_STORAGE, VERSION_CODES.JELLY_BEAN);  MIN_SDK_PERMISSIONS.put(permission.USE_SIP, VERSION_CODES.GINGERBREAD);  MIN_SDK_PERMISSIONS.put(permission.WRITE_CALL_LOG, VERSION_CODES.JELLY_BEAN);  MIN_SDK_PERMISSIONS.put(permission.SYSTEM_ALERT_WINDOW, VERSION_CODES.M);  MIN_SDK_PERMISSIONS.put(permission.WRITE_SETTINGS, VERSION_CODES.M);  }   public static void requestPermission(FragmentActivity activity,  int requestCode, OnMkPermissionListener listener, String... permission) {  if (activity == null) {  return;  }  if (checkPermissionsMarshmallow(activity, permission)) {  listener.onMkGranted(requestCode, permission);  return;  }  MkDialogFragment fragment = MkDialogFragment.newInstance();  fragment.requestAllPermissions(activity, requestCode, listener, permission);  }     private static boolean checkPermissionsMarshmallow(FragmentActivity activity,  String... permissions) {  return VERSION.SDK_INT < 23 || hasSelfPermissions(activity, permissions);  }     @Deprecated  @TargetApi(VERSION_CODES.KITKAT)  public static boolean checkPermissionKitkat(Context context, int op) {  if (context == null || context.getPackageName() == null) {  return false;  }  AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);  ApplicationInfo appInfo = context.getApplicationInfo();   if (appInfo == null || mAppOps == null) {  return false;  }  try {  Class sCheckClass = Class.forName(AppOpsManager.class.getName());  Method sCheckMethod = sCheckClass.getDeclaredMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);  sCheckMethod.setAccessible(true);  return ((Integer) sCheckMethod.invoke(mAppOps, op, appInfo.uid, context.getPackageName()) == AppOpsManager.MODE_ALLOWED);  } catch (Exception e) {  Log.e("checkPermissionKitkat", e.getMessage() + "");  }  return true;  }     public static boolean verifyPermissions(int... grantResults) {  if (grantResults.length == 0) {  return false;  }  for (int result : grantResults) {  if (result != PackageManager.PERMISSION_GRANTED) {  return false;  }  }  return true;  }    private static boolean permissionExists(String permission) {  // 检查此设备上是否可能缺少权限  Integer minVersion = MIN_SDK_PERMISSIONS.get(permission);  // 如果从上述调用返回 null,则无需检查设备 API 级别的权限;  // 否则,我们检查其最低 API 级别要求是否得到满足  return minVersion == null || VERSION.SDK_INT >= minVersion;  }    public static boolean hasSelfPermissions(Context context, String... permissions) {  for (String permission : permissions) {  if (permissionExists(permission) && !hasSelfPermission(context, permission)) {  return false;  }  }  return true;  }    @SuppressLint("WrongConstant")  private static boolean hasSelfPermission(Context context, String permission) {  try {  return PermissionChecker.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;  } catch (RuntimeException t) {  return false;  }  }    public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) {  for (String permission : permissions) {  if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {  return true;  }  }  return false;  }    public static int getTargetSdkVersion(Context context) {  if (targetSdkVersion != -1) {  return targetSdkVersion;  }  try {  PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);  targetSdkVersion = packageInfo.applicationInfo.targetSdkVersion;  } catch (PackageManager.NameNotFoundException ignored) {  Log.e("getTargetSdkVersion", ignored.getMessage() + "");  }  return targetSdkVersion;  }   public static void runOnUiThread(final Runnable runnable) {  if (Looper.myLooper() == Looper.getMainLooper()) {  runnable.run();  } else {  new Handler(Looper.getMainLooper()).post(runnable);  }  }    private static boolean isIntentAvailable(Context context, final Intent intent) {  return context.getPackageManager()  .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)  .size() > 0;  }    public static void launchAppDetailsSettings(Context context) {  Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  intent.setData(Uri.parse("package:" + context.getPackageName()));  if (!isIntentAvailable(context, intent)) {  return;  }  context.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));  }  } 
3. 自定义权限申请Dialog
public class MkToGoSettingDialog extends AlertDialog {


    protected MkToGoSettingDialog(@NonNull Context context) {
        super(context, R.style.permission_dialog_style);
 }   @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  initDialogStyle();  View rootView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_mk_permission_layout, null);  setContentView(rootView);  initView(rootView);  }   private void initDialogStyle() {   Window window = getWindow();  if (window != null) {  window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);  window.setFeatureDrawableAlpha(Window.FEATURE_OPTIONS_PANEL, 0);  WindowManager.LayoutParams params = window.getAttributes();  // 设置宽度为全屏  params.width = ViewGroup.LayoutParams.WRAP_CONTENT;  params.height = ViewGroup.LayoutParams.WRAP_CONTENT;  window.setGravity(Gravity.CENTER);  window.setAttributes(params);  setCancelable(true);  setCanceledOnTouchOutside(true);  // 设置窗口弹出动画  window.setWindowAnimations(R.style.mk_bottom_inout_animation);  }  }   private void initView(View rootView) {  Button btnCancel = rootView.findViewById(R.id.btn_cancel);  Button btnSure = rootView.findViewById(R.id.btn_sure);  btnCancel.setText(R.string.permission_sanity_dialog_cancel);  btnSure.setText(R.string.permission_sanity_dialog_open);  TextView titleTextContent = rootView.findViewById(R.id.title_text_content);  TextView titleTextNotice = rootView.findViewById(R.id.title_text_notice);  titleTextNotice.setText(R.string.permission_sanity_dialog_title);  titleTextContent.setText(R.string.permission_sanity_dialog_description);  btnCancel.setOnClickListener(view -> dismiss());  btnSure.setOnClickListener(view -> {  MkPermissionUtil.launchAppDetailsSettings(getContext());  dismiss();  });  }   } 
4. 权限申请帮助类
public class MkPermissionHelper {


    public static void requestPermission(Activity context, OnMkPermissionListener permissionListener, String... permissions) {

 MkPermissionUtil.requestPermission((FragmentActivity) context, 0, new OnMkPermissionListener() {  @Override  public void onMkGranted(int requestCode, String... permissions) {  permissionListener.onMkGranted(requestCode, permissions);  }   @Override  public void onMkDenied(int requestCode, Map<String, Integer> result) {  permissionListener.oMkDenied(requestCode, result);   }   @Override  public void onMkNeverAsk(int requestCode, Map<String, Integer> result) {  MkToGoSettingDialog mkPermissionDialog = new MkToGoSettingDialog(context);  mkPermissionDialog.show();  permissionListener.onMkNeverAsk(requestCode, result);   }  }, permissions);   } } 

改不完的 Bug,写不完的矫情。公众号现在专注移动前端领域。涵盖APM, 音视频等各个知识领域;
只做全网最Geek的公众号,欢迎你的关注!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值