当前位置:   article > 正文

AOP 在android中的使用之埋点日志_android日志埋点

android日志埋点

android 开发,我们通常使用的是面向对象编程,这个写起来比较方便。但一些特殊的功能,比如说埋点统计些信息,或者打印某些方法的消耗时间,如果我们在要统计的地方直接写代码,看着不优雅,并且也把功能耦合在一起了。AOP 叫做切面编程,它更像一把刀切入到某个功能里面,不用直接耦合代码。比如如打印耗时日志,使用切面编程则可以把要统计的一些方法的代码统一放在一个地方,通过注解来引用,这样就比较完美的做到了代码分离。


AspectJ 是 AOP 的一个实现类库,我们可以直接使用它。先说说gradle配置方式,我们可以在 Android Studio 中建个 module 库,再库的 gradle 配置文件中,引入 aspectj 的单独脚本配置,我把它抽了出来,如下

  1. build.gradle 
  2. ******************
  3. apply plugin: 'com.android.library'
  4. apply from: 'asplib.gradle'
  5. android {
  6.   compileSdkVersion 28
  7.   buildToolsVersion '28.0.3'
  8. }
  9. ******************
  10. asplib.gradle
  11. *********************
  12. import org.aspectj.bridge.MessageHandler
  13. import org.aspectj.tools.ajc.Main
  14. buildscript {
  15.   repositories {
  16.     mavenCentral()
  17.     google()
  18.   }
  19.   dependencies {
  20.     classpath 'com.android.tools.build:gradle:3.4.1'
  21.     classpath 'org.aspectj:aspectjtools:1.8.1'
  22.   }
  23. }
  24. dependencies {
  25.   implementation 'org.aspectj:aspectjrt:1.8.1'
  26. }
  27. project.android.libraryVariants.all { variant ->
  28.   JavaCompile javaCompile = variant.javaCompileProvider.get()
  29.   javaCompile.doLast {
  30.     String[] args = ["-showWeaveInfo",
  31.                      "-1.5",
  32.                      "-inpath", javaCompile.destinationDir.toString(),
  33.                      "-aspectpath", javaCompile.classpath.asPath,
  34.                      "-d", javaCompile.destinationDir.toString(),
  35.                      "-classpath", javaCompile.classpath.asPath]
  36.     MessageHandler handler = new MessageHandler(true)
  37.     new Main().run(args, handler)
  38.   }
  39. }
  40. *******************************


在 module 中,定义一个类 TrAspect ,用 @Aspect 来修饰它,比如我们来打印下 Activity 的声明周期日志,

  1. @Aspect
  2. public class TrAspect {
  3.   private static final String POINTCUT_ONMETHOD = "execution(* android.app.Activity.on**(..))";
  4.   @Before(POINTCUT_ONMETHOD)
  5.   public void beforeOnMethod(JoinPoint joinPoint) {
  6.     MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  7.     String className = methodSignature.getDeclaringType().getSimpleName();
  8.     String methodName = methodSignature.getName();
  9.     Log.e("TrAspect", "before   " + className + "    " + methodName );
  10.   }
  11.   @After(POINTCUT_ONMETHOD)
  12.   public void onMethLog(JoinPoint joinPoint){
  13.     MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  14.     String className = methodSignature.getDeclaringType().getSimpleName();
  15.     String methodName = methodSignature.getName();
  16.     Log.e("TrAspect", "after   " + className + "    " + methodName );
  17.   }
  18. }


在主工程 app 中,创建 MainActivity,重写 onCreate(Bundle savedInstanceState) 方法

  1. public class MainActivity extends Activity {
  2.   @Override
  3.   protected void onCreate(Bundle savedInstanceState) {
  4.     super.onCreate(savedInstanceState);
  5.     setContentView(R.layout.activity_main);
  6.   }
  7.   
  8. }


然后我们编译下,发现无效,什么原因呢?原来 app 主工程中 build.gradle 也需要配置(我也不清楚原因),抽取出来,build.gradle 中配置 apply from:'asp.gradle'

  1. asp.gradle
  2. ********************************
  3. import org.aspectj.bridge.IMessage
  4. import org.aspectj.bridge.MessageHandler
  5. import org.aspectj.tools.ajc.Main
  6. buildscript {
  7.   repositories {
  8.     mavenCentral()
  9.     google()
  10.   }
  11.   dependencies {
  12.     classpath 'com.android.tools.build:gradle:3.4.1'
  13.     classpath 'org.aspectj:aspectjtools:1.8.1'
  14.   }
  15. }
  16. dependencies {
  17.   implementation project(':gintonic')
  18.   implementation 'org.aspectj:aspectjrt:1.8.1'
  19. }
  20. final def log = project.logger
  21. final def variants = project.android.applicationVariants
  22. variants.all { variant ->
  23.   if (!variant.buildType.isDebuggable()) {
  24.     log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
  25.     return
  26.   }
  27.   JavaCompile javaCompile = variant.javaCompileProvider.get()
  28.   javaCompile.doLast {
  29.     String[] args = ["-showWeaveInfo",
  30.                      "-1.5",
  31.                      "-inpath", javaCompile.destinationDir.toString(),
  32.                      "-aspectpath", javaCompile.classpath.asPath,
  33.                      "-d", javaCompile.destinationDir.toString(),
  34.                      "-classpath", javaCompile.classpath.asPath,
  35.                      "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
  36.     MessageHandler handler = new MessageHandler(true)
  37.     new Main().run(args, handler)
  38.     for (IMessage message : handler.getMessages(null, true)) {
  39.       switch (message.getKind()) {
  40.         case IMessage.ABORT:
  41.         case IMessage.ERROR:
  42.         case IMessage.FAIL:
  43.           log.error message.message, message.thrown
  44.           break
  45.         case IMessage.WARNING:
  46.           log.warn message.message, message.thrown
  47.           break
  48.         case IMessage.INFO:
  49.           log.info message.message, message.thrown
  50.           break
  51.         case IMessage.DEBUG:
  52.           log.debug message.message, message.thrown
  53.           break
  54.       }
  55.     }
  56.   }
  57. }
  58. ***************************


编译后,打印日志

  1. 2020-04-29 19:08:28.406 11794-11794/ E/TrAspect: before   MainActivity    onCreate
  2. 2020-04-29 19:08:28.495 11794-11794/ E/TrAspect: after   MainActivity    onCreate

细看 TrAspect 中使用的注解,@Before 和 @After 这两个,意思是在要切入的方法之前和之后执行,"execution(* android.app.Activity.on**(..))" 是我们配置的条件,这个里面是说 Activity 子类中所有以 on 开头的方法,当然是我们重写的方法,这就是个条件匹配,一旦匹配到了,马上执行方法。如果想把上面二合一,怎么办?使用 @Around,它具有 @Before 和 @After 的功能,见代码

  1.   @Around(POINTCUT_ONMETHOD)
  2.   public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
  3.     MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  4.     String className = methodSignature.getDeclaringType().getSimpleName();
  5.     String methodName = methodSignature.getName();
  6.     Log.e("TrAspect", "before   " + className + "    " + methodName );
  7.     Object result = joinPoint.proceed();
  8.     Log.e("TrAspect", "after   " + className + "    " + methodName );
  9.     return result;
  10.   }

joinPoint.proceed(); 的意思就是执行 onCreate()  方法,打印值日,和上面的一样。

同理,埋点也可以这么做,我们可以通过判断方法名字,把日志写入缓存或文本中,然后在主工程中通过读取缓存输入,上报到服务端。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/266748
推荐阅读
相关标签
  

闽ICP备14008679号