Framework学习(五):PKMS 学习之权限申请框架
PKMS 学习 之 权限申请框架
AspectJ 实现的权限申请框架
AOP是一个老生常谈的话题,全称"Aspect Oriented Programming",表示面向切面编程。由于面向对象的编程思想推崇高内聚、低耦合的架构风格,使得模块间代码的可见性变差,这使得实现下面的需求变得十分复杂:统计埋点、日志输出、权限拦截等等,如果手动编码,代码侵入性太高且不利于扩展,AOP技术应运而生。
通常来说,AOP都是为一些相对基础且固定的需求服务,实际常见的场景大致包括:
- 统计埋点
- 日志打印/打点
- 数据校验
- 行为拦截
- 性能监控
- 动态权限控制
本demo就是基于AOP实现的动态权限申请框架,实现原理为Android平台,通过Gradle Transform,在class文件生成后至dex文件生成前,遍历并匹配所有符合AspectJ文件中声明的切点,然后将事先声明好的代码在切点前后织入,会增加一定的编译时长,但几乎不会影响程序的运行时效率。
1.0 环境配置
在Android平台,我们通常使用上文提到的Aspectjx插件来配置AspectJ环境,具体使用是通过AspectJ注解完成。
- 在项目根目录的build.gradle里依赖AspectJX
dependencies { classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4' }
- 在需要支持AspectJ的module的build.gradle文件中声明插件。
apply plugin: 'android-aspectjx'
在编译阶段AspectJ会遍历工程中所有class文件(包括第三方类库的class)寻找符合条件的切入点,为加快这个过程或缩小代码织入范围,我们可以使用exclude排除掉指定包名的class。
# app/build.gradle aspectjx { //排除所有package路径中包含`android.support`的class文件及库(jar文件) exclude 'android.support' }
在debug阶段我们更注重编译速度,可以关闭代码织入。
# app/build.gradle aspectjx { //关闭AspectJX功能 enabled false }
2.0 传统方式申请权限
耦合度太高
// 传统方式申请权限的方式, 耦合度太高 public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 999; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 申请 危险权限 requestPermission(); } // 第二步:封装了一个requestPermission方法来动态检查和申请权限 private void requestPermission() { Log.i(TAG,"requestPermission"); // 注意:先检查之前有没有申请过这个READ_CONTACTS权限,如果么有申请过,才申请 // Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { Log.i(TAG,"checkSelfPermission"); // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) { Log.i(TAG,"shouldShowRequestPermissionRationale 原来你个货,之前拒绝过申请权限"); // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. // 申请 联系人读取权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); } else { Log.i(TAG,"requestPermissions 之前没有拒绝过,正常的申请权限"); // No explanation needed, we can request the permission. // 申请 联系人读取权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } } } // 第三步:重写onRequestPermissionsResult方法根据用户的不同选择做出响应。 @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.i(TAG,"onRequestPermissionsResult granted"); // permission was granted, yay! Do the // contacts-related task you need to do. } else { Log.i(TAG,"onRequestPermissionsResult denied"); // permission denied, boo! Disable the // functionality that depends on this permission. showWaringDialog(); } return; } // other 'case' lines to check for other // permissions this app might request } } // 如果点击 拒绝,就会弹出这个 提示框 private void showWaringDialog() { new AlertDialog.Builder(this) .setTitle("警告!") .setMessage("请前往设置->应用->PermissionDemo->权限中打开相关权限,否则功能无法正常运行!") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 一般情况下如果用户不授权的话,功能是无法运行的,做退出处理 finish(); } }).show(); } }
3.0 权限申请框架的方式
使用 权限申请框架 申请权限的方式, 只需要注解姐可以完成权限申请, 打打简化了开发的工作 , 但是苦逼的就是架构师了
要写权限申请库?
权限申请这一件事情,应该独立处理,隔离出来。不要让Activity或Fragment有着高耦合度。
使用者:
只需要关心,用一个注解,把具体权限传递到注解中就OK了,其他什么都不需要管
package com.example.myapplication; /** 要写权限申请库? 权限申请这一件事情,应该独立处理,隔离出来。 不要让Activity或Fragment有着高耦合度。 使用者: 只需要关心,用一个注解,把具体权限传递到注解中就OK了,其他什么都不需要管 */ /** * TODO 用户的角度上 use 我们写的权限申请库 */ public class PermissionFrameActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void test(View view) {} // 点击事件 public void permissionRequestTest(View view) { testRequest(); } // 申请权限 函数名可以随意些 @Permission(value = Manifest.permission.READ_EXTERNAL_STORAGE, requestCode = 200) public void testRequest() { Toast.makeText(this, "权限申请成功...", Toast.LENGTH_SHORT).show(); // 100 行 } // 权限被取消 函数名可以随意些 @PermissionCancel public void testCancel() { Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show(); } // 多次拒绝,还勾选了“不再提示” @PermissionDenied public void testDenied() { Toast.makeText(this, "权限被拒绝(用户勾选了 不再提示),注意:你必须要去设置中打开此权限,否则功能无法使用", Toast.LENGTH_SHORT).show(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!