最近有做用户行为统计的需求,为了尽可能使统计代码不侵入业务代码,就研究了下hook和Aop。
之前写的hook方面的文章里,有评论给出了些建议,于是研究了下AspectJ,虽然还是不能完美解决项目中的问题,不过确实是个好东西。
实践了一把,这里简单记录一下。


先来一堆参考链接
【翻译】Android中的AOP编程
Android之AOP
Android Studio 中自定义 Gradle 插件
看AspectJ在Android中的强势插入
jarryleo / MagicBuriedPoint


言归正传

1.新建一个Library的module

新建一个module,类型选Library。
比如这里的TrackPoint

20180930103904.png

切面代码的定义基本就写在这里。

2.添加依赖

我们这种凡夫俗子要做点事只能抱一下大神的大腿,我们这里用一下别人写好的SDK:https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx

2.1.根目录的build.gradle里

buildscript {...dependencies {...classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'}
}

2.2.app项目的build.gradle及新建的module的build.gradle里都应用插件

apply plugin: 'android-aspectjx'

2.3.在app的build.gradle里面添加刚才新建的那个库

dependencies {...implementation project(':TrackPoint')
}

3.定义切入点

Library里定义文件主要分三个文件TrackPointCallBack,TrackPoint,TrackPointAspect

3.1.先定义接口以供调用

TrackPointCallBack和TrackPoint两个文件就是接口和调用方法定义,简单起见,这里仅以点击和页面的打开关闭为例:

package net.codepig.trackpoint;public class TrackPoint {private static TrackPointCallBack trackPointCallBack;private TrackPoint() {}public static void init(TrackPointCallBack callBack) {trackPointCallBack = callBack;}static void onClick(String pageClassName, String viewIdName) {if (trackPointCallBack == null) {return;}trackPointCallBack.onClick(pageClassName, viewIdName);}static void onPageOpen(String pageClassName) {if (trackPointCallBack == null) {return;}trackPointCallBack.onPageOpen(pageClassName);}static void onPageClose(String pageClassName) {if (trackPointCallBack == null) {return;}trackPointCallBack.onPageClose(pageClassName);}
}
package net.codepig.trackpoint;public interface TrackPointCallBack {void onClick(String pageClassName, String viewIdName);void onPageOpen(String pageClassName);void onPageClose(String pageClassName);
}

3.2.Aspect的定义

这里是重点,就靠这个在不涉及业务代码的情况下,在需要的事件前后插入新的行为。
先看代码:

package net.codepig.trackpoint;import android.view.View;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class TrackPointAspect {@Pointcut("execution(* onClick(..))")public void methodPointcut() {}@Pointcut("execution(* android.app.Activity+.onCreate(..))")public void activityOnCreatePointcut() {}@Pointcut("execution(* android.app.Activity+.onDestroy(..))")public void activityOnDestroyPointcut() {}@Pointcut("execution(* android.app.Fragment+.onCreate(..))")public void fragmentOnCreatePointcut() {}@Pointcut("execution(* android.support.v4.app.Fragment+.onCreate(..))")public void fragmentV4OnCreatePointcut() {}@Pointcut("execution(* android.app.Fragment+.onDestroy(..))")public void fragmentOnDestroyPointcut() {}@Pointcut("execution(* android.support.v4.app.Fragment+.onDestroy(..))")public void fragmentV4OnDestroyPointcut() {}@Around("onClickPointcut()")public void aroundJoinClickPoint(final ProceedingJoinPoint joinPoint) throws Throwable {Object target = joinPoint.getTarget();String className = "";if (target != null) {className = target.getClass().getName();}//获取点击事件view对象及名称,可以对不同按钮的点击事件进行统计Object[] args = joinPoint.getArgs();if (args.length >= 1 && args[0] instanceof View) {View view = (View) args[0];int id = view.getId();String entryName = view.getResources().getResourceEntryName(id);TrackPoint.onClick(className, entryName);}joinPoint.proceed();//执行原来的代码}@Around("activityOnCreatePointcut() || fragmentOnCreatePointcut() || fragmentV4OnCreatePointcut()")public void aroundJoinPageOpenPoint(final ProceedingJoinPoint joinPoint) throws Throwable {Object target = joinPoint.getTarget();String className = target.getClass().getName();TrackPoint.onPageOpen(className);joinPoint.proceed();}@Around("activityOnDestroyPointcut() || fragmentOnDestroyPointcut() || fragmentV4OnDestroyPointcut()")public void aroundJoinPageClosePoint(final ProceedingJoinPoint joinPoint) throws Throwable {Object target = joinPoint.getTarget();String className = target.getClass().getName();TrackPoint.onPageClose(className);joinPoint.proceed();}
}

具体的语法可以参考前面列出的参考教程,这里只是简单的做一下说明:

3.2.1@Pointcut语法

设置需要切入的方法。其中参数中第一个*表示返回值使用任意类型。方法中的(..)也表示使用任意类型。
需要注意的是这里的Fragment相关需要加上android.support类的支持。

3.2.2@Around@Before@After语法

定义具体插入的代码,比如在相关的事件上插入需要的统计代码。
这里可以使用『&&、||、!』来组合不同的Pointcut定义。比如@Around("activityOnDestroyPointcut() || fragmentOnDestroyPointcut() || fragmentV4OnDestroyPointcut()")就是组合了三种关闭事件。

4.初始化

初始化可以在Application中进行。(没有的话就建一个。)
然后在onCreate方法中进行初始化

public class MainApp extends Application {private static final String TAG = "LOGCAT";@Overridepublic void onCreate() {super.onCreate();TrackPoint.init(new TrackPointCallBack() {@Overridepublic void onClick(String pageClassName, String viewIdName) {Log.d(TAG, "onClick: " + pageClassName + "-" + viewIdName);//添加你的操作}@Overridepublic void onPageOpen(String pageClassName) {Log.d(TAG, "onPageOpen: " + pageClassName);//添加你的操作}@Overridepublic void onPageClose(String pageClassName) {Log.d(TAG, "onPageClose: " + pageClassName);//添加你的操作}});}
}

收工!
当然值得操作的事件肯定不止上面这三种,以后慢慢添加吧。


相关github项目地址:https://github.com/codeqian/aspectJDemo

在Android中使用AspectJ进行切面编程的简易步骤相关推荐

  1. spring中使用Aspectj进行切面编程

    推荐 个网购 优惠券 领取网站 U券网 uquanfree.com 点击链接进入 Spring的AOP可以通过对@AspectJ注解的支持和在XML中配置来实现,本文通过实例简述如何在Spring中使 ...

  2. spring aop实例讲解_小实例理解Spring中的AOP----面向切面编程

    关于面向切面编程(Spring AOP),是在java面试中经常提及的,只有在充分理解了,日常工作中才能得心应手. 如何理解AOP呢?首先我们要思考为什么要使用切面编程,如下图: 对于一个系统来说保存 ...

  3. java切面不需要接口了吗_使用java语言,如何对一个类中的静态方法做切面编程?...

    展开全部 package com.classloader.test; import java.lang.reflect.InvocationTargetException; import java.l ...

  4. AOP面向切面编程简单使用

    一.AOP介绍 1.AOP是什么? AOP即为面向切面编程,和Java的OOP面向对象编程一样,都是一种编程思想,一些先行者已经为面向切面编程开发了一套语言来支持. 2.AOP的作用是什么? 通过预编 ...

  5. Spring AOP 面向切面编程

    AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件 ...

  6. AOP (面向切面编程)

    AOP (面向切面编程) 编辑 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AO ...

  7. 一篇文搞懂《AOP面向切面编程》是一种什么样的体验?

    写在前面 hello,大家好,我是灰小猿,一个超会写bug的程序猿! 近期一直在准备秋招和技术,所以写文的频率有些下降,但是这也依然阻挡不了我要和大家一起分享技术的热情呀. 之前在专栏<SSM编 ...

  8. AOP(面向切面编程)大概了解一下

    前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 1. 概述 在软件业, ...

  9. Spring.NET学习笔记12——面向切面编程(基础篇) Level 300

    AOP即面向切面编程(Aspect Oriented Programming的缩写),是OOP(面向对象编程)的一种延续形式.是通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添 ...

最新文章

  1. 湖南中医药大学计算机刘伟老师,喜讯 | 湖南中医药大学在全省高校教师课堂教学竞赛中喜获佳绩...
  2. java怎么画词云_Matplotlib学习---用wordcloud画词云(Word Cloud)
  3. Nginx详细安装部署教程
  4. url中参数以及callback后面的串
  5. 一种基于云信sdk的互动直播的实现
  6. Spark笔记:RDD基本操作(上)
  7. 介绍一个好用的日期倒计时工具
  8. mkimage command not found
  9. 作者:邹本友,男,中国人民大学信息学院博士生, CCF学生会员。
  10. 六招让你成职场超男超女
  11. 1006 A+B问题
  12. ssfn授权_Steam盗号木马窃取授权文件,360安全大脑强力拦截
  13. Google 数学之美系列整理
  14. Linux中查看文件夹大小的命令
  15. 测试计划与测试方案区别
  16. word分节符设置与不同页眉页脚页码设置
  17. 后端开发岗位要求汇总
  18. 【数据库学习笔记】Day03 - SQL语言基础及数据库定义功能
  19. 数据分析岗位面试准备请看这篇!
  20. L2正则化(L2 Regularization)

热门文章

  1. Java8-Stream 概括
  2. 计算机二级c语言作弊的东西,计算机二级C全部考试题库[作弊必备]编程题.txt
  3. linux怎么测试磁盘读写,怎样测试Linux磁盘的读写速率
  4. unity加载sprite_Unity 利用UGUI打包图集,动态加载sprite资源
  5. bochs调试方法与指令详解
  6. foo php,php – $foo === TRUE和TRUE === $foo有什么区别?
  7. python语言的格式框架_django框架模板语言使用方法详解
  8. tomcat拒绝访问是为什么_Tomcat中的connectTimeout和慢攻击
  9. 网络配置_Linux网络环境配置
  10. 执行计划有时不准确_生管如何应对采购物料不及时、回不来?