Android 权限申请

316 阅读4分钟

权限申请方式:

  1. 原生申请
  2. androidx 中的协定类
  3. 注解与反射的使用
  4. 常用的第三方框架
  5. 动态代理(待更新)
  6. AOP切面注入(待更新)

1. 原生申请

检核是否有权限

if (checkSelfPermission(permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
    //执行操作
    callPhone()
} else {
    //这边直接申请,但谷歌建议申请前,先界面告知用处
    requestPermissions(arrayOf(permission.CALL_PHONE), REQUEST_CALL_PHONE)
}

申请权限返回

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
        REQUEST_CALL_PHONE -> {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //同意权限
                callPhone()
            } else {
                if (shouldShowRequestPermissionRationale(permission.CALL_PHONE)) {
                //本次不同意,告知用户为什么使用
                    "需要开启".showToast()
                } else {
                //禁止不再提醒,说明原因,然后提供跳转到设置界面的功能
                    "跳转".showToast()
                }
            }
        }
    }
}

优缺点: 1.请求与回调分离,多了很多跟业务无关的代码

2. androidx协定类

权限检核不变

if (checkSelfPermission(permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
    //执行操作
    callPhone()
} else {
    //这边直接申请,但谷歌建议申请前,先界面告知用处
    requestCallPhone.launch(permission.CALL_PHONE)
}

权限申请

private val requestCallPhone = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
    if (isGranted) {
        //同意
        callPhone()
    } else {
        // 不同意
        if (shouldShowRequestPermissionRationale(permission.CALL_PHONE)) {
            "需要开启".showToast()
        } else {
            "跳转".showToast()
        }
    }
}

通过kotlin的高阶函数,也可以再基类进行优化

//基类方法
private fun requestPermission(method: () -> Unit): ActivityResultLauncher<String> {
    return registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        if (isGranted) {
            //同意
            method
        } else {
            // 不同意
            if (shouldShowRequestPermissionRationale(permission.CALL_PHONE)) {
                "需要开启".showToast()
            } else {
                "跳转".showToast()
            }
        }
    }
}

//实现类
private val requestCallPhone = requestPermission { callPhone() }

优点: 不需要区分返回,简化了原生

缺点: 请求与回调分离,依旧存在无关代码

3. 反射进行权限申请

这边查看文章:

blog.csdn.net/qq_26629729…

对内容做了简化 文章中思路获取权限,判断权限是否授权,没有就去申请,然后通过反射返回结果 也就是说文档中只是最后结果进行了权限反射,在业务类中确实起到了解耦的作用 具体实现类如下:

class MainActivity : AppCompatActivity() {
    companion object {
        private const val REQUEST_CALL_PHONE: Int = 1;
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn.setOnClickListener {
            PermissionHelper.with(this).requestCode(REQUEST_CALL_PHONE).requestPermission(permission.CALL_PHONE)
                .request();
        }
    }


    @PermissionSuccess(requestCode = REQUEST_CALL_PHONE)
    private fun callPhone() {
        val intent = Intent().apply {
            action = Intent.ACTION_CALL
            data = Uri.parse("tel:10086")
            startActivity(this)
        }
    }

    @PermissionFail(requestCode = REQUEST_CALL_PHONE)
    private fun callFail() {
        "请求失败".showToast()
    }


    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        PermissionHelper.requestPermissionsResult(this, requestCode, permissions);
    }
}

权限请求帮助类

/**
 * Created by XZ on 2022/8/4 10:31
 */
public class PermissionHelper {
    private Context context;
    private int code;
    private String[] mRequestPermission;


    public void request() {
        List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(context, mRequestPermission);
        if (deniedPermissions.size() == 0) {
            //直接授权通过
            PermissionUtils.executeSucceedMethod(context, code);
        } else {
            //没授权通过
            ActivityCompat.requestPermissions((Activity) context, mRequestPermission, code);
        }
    }

    /**
     * 权限请求返回,需要在类中调用
     * @param object
     * @param requestCode
     * @param permission
     */
    public static void requestPermissionsResult(Object object, int requestCode, String[] permission) {
        List<String> deniedPermissions = PermissionUtils.getDeniedPermissions(object, permission);
        if (deniedPermissions.size() == 0) {
            // 权限用户都同意授予了
            PermissionUtils.executeSucceedMethod(object, requestCode);
        } else {
            // 你申请的权限中 有用户不同意的
            PermissionUtils.executeFailMethod(object, requestCode);
        }
    }

    private PermissionHelper(Context object) {
        this.context = object;
    }

    public static PermissionHelper with(Activity activity) {
        return new PermissionHelper(activity);
    }

    public PermissionHelper requestCode(int requestCode) {
        this.code = requestCode;
        return this;
    }

