权限申请方式:
- 原生申请
- androidx 中的协定类
- 注解与反射的使用
- 常用的第三方框架
- 动态代理(待更新)
- 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. 反射进行权限申请
这边查看文章:
对内容做了简化 文章中思路获取权限,判断权限是否授权,没有就去申请,然后通过反射返回结果 也就是说文档中只是最后结果进行了权限反射,在业务类中确实起到了解耦的作用 具体实现类如下:
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…
权限请求反射方案:blog.csdn.net/qq_26629729…