Android——面向AOP编程
Posted 化作孤岛的瓜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android——面向AOP编程相关的知识,希望对你有一定的参考价值。
前言:
最近在工作中接触到了字节码插桩相关的知识,所以以本文来整理并实践一下相关的知识体系。
字节码插桩:
- AOP编程
- 打包流程
- 自定义Gradle Task
- 查看,识别Java字节码
- ASM使用
- Transform
AOP编程思想:
面向切面编程思想,与面向过程和面向对象编程不同,AOP可以理解s为处理项目中一些统一的事物的过程,比如统计所有log,所有的点击事件监听,某个方法的全局操作等等。
打包流程:
java → class+jar → classes.dex+aaset+res → resource.zip+dex → apk
参考:https://blog.csdn.net/wangzhongshun/article/details/96160984
自定义grade插件:
Gradle以Groovy作为脚本语言,Groovy类似于java的方言。
Grade由project组成,一个Project包含n个Task,Task由n个Action组成,Action即执行代码块。
构建工具会根据每个build.grade文件创建出Project实例,初始化的时候会去settings.gradle文件下拿到摇构建的项目。
settings.gradle文件:
rootProject.name = "aop_asm_study"
include ':app'
可以其中的include,告诉Gradle需要参与构建的项目。
Task是gradle执行的最小单元,构建,编译,打包,debug,test等都是执行了某一个task。
Task会按依赖关系顺序执行。
编写Gradle插件主要有三种方法:
- build.gradle脚本中直接使用。这种方式就是直接在android Studio app moudle的build.gradle中进行插件的编写,优点是不用再上传插件到maven或者其它地方,项目就可以直接使用;缺点也很明显,就是只能在自己的项目中使用,不能复用,这个不是我们今天要说的。
可以看到,可以在工程的build.gradle中直接写task,这里输出一句话,然后在右边的Gradle列表里:Tasks->other中找到myCustionTask
双击运行:
- buildSrc中使用。这种方式需要在项目中新建一个model命名为buildSrc,这个目录就用来存放自定义插件。然后在src/main中建立两个目录,一个就是存放代码的groovy目录,一个是存放自定义插件名称的resources目录。这种定义方式也是只能在我们项目中进行使用,不好复用。
- 独立Module中使用。这种方式就是完全独立开发一个Module,可以随便用,与第二种方式的区别是不直接依赖,采用maven仓库依赖。
单Module方式:
- 首先新建一个module,文件结构修改为以下图所示:
这里要注意划线部分一定要一致。
NetworkPlugin:
package com.example.jzn.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
class NetworkPlugin implements Plugin<Project>{
@Override
void apply(Project project) {
println "------network plugin begin-------"
project.tasks.create("ngTestWork", NetworkTask) {
doLast {
println "doLast"
}
}
println "------network plugin end-------"
}
}
NetworkTask:
package com.example.jzn.plugin
import okhttp3.Call
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class NetworkTask extends DefaultTask {
@TaskAction
def testNetwork() {
println "------NetworkTask begin-------"
try {
OkHttpClient mOkHttpClient = new OkHttpClient()
Request request = new Request.Builder().url("http://www.baidu.com/").build()
Call call = mOkHttpClient.newCall(request)
Response mResponse = call.execute()
if (mResponse.isSuccessful()) {
println mResponse.body().string()
}
} catch (Exception e) {
e.printStackTrace()
println e.toString()
}
println "------NetworkTask end-------"
}
}
com.example.jzn.plugin.properties:
implementation-class=com.example.jzn.plugin.NetworkPlugin
然后这里要注意修改该module下的build.gradle:
apply plugin: 'groovy'
//使用该插件,才能使用uploadArchives
apply plugin: 'maven'
repositories {
jcenter()
}
dependencies {
//使用gradle sdk
compile gradleApi()
//使用groovy sdk
compile localGroovy()
compile 'com.android.tools.build:gradle:3.0.1'
compile 'com.squareup.okhttp3:okhttp:3.7.0'
compile 'com.squareup.okio:okio:1.9.0'
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
uploadArchives {
repositories.mavenDeployer {
pom.version = '1.0.0'
pom.artifactId = 'jznPlugin'
pom.groupId = 'com.example.jzn.plugin'
//repository(url: "file:///D:/repository/")
repository(url: "file:/Users/xiaoguagua/Desktop/chajian/")
}
}
这里没有用网络maven,用的本地地址,是我在mac桌面创建的一个文件夹。
全部配置好之后,sync一下项目,在gradle任务下会出现这个上传的task:
点击运行,成功之后会看到chajian文件夹里已经有了我们生成的组件:
这个时候,我们如果要在其他工程中引用,只需要在根目录的build.gradle作如下配置即可:
引入依赖,支持组件,然后编译一下,就会在gradle列表的Tasks->other里看到我们自定义的task:
最后点击运行可以看到控制台输出的效果了。
查看字节码
首先查看class文件:
可以在app-build-intermediates-javac里看到所有的class
查看字节码:ASM Bytecode Viewer插件。
ASM的使用
主要的操作流程:
- 需要创建一个 ClassReader 对象,将 .class 文件的内容读入到一个字节数组中
- 然后需要一个 ClassWriter 的对象将操作之后的字节码的字节数组回写
- 需要事件过滤器 ClassVisitor。在调用 ClassVisitor 的某些方法时会产生一个新的 XXXVisitor 对象,当我们需要修改对应的内容时只要实现自己的 XXXVisitor 并返回就可以了
Transform
在Android打包过程中的class 文件到 .dex 发文件的阶段里,Transform 是 Android 官方提供的在这一阶段用来修改 .class 文件的一套标准 API。这一应用现在主要集中在字节码查找、代码注入等。
每个 Transform 都是一个 gradle task, 将 class 文件、本地依赖的 jar, aar 和 resource 资源统一处理。 每个 Transform 在处理完之后交给下一个 Transform。
如果是用户自定义的 Transform 会插在队列的最前面。
Transform使用方式:
Transform是一个抽象类,我们可以创建一个类继承它,然后在自定义的Plugin中注册:
val android = project.extensions.getByType(AppExtension::class.java)
android.registerTransform(LogTransform())
这里的AppExtension是啥呢?可以参考:https://blog.csdn.net/chennai1101/article/details/103279116
参考资料:
aop编程:https://blog.csdn.net/huaxun66/article/details/103497729
Android编译插桩:https://zhuanlan.zhihu.com/p/262865457
自定义gradle插件参考:
https://www.jianshu.com/p/d53399cd507b
https://blog.csdn.net/huaxun66/article/details/103497369
Transform参考:https://zhuanlan.zhihu.com/p/262865457
asm参考:https://www.jianshu.com/p/905be2a9a700
配合ASM实现AOP编程:
测试工程:aop_asm_study
以上是关于Android——面向AOP编程的主要内容,如果未能解决你的问题,请参考以下文章
Android——面向AOP编程 Xerath 开源AOP框架