AspectJXAndroid 中快速集成使用一款 AOP 框架并附加数据埋点解决方案实现

Posted 邹奇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AspectJXAndroid 中快速集成使用一款 AOP 框架并附加数据埋点解决方案实现相关的知识,希望对你有一定的参考价值。

文章目录

背景


主要是记录学习 AOP 编程思想。项目中数据埋点统一方案有使用到,也是一次加深学习理解的过程。

什么是 AOP


AOPAspect-Oriented Programming 缩写,即面向切面编程。提倡针对同一类问题的统一处理方法。

AOP 这种编程思想有哪些作用呢?一般来说,主要用于不想侵入原有代码的场景中,例如SDK 需要无侵入的在宿主中插入一些代码,做日志埋点、性能监控、动态权限控制、甚至是代码调试等。

AspectJX


一个基于 AspectJ 并在此基础上扩展出来可应用于 android 开发平台的 AOP 框架,可作用于java 源码,class 文件及 jar 包,同时支持 kotlin 的应用。

  • 目前 AspectJX 仅支持 annotation 的方式

【 Github AspectJX 】点击了解更多

问:编译时会出现 can’t determine superclass of missing type** 及其他编译错误怎么办?

答:大部分情况下把出现问题相关的 class 文件或者库(jar 文件)过滤掉就可以搞定了

集成使用

具体配置


  • 在项目根目录的 build.gradle 里依赖 AspectJX。如下:
dependencies 

        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    
  • 在项目中 app 模块的 build.gradle 里应用插件。如下:
apply plugin: 'android-aspectjx'
  • AspectJX配置

AspectJX 默认会处理所有的二进制代码文件和库,为了提升编译效率及规避部分第三方库出现的编译兼容性问题,AspectJX 提供 include, exclude 命令来过滤需要处理的文件及排除某些文件(包括 class 文件及 jar 文件)。

配置在对应模块的 gradle 文件下,如下:

android
	aspectjx
		// 配置规则
	

示例配置如下:

aspectjx 
//排除所有package路径中包含`android.support`的class文件及库(jar文件)
	exclude 'android.support'

aspectjx 
//忽略所有的class文件及jar文件,相当于AspectJX不生效
	exclude '*'

更多详细规则使用自行查阅 Github AspectJX 框架相关知识了解。

  • 模块的 gradle 中添加 dependencies 依赖。如下:
dependencies 
	implementation 'org.aspectj:aspectjrt:1.9.5'

  • 配置编译选项支持 java 8
android
	compileOptions 
        targetCompatibility 1.8
        sourceCompatibility 1.8
    

这样可以保证编译时不会报错异常,建议加上。到这里就完成了所有的配置,然后就可以愉快的 coding

Demo 中使用


  • MainActivity.java 中新增一个方法 void doAspectJX(String s),并在 onCreate 中调用,保证程序运行时能执行到这个方法。如下:
@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        doAspectJX("");
    

    private void doAspectJX(String s)

    
  • 创建一个 MyAspectJX.java 自定义类,然后在合适的时机切入。如下:
@Aspect
public class MyAspectJX 

    @After("execution(* *..MainActivity.doAspectJX*(..))")
    public void test(JoinPoint point)
        try 
        
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            String methodName = methodSignature.getName();
            System.out.println(":> methodName: " + methodName);

        catch (Exception e)
            e.printStackTrace();
        
    

几点说明:

  • 切入类需要使用 @Aspect 注解进行标识
  • 根据自定义的切入规则,在程序运行过程中,满足规则时进行切入

示例中规则为:@After("execution(* *..MainActivity.doAspectJX*(..))")

表示:当程序执行完 MainActivity 类中的 doAspectJX() 这个方法之后进行切入。

更多规则同学们自行学习使用。

  • 切入验证

我们切入后,打印切入的方法名称。运行程序后打印结果如下:


上图所示,说明成功切入了,打印方法名称 doAspectJX

到这里就完成了从集成到简单应用的一个整体流程。

拓展实现:数据埋点解决方案

准备工作


上面也谈到了 AOP 编程思想可用于埋点功能的实现,下面我们一起实现一下。

  • 首先新建一个接口,命名为 Behavior.java 。如下:
public interface Behavior 

    Map<String, Object> params();


这个接口,可以供需要埋点的类实现,然后通过实现 param() 方法,把需要埋点的参数和值保存到 map 中返回即可。

  • 自定义 DataPoint.java 注解。如下:
/**
 * 自定义 DataPoint 注解
 * 切入规则使用:仅标记方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPoint 

使用注解来标记方法,可以很方便的指定切入规则,在合适时机进行切入获取数据,然后就可以愉快的上报数据了。

完整代码实现


  • MainActivity.java 代码如下:
// 实现 Behavior 接口
public class MainActivity extends AppCompatActivity implements Behavior

    Map<String, Object> map = new HashMap<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        doAspectJX("");
    

    @DataPoint
    private void doAspectJX(String s)
        System.out.println(":> doAspectJX 执行");
        map.put("name", "imxiaoqi");
    

    @Override
    public Map<String, Object> params() 
        return map;
    

  • 切入类 MyAspectJX.java 代码如下:
@Aspect
public class MyAspectJX 

//    @After("execution(* *..MainActivity+.on*(..))")
//    @After("execution(* *..*.doAspectJX(..))")
    @After("execution(@DataPoint * *..*.*(..))")
    public void test(JoinPoint point)
        try 

            // 获取被切入的类对象
            // 示例中 MainActivity 实现了 Behavior 接口,故可以类型强转为 Behavior
            Behavior behavior = (Behavior) point.getThis();
            // 获取数据,存于 Map 中
            Map<String, Object> map = behavior.params();
            System.out.println(":> 成功切入,获取 name: " + map.get("name"));

        catch (Exception e)
            e.printStackTrace();
        
    



@After("execution(@DataPoint * *..*.*(..))") 表示:任意类型 任意包下的任意类里的任意方法,并且方法添加了 DataPoint 注解,会在方法执行完后立即切入。

这样就会只在添加了注解的方法执行完后进行切入,可以对程序的整体性能影响降到最低。

  • 运行结果

上图所示,切入成功,数据也正常获取。

然后就可以愉快的将该数据埋点解决方案应用于项目中去了。

参考文章


AspectJ在Android 中的使用攻略

Android中使用AspectJ


技术永不眠!我们下期见!

以上是关于AspectJXAndroid 中快速集成使用一款 AOP 框架并附加数据埋点解决方案实现的主要内容,如果未能解决你的问题,请参考以下文章

AspectJXAndroid 中快速集成使用一款 AOP 框架并附加数据埋点解决方案实现

AspectJXAndroid 中快速集成使用一款 AOP 框架并附加数据埋点解决方案实现

如何快速地开发一款 Android App

一款最流行的MVPArms MVP快速集成框架Retoift,Okhttp,RxCache,Gson,RxLifeCycle, Dagger2,Rxjava,ImageLoader

想找一款B/S架构的快速开发平台,请大家帮忙推荐一款。

Vue与UIKit集成