    public PermissionHelper requestPermission(String... mRequestPermission) {
        this.mRequestPermission = mRequestPermission;
        return this;
    }

权限请求结果反射类

public class PermissionUtils {
    /**
     * 执行成功的方法
     */
    public static void executeSucceedMethod(Object object, int requestCode) {
        Class<?> aClass = object.getClass();
        // 获取class中多有的方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
        // 遍历找到我们打了注解的方法
        for (Method method : declaredMethods) {
            //判断方法上是否打了PermissionSucceed注解
            if (method.isAnnotationPresent(PermissionSuccess.class)) {
                //获取该注解的一些类,并获取注解里面的值
                PermissionSuccess annotation = method.getAnnotation(PermissionSuccess.class);
                int i = annotation.requestCode();
                if (i == requestCode) {
                    //设置方法的一个访问权限
                    method.setAccessible(true);
                    try {
                        //反射执行该方法
                        method.invoke(object, null);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    //执行失败的方法
    public static void executeFailMethod(Object object, int requestCode) {
        Class<?> aClass = object.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (method.isAnnotationPresent(PermissionFail.class)) {
                PermissionFail annotation = method.getAnnotation(PermissionFail.class);
                int i = annotation.requestCode();
                if (i == requestCode) {
                    method.setAccessible(true);
                    try {
                        method.invoke(object, null);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }

    // 获取没有授予过得权限
    @SuppressLint("NewApi")
    public static List<String> getDeniedPermissions(Object object, String... permission) {
        List<String> deniedPermission = new LinkedList<String>();
        for (String list : permission) {
            if (object instanceof Activity) {
                if (((Activity) object).checkSelfPermission(list) != PackageManager.PERMISSION_GRANTED) {
                    deniedPermission.add(list);
                }
            } else {
                if (((Fragment) object).getActivity().checkSelfPermission(list) != PackageManager.PERMISSION_GRANTED) {
                    deniedPermission.add(list);
                }
            }
        }
        return deniedPermission;
    }
}

4. 第三方请求框架

此处选择 permissions-dispatcher 链接 github.com/hotchemi/Pe… 通过注解,与代码生成,无反射,github 11k 实现效果


@RuntimePermissions
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn.setOnClickListener {
            callPhoneWithPermissionCheck()
        }
    }

    @NeedsPermission(permission.CALL_PHONE)
    fun callPhone() {
        val intent = Intent().apply {
            action = Intent.ACTION_CALL
            data = Uri.parse("tel:10086")
            startActivity(this)
        }
    }

    @OnShowRationale(permission.CALL_PHONE)
    fun showRationaleDialog() {
        "展示为什么要权限".showToast()
    }

    @OnPermissionDenied(permission.CALL_PHONE)
    fun onCallPhoneDenied() {
        "拒绝了权限".showToast()
    }

    @OnNeverAskAgain(permission.CALL_PHONE)
    fun onCallNever() {
        "不再申请权限是不好的".showToast()
    }


    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        onRequestPermissionsResult(requestCode, grantResults)
    }
}

而代码生成类


private const val REQUEST_CALLPHONE: Int = 0

private val PERMISSION_CALLPHONE: Array<String> = arrayOf("android.permission.CALL_PHONE")

fun MainActivity.callPhoneWithPermissionCheck() {
  if (PermissionUtils.hasSelfPermissions(this, *PERMISSION_CALLPHONE)) {
    callPhone()
  } else {
    if (PermissionUtils.shouldShowRequestPermissionRationale(this, *PERMISSION_CALLPHONE)) {
      showRationaleDialog()
    } else {
      ActivityCompat.requestPermissions(this, PERMISSION_CALLPHONE, REQUEST_CALLPHONE)
    }
  }
}

fun MainActivity.proceedCallPhonePermissionRequest() {
  ActivityCompat.requestPermissions(this, PERMISSION_CALLPHONE, REQUEST_CALLPHONE)
}

fun MainActivity.cancelCallPhonePermissionRequest() {
  this.onCallPhoneDenied()
}

fun MainActivity.onRequestPermissionsResult(requestCode: Int, grantResults: IntArray) {
  when (requestCode) {
    REQUEST_CALLPHONE ->
     {
      if (PermissionUtils.verifyPermissions(*grantResults)) {
        callPhone()
      } else {
        if (!PermissionUtils.shouldShowRequestPermissionRationale(this, *PERMISSION_CALLPHONE)) {
          onCallNever()
        } else {
          onCallPhoneDenied()
        }
      }
    }
  }
}

private class MainActivityCallPhonePermissionRequest(target: MainActivity) : PermissionRequest {
  private val weakTarget: WeakReference<MainActivity> = WeakReference(target)

  override fun proceed() {
    val target = weakTarget.get() ?: return
    ActivityCompat.requestPermissions(target, PERMISSION_CALLPHONE, REQUEST_CALLPHONE)
  }

  override fun cancel() {
    val target = weakTarget.get() ?: return
    target.onCallPhoneDenied()
  }
}

通过扩展函数生成代码,简洁优雅

文章参考目录: 官方网址:developer.android.google.cn/training/pe…

申请总结:juejin.cn/post/686159…

权限请求反射方案:blog.csdn.net/qq_26629729…