今天老大跑过来说项目埋点了解一下!丢下了这句话之后,就没有之后了!剩下我一个人在风中凌乱!!!
其实这个需求老大在很久之前就说要开发了,后来就搁置了!但是今天看老大的态度,应该排到日程了!所以没办法只有硬着头皮磕了!免得过一阵子加班到很晚,所以趁着时间宽松,先能把踩的坑踩踩!!!分享给大家,也让大家能避免一些不必要的时间浪费。更好的过个周末,陪陪女盆友!!!
出于可读性考虑,我准备把这个系列分成几部分去写,因为这样才能充分利用你的碎片时间,能让你在碎片化中学习一个知识点。
第一篇文章主要讲解关于AOP中埋点的概念和相应的集成; 第二篇文章主要讲解关于AspectJ中用到的一些知识点; 第三篇文章主要讲解关于AspectJ在项目的其他一些应用。
所谓埋点 ,百度百科是这么说的!其实说简单点,就是我在APP中都做了什么事情,让你们运营的知道,其实想想挺可怕的,这我要是出去浪,媳妇就知道了!!!明白了吧,你的一切行为都在掌控之中,用来生成人物画像什么的。。。一堆乱七八糟的!那么我们程序员要做什么呢?像什么统计时长了,点击了什么按钮了,常去什么页面了等...好吧!剩下的就看你们运营需要什么了,就科普到这里吧!
我整理了相应内容,我发现其实埋点可以分为:
作为一个移动端的猿,理所应当的从APP层面去分析相应的实现,现在在APP端的实现基本上分为以下几种
其实从程序员角度分析的话,无非就是代码写得多少的事情吗?往往许多内容都这能用这个东西衡量的,所以没有实现不了的,大不了我就多写点代码呗!但是为了让你成为一名有逼格的程序猿,总是要学点什么的!!!
百度百科是这么形容AOP的!面向切面编程。也就是说在某个切面,你可以做一些相应的操作!这么和你比喻吧,当你触发一个点击事件的时候,点击的一瞬间算是一个切面,你可以在这个切面的前后加上一些相应的内容,也就是相应的切面编程了!
能解决什么问题呢?往往很多人都会这么问?有这样一个需求,一些APP只有在登陆的情况下才能做一些事情,往往有很多按钮都需要判断登陆的情况,如果你每一个按钮都写一个判断方法,那代码就很多了,如果产品跑过来说在添加一个VIP的功能你怎么办?所有的地方都要改?我擦,毁灭性的啊!这个时候就可以使用AOP这种编程思想了!再点击之前做一些相应的处理,那么即便是你在改的话,也只需要改一个地方!
上面说了那么多都是废话,只是了解一下就可以了!我看Android中使用AOP基本上都是使用注解和一个叫 AspectJ 这么个东西,都说是非侵入式埋点,这个非侵入式是一个很好的东西,也就是不用更改之前代码的逻辑就可以实现相应的需求,所以我觉得埋点使用这个东西就非常好了!
关于AspectJ这个东西的集成,要用到一些gradle中的知识,其实对这里的知识我也不是很了解,也不再我们今天要讲的内容中,所以这里直接跳过了,感兴趣的同学可以自行百度,这个插一句(学习要有目的性,如果你要学某一个东西的话,其它的东西真的可以先放一放!!!)我就讲讲怎么集成就好了!!!
首先说明一个事情,因为代码是非侵入性的,所以建议你把AspectJ集成在一个专门的Module中,这样在不改变原有的内容就能实现相应的方案。why?因为我就是这么做的。。。
classpath 'org.aspectj:aspectjtools:1.8.9' //虽然都说句要加,但是我没加程序还是正常运行的! classpath 'org.aspectj:aspectjweaver:1.8.9' 复制代码
整段代码是这样滴!
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.4' classpath 'org.aspectj:aspectjtools:1.8.9' //我发现这个东西不加也是可以正常运行的 // classpath 'org.aspectj:aspectjweaver:1.8.9' } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } 复制代码
在项目的build.gradle中添加相应的依赖 implementation 'org.aspectj:aspectjrt:1.8.9'
然后在 根路径 添加相应的配置
import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main final def log = project.logger android.applicationVariants.all{ variant -> if (!variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.") return } JavaCompile javaCompile = variant.javaCompiler javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.8", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)] log.debug "ajc args: " + Arrays.toString(args) MessageHandler handler = new MessageHandler(true) new Main().run(args, handler) for (IMessage message : handler.getMessages(null, true)) { switch (message.getKind()) { case IMessage.ABORT: case IMessage.ERROR: case IMessage.FAIL: log.error message.message, message.thrown break case IMessage.WARNING: log.warn message.message, message.thrown break case IMessage.INFO: log.info message.message, message.thrown break case IMessage.DEBUG: log.debug message.message, message.thrown break } } } } 复制代码
别问我为什么?我怎得不理解这段代码,反正我知道这段代码是必须的。
整段代码是这样滴!
apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "com.jinlong.aspectjdemo" minSdkVersion 14 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:28.0.0-rc01' implementation 'com.android.support.constraint:constraint-layout:1.1.2' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation project(':aspectmodule') implementation 'org.aspectj:aspectjrt:1.8.9' } import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main final def log = project.logger android.applicationVariants.all{ variant -> if (!variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.") return } JavaCompile javaCompile = variant.javaCompiler javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.8", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)] log.debug "ajc args: " + Arrays.toString(args) MessageHandler handler = new MessageHandler(true) new Main().run(args, handler) for (IMessage message : handler.getMessages(null, true)) { switch (message.getKind()) { case IMessage.ABORT: case IMessage.ERROR: case IMessage.FAIL: log.error message.message, message.thrown break case IMessage.WARNING: log.warn message.message, message.thrown break case IMessage.INFO: log.info message.message, message.thrown break case IMessage.DEBUG: log.debug message.message, message.thrown break } } } } 复制代码
在这里说明以下,如果你要是在Module中使用,那么在app的build.gradle中也要进行相应的配置!切记!!! 重要的事情说 " 三遍 "!!!这里直接贴一下相应Module中的配置!
apply plugin: 'com.android.library' android { compileSdkVersion 28 defaultConfig { minSdkVersion 14 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0-rc01' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'org.aspectj:aspectjrt:1.8.9' } import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main final def log = project.logger android.libraryVariants.all{ variant -> if (!variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.") return } JavaCompile javaCompile = variant.javaCompiler javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.8", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)] log.debug "ajc args: " + Arrays.toString(args) MessageHandler handler = new MessageHandler(true) new Main().run(args, handler) for (IMessage message : handler.getMessages(null, true)) { switch (message.getKind()) { case IMessage.ABORT: case IMessage.ERROR: case IMessage.FAIL: log.error message.message, message.thrown break case IMessage.WARNING: log.warn message.message, message.thrown break case IMessage.INFO: log.info message.message, message.thrown break case IMessage.DEBUG: log.debug message.message, message.thrown break } } } } 复制代码
注意这里主项目和类库中是不一样的!!!以上可以保证你编译通过了,但是这才是开始的配置!!!
这里先说以下相应的配置,具体为什么先不去说!!!下篇文章我会尽我所能给你讲解清楚的!!!相信我
@Aspect public class TraceAspect { private static final String TAG = "hjl"; @Before("execution(* android.app.Activity.on*(..))") public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable { String key = joinPoint.getSignature().toString(); Log.e(TAG, "onActivityMethodBefore: 切面的点执行了!" + key); } } 复制代码
首先说一下这段注意事项:
简单说明一下原理,通过上面这个类,主要是在方法中的最开始添加一个相应的方法,也就是把你写的这段代码以一个方法的形式添加到某个位置!这样就实现了通过切面进行相应的处理方案了!!!
想看源码吗?想看链接吗? 点这里