[Android开发]推荐一个专属Android 端 AOP 切面框架,没有AspectJ

AndroidAOP 是专属于 Android 端 Aop 框架,没有使用 AspectJ,也可以定制出属于你的 Aop 代码,心动不如行动,赶紧用起来吧

AndroidAOP - Github链接

特色功能

1、本库内置了开发中常用的一些切面注解供你使用

2、本库支持让你自己做切面,语法简单易上手

3、同时本库支持 Java 和 Kotlin 代码

4、本库没有使用 AspectJ,织入代码量极少,侵入性极低

使用步骤

一、在项目根目录下的build.gradle添加(必须)

gradle 复制代码
buildscript {
    dependencies {
        classpath 'io.github.FlyJingFish.AndroidAop:android-aop-plugin:1.0.2'
    }
}

二、在 app 的build.gradle添加(此步为必须项)

⚠️注意:👆此步为必须项👇

gradle 复制代码
//必须项 👇
plugins {
    id 'android.aop'
}

三、引入依赖库

gradle 复制代码
dependencies {
    //必须项 👇
    implementation 'io.github.FlyJingFish.AndroidAop:android-aop-core:1.0.2'
    implementation 'io.github.FlyJingFish.AndroidAop:android-aop-annotation:1.0.2'
    //非必须项 👇,如果你想自定义切面需要用到 ⚠️如果是kotlin项目 也要用 annotationProcessor
    annotationProcessor 'io.github.FlyJingFish.AndroidAop:android-aop-processor:1.0.2'
}

本库内置了一些功能注解可供你直接使用

注解名称 参数说明 功能说明
@SingleClick value = 时间间隔 单击注解,加入此注解,可是你的方法只有单击时才可进入
@DoubleClick value = 时间间隔 双击注解,加入此注解,可是你的方法双击时才可进入
@IOThread ThreadType = 线程类型 切换到子线程的操作,加入此注解可使你的方法内的代码切换到子线程执行
@MainThread 无参数 切换到主线程的操作,加入此注解可使你的方法内的代码切换到主线程执行
@OnLifecycle value = Lifecycle.Event 监听生命周期的操作,加入此注解可使你的方法内的代码在对应生命周期内才去执行
@TryCatch value = 你自定义加的一个flag 加入此注解可为您的方法包裹一层 try catch 代码
@Permission value = 权限的字符串数组 申请权限的操作,加入此注解可使您的代码在获取权限后才执行
@CustomIntercept value = 你自定义加的一个字符串数组的flag 自定义拦截,此注解可以加到方法上

这块强调一下 @OnLifecycle

@OnLifecycle 加到的位置必须是属于直接或间接继承自 FragmentActivity 或 Fragment的方法才有用(即这个方法是直接或间接继承FragmentActivity 或 Fragment的类的)

下面再着重介绍下 @TryCatch @Permission @CustomIntercept

  • @TryCatch 使用此注解你可以设置
java 复制代码
AndroidAop.INSTANCE.setOnThrowableListener(new OnThrowableListener() {
    @Nullable
    @Override
    public Object handleThrowable(@NonNull String flag, @Nullable Throwable throwable,TryCatch tryCatch) {
        // TODO: 2023/11/11 发生异常可根据你当时传入的flag作出相应处理,如果需要改写返回值,则在 return 处返回即可
        return 3;
    }
});
  • @Permission 使用此注解你可以设置
java 复制代码
AndroidAop.INSTANCE.setOnPermissionsInterceptListener(new OnPermissionsInterceptListener() {
    @SuppressLint("CheckResult")
    @Override
    public void requestPermission(@NonNull ProceedJoinPoint joinPoint, @NonNull Permission permission, @NonNull OnRequestPermissionListener call) {
        Object target =  joinPoint.getTarget();
        if (target instanceof FragmentActivity){
            RxPermissions rxPermissions = new RxPermissions((FragmentActivity) target);
            rxPermissions.request(permission.value()).subscribe(call::onCall);
        }else if (target instanceof Fragment){
            RxPermissions rxPermissions = new RxPermissions((Fragment) target);
            rxPermissions.request(permission.value()).subscribe(call::onCall);
        }
    }
});
  • @CustomIntercept 使用此注解你可以设置
java 复制代码
AndroidAop.INSTANCE.setOnCustomInterceptListener(new OnCustomInterceptListener() {
    @Nullable
    @Override
    public Object invoke(@NonNull ProceedJoinPoint joinPoint, @NonNull CustomIntercept customIntercept) {
        // TODO: 2023/11/11 在此写你的逻辑 在合适的地方调用 joinPoint.proceed(),
        //  joinPoint.proceed(args)可以修改方法传入的参数,如果需要改写返回值,则在 return 处返回即可

        return null;
    }
});

👆上边三个监听,最好放到你的 application 中

在这介绍下 在使用 ProceedJoinPoint 这个对象的 proceed() 或 proceed(args) 表示执行原来方法的逻辑,区别是:

  • proceed() 不传参,表示不改变当初的传入参数,
  • proceed(args) 有参数,表示改写当时传入的参数

在此的return 返回的就是对应拦截的那个方法返回的

不调用 proceed 就不会执行拦截切面方法内的代码,return什么也无所谓了

此外本库也同样支持让你自己做切面,语法相对来说也比较简单

本库中提供了 @AndroidAopPointCut 和 @AndroidAopMatchClassMethod 两种切面供你使用

  • @AndroidAopPointCut 是只能在方法上做切面的,上述中注解都是通过这个做的

下面以 @CustomIntercept 为例介绍下该如何使用(⚠️注意:自定义的注解,请使用Java代码来写,目前版本还未适配Kotlin,其他代码都可以用Kotlin)

java 复制代码
@AndroidAopPointCut(CustomInterceptCut.class)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomIntercept {
    String[] value() default {};
}

@AndroidAopPointCutCustomInterceptCut.class 为您处理切面的类

@Target 的 ElementType.METHOD 表示作用在方法上

@Retention 只可以用 RetentionPolicy.RUNTIME

@Target 只可以传 ElementType.METHOD传其他无作用

CustomInterceptCut 的代码如下:

kotlin 复制代码
class CustomInterceptCut : BasePointCut<CustomIntercept> {
    override fun invoke(
        joinPoint: ProceedJoinPoint,
        annotation: CustomIntercept
    ): Any? {
        // 在此写你的逻辑
        return joinPoint.proceed()
    }
}
  • @AndroidAopMatchClassMethod 是做匹配类和类方法的切面的
kotlin 复制代码
@AndroidAopMatchClassMethod(
    targetClassName = "com.flyjingfish.test_lib.BaseActivity",
    methodName = ["onCreate", "onResume", "onTest"]
)
class MatchActivityOnCreate : MatchClassMethod {
    override fun invoke(joinPoint: ProceedJoinPoint, methodName: String): Any? {
        Log.e("MatchActivityMethod", "=====invoke=====$methodName")
        return try {
            joinPoint.proceed()
        } catch (e: InvocationTargetException) {
            throw RuntimeException(e)
        } catch (e: IllegalAccessException) {
            throw RuntimeException(e)
        }
    }
}

上边表示凡是继承自 com.flyjingfish.test_lib.BaseActivity 的类执行 onCreate 和 onResume 方法时则进行切面

⚠️注意如果你没写对应的方法或者没有重写父类的该方法则切面无效

例如你想做退出登陆逻辑时可以使用这个

混淆规则

下边是涉及到本库的一些必须混淆规则

typescript 复制代码
# AndroidAop必备混淆规则 -----start-----


-keep @com.flyjingfish.android_aop_core.annotations.* class * {*;}
-keep @com.flyjingfish.android_aop_annotation.anno.* class * {*;}
-keep class * {
    @com.flyjingfish.android_aop_core.annotations.* <fields>;
    @com.flyjingfish.android_aop_annotation.anno.* <fields>;
}
-keepclassmembers class * {
    @com.flyjingfish.android_aop_core.annotations.* <methods>;
    @com.flyjingfish.android_aop_annotation.anno.* <methods>;
}

-keepnames class * implements com.flyjingfish.android_aop_annotation.BasePointCut
-keepnames class * implements com.flyjingfish.android_aop_annotation.MatchClassMethod
-keep class * implements com.flyjingfish.android_aop_annotation.BasePointCut{
    public <init>();
}
-keepclassmembers class * implements com.flyjingfish.android_aop_annotation.BasePointCut{
    <methods>;
}

-keep class * implements com.flyjingfish.android_aop_annotation.MatchClassMethod{
    public <init>();
}
-keepclassmembers class * implements com.flyjingfish.android_aop_annotation.MatchClassMethod{
    <methods>;
}

# AndroidAop必备混淆规则 -----end-----

如果你自己写了新的切面代码,记得加上你的混淆规则

如果你用到了 @AndroidAopPointCut 做切面,那你需要对你自己写的注解类做如下处理

下边的 com.flyjingfish.test_lib.annotation 就是你自定义的注解存放包名,你可以将你的注解类统一放到一个包下

kotlin 复制代码
# 你自定义的混淆规则 -----start-----
-keep @com.flyjingfish.test_lib.annotation.* class * {*;}
-keep class * {
    @com.flyjingfish.test_lib.annotation.* <fields>;
}
-keepclassmembers class * {
    @com.flyjingfish.test_lib.annotation.* <methods>;
}
# 你自定义的混淆规则 -----end-----

如果你用到了 @AndroidAopMatchClassMethod 做切面,那你需要为切面内的方法做混淆处理 下面是上文提到的 MatchActivityOnCreate 类的匹配规则,对应的逻辑是 匹配的 为继承自 com.flyjingfish.test_lib.BaseActivity 的类的 onCreate ,onResume,onTest三个方法加入切面

scala 复制代码
-keepnames class * extends com.flyjingfish.test_lib.BaseActivity{
    void onCreate(...);
    void onResume(...);
    void onTest(...);
}
相关推荐
轻口味3 小时前
Vue.js `v-memo` 性能优化技巧
前端·vue.js·性能优化
prince_zxill3 小时前
Array.prototype 方法在复杂数据处理中的应用
前端·javascript·原型模式
GISer_Jing3 小时前
React基础知识回顾详解
前端·react.js·前端框架
阿正的梦工坊4 小时前
深入解析 Chrome 浏览器的多进程架构:标签页是进程还是线程?(中英双语)
linux·服务器·前端·chrome·架构·unix
无限大.4 小时前
前端知识速记--CSS篇:display
前端·css
小松聊PHP进阶4 小时前
万字总结PHP与JavaScript、PHP与PHP 实现开箱即用的AES、RSA和较为安全的自定义加解密算法
前端·后端·php
滚雪球~4 小时前
el-button 中icon在文字前和在文字后的写法
前端
半世轮回半世寻5 小时前
Nuxt后端接口实战:从0到1连接MongoDB数据库
前端
小乌龟快跑5 小时前
React 设计实现一个支持动态插槽的Layout组件
前端·面试
打野赵怀真5 小时前
行内元素和块级元素有什么区别,如何相互转换?
前端·javascript