AspectJX打造权限申请框架

AspectJ打造权限申请框架


前言


一、AOP是什么?

  • OOP是面向对象。
  • AOPAspect Orented Programming的缩写,翻译为:面向切面编程,通过预编译方式和运行期间动态代码来实现程序功能的统一维护的技术。

假如我们现在有这样一个需求,我们需要对50个方法分别进行代码执行时间统计,在面向对象的思想里我们肯定是会写入如下的代码

fun1(){
long startTime = System.currentTimeMills();
...
long endTime = System.currentTimeMills();
Log.d("function cost time",endTime - startTime);
}
fun2(){
long startTime = System.currentTimeMills();
...
long endTime = System.currentTimeMills();
Log.d("function cost time",endTime - startTime);
}
fun3(){
long startTime = System.currentTimeMills();
...
long endTime = System.currentTimeMills();
Log.d("function cost time",endTime - startTime);
}
...

有没有发现我们在这几个方法里加了三行相同的代码,是不是感觉到优点重复,还有比较累人 ,而且我们虽然实现了我们想做的事情,但是并不优雅,添加/修改原有的代码其实并不好,所以面向对象并不适合,我们就要通过面向切面的方式。

@ExecetuTime
fun1(){
...
}
@ExecetuTime
fun2(){
...
}
@ExecetuTime
fun3(){
...
}
...

看上面的代码是不是优雅很多了,是利用AspectJx实现的(面向切面的框架,封装了AspectJ)重复的代码也不见了。我们并不需要自己实现面向切面,避免重复造轮子,有能力的小伙伴也可以自行研究,欢迎讨论。

AOP应用场景:

  1. 权限申请
  2. 日志统计
  3. 行为统计
  4. 性能检测

再来看一张图,这张图可以看出两种不同方式的编译流程,一个是用javac来编译,一个是AJC来编译,所以AsepctJ的AJC编译器帮我们做了许多事,实现了切面。
在这里插入图片描述

二、AspectJX实现权限申请框架

1.基本概念

AspectJ在程序的编译过程中通过它特有的AJC编译器将字节码文件中插入我们自己定义的切面代码。

  • Pointcut(切入点)
    告诉AspectJ你要在原有的业务逻辑的某一块插入自己的代码,插入的那个地方就叫切入点。标识。
  • Advice(通知)
    这个是你切入点插入的代码的具体逻辑实现的地方,典型的类型有before,after和around。
Advice类型解释
before在目标方法前执行这个代码
after在目标方法后执行这个代码
around替换目标方法执行的代码
  • Joint point(连接点)
    程序中可能作为代码注入目标的点。拿到了方法。

这里我用的是AspectJX,因为原生的AspectJ我不太喜欢,比较烦人。

2.引入AspcetJX

项目的Build.gradle

//aspectjtools插件
        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'

moudle的Build.gradle

apply plugin: 'com.hujiang.android-aspectjx'
implementation 'org.aspectj:aspectjrt:1.8.+'

如果是是作为lib方式引入的化,记得在app模块下也加入

apply plugin: 'com.hujiang.android-aspectjx'
implementation 'org.aspectj:aspectjrt:1.8.+'

3.项目结构

这里我把这个封装了一下,把它作为lib的方式,这样以后的项目直接移过去就好了。
在这里插入图片描述

类名作用
PermissionActivity权限申请的activity(透明的,用户看不见)
RequestCallBackListener权限申请回调接口
PermissionUtils权限申请工具类
Permissionaop切入点
PermissionAspectaop通知
PermissionDenied权限被拒绝并不再提示的方法
PermissionFailed权限被拒绝的方法

这里就介绍一个核心类PermissionAspect

//这个标注 意味着这个类由AJC编译器来编译
@Aspect
public class PermissionAspect {
    // Permission 修饰的 任何返回值类型 任何方法名字 任何参数
    //这里有一些通配符语法,不知道的小伙伴可以问一下度娘
    @Pointcut("execution(@com.suyong.permissionslibrary.annotations.Permission * *(..)) && @annotation(permission)")
    public void requestPermission(Permission permission) {
    }

    @Around("requestPermission(permission)")
    public void getPermission(final ProceedingJoinPoint proceedingJoinPoint, Permission permission) {
        Log.d("-------", "执行了权限请求");
        Context context = null;
        final Object aThis = proceedingJoinPoint.getThis();
        if (aThis instanceof Context) {
            context = (Context) aThis;
        } else if (aThis instanceof Fragment) {
            context = ((Fragment) aThis).getActivity();
        }
        if (context == null || permission.requestPermissionList() == null || permission.requestPermissionList().length == 0) {
            return;
        }

        String[] permissions = permission.requestPermissionList();
        int requestCode = permission.requestCode();
        //启动隐藏的activity进行权限申请
        PermissionActivity.start(context, permissions, requestCode, new RequestCallBackListener() {
            @Override
            public void permissionSuccess() {
                //执行原来的代码逻辑
                try {
                    proceedingJoinPoint.proceed();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }

            @Override
            public void permissionCanceled() {
            //利用防反射的方式运行PermissionFailed所标注的方法
                PermissionUtils.invokeAnnotation(aThis, PermissionFailed.class);
            }

            @Override
            public void permissionDenied() {
            //利用防反射的方式运行PermissionDenied所标注的方法
                PermissionUtils.invokeAnnotation(aThis, PermissionDenied.class);
            }
        });
    }
}

我们在项目里优雅的使用例子:

@Permission(requestPermissionList = Manifest.permission.READ_EXTERNAL_STORAGE, requestCode = REQUEST_CODE)
    public void queryPhoto(View view) {
        Toast.makeText(this, "权限申请成功", Toast.LENGTH_SHORT).show();
    }

    @PermissionDenied(requestCode = REQUEST_CODE)
    private void requestPermissionDenied() {
        Toast.makeText(this, "权限申请失败,不在询问", Toast.LENGTH_SHORT).show();
    }

    @PermissionFailed(requestCode = REQUEST_CODE)
    private void requestPermissionFailed() {
        Toast.makeText(this, "用户拒绝了权限", Toast.LENGTH_SHORT).show();
    }

具体的代码大家可以去下载 项目链接


结果展示

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值