详情可见(顺便求个Star🌟):github.com/stewForAni/…
编译环境
- Android Studio Flamingo | 2022.2.1 Patch 1
- GV7.5 / AGP7.4.2
- Java11
常见功能
- 日志埋点
- 性能监控
- 登录校验
Tips
TransformApi在Gradle7.0废弃,这里采用新Api(参考上述项目)
- AppExtension替换为AndroidComponentsExtension
- AsmClassVisitorFactory类可以避免老版Transform中繁琐的io操作
- MethodVisitor需继承AdviceAdapter,涉及到LocalVariablesSorter类可以对局部变量进行重新排序
使用步骤
- 创建library类型的module,除build.gradle和main/java文件夹,其余都删除
- 自定义包名,新建xxxplugin文件
class AppPlugin :Plugin<Project>{
override fun apply(p0: Project) {
println(" **** AppPlugin start : "+p0.name+" **** ")
val ex = p0.extensions.getByType(AndroidComponentsExtension::class.java)
ex.onVariants {
it.instrumentation.transformClassesWith(MTTransform::class.java,InstrumentationScope.PROJECT) {}
it.instrumentation.setAsmFramesComputationMode(FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
}
}
}
- 自定义一个AsmClassVisitorFactory的子类,重写visit和visitMethod方法
abstract class MTTransform : AsmClassVisitorFactory<InstrumentationParameters.None> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor
): ClassVisitor {
return object : ClassVisitor(Opcodes.ASM5, nextClassVisitor) {
val cName = classContext.currentClassData.className
override fun visit(
version: Int,
access: Int,
name: String?,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
super.visit(version, access, name, signature, superName, interfaces)
if (classFilter(cName)) {
if (classFilter(cName)) {
println("---classname = $cName")
}
}
}
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
val mv = super.visitMethod(access, name, descriptor, signature, exceptions)
if (classFilter(cName)&&methodFilter(name!!)) {
println("***method = $name")
return MTMethodVisitor(cName, mv, access, name, descriptor)
}
return mv
}
}
}
override fun isInstrumentable(classData: ClassData): Boolean {
return true
}
fun classFilter(cName: String): Boolean {
return !cName.contains("Base") && (cName.endsWith("Activity") || cName.endsWith("Fragment"))
}
fun methodFilter(mName: String): Boolean {
return !mName.contains("$")&&!mName.contains("<init>")
}
}
- 自定义一个AdviceAdapter的子类xxxMethodVisitor,重写onMethodEnter和onMethodExit
class MTMethodVisitor(
private val cName: String,
mv: MethodVisitor,
access: Int,
private val mName: String?,
descriptor: String?
) : AdviceAdapter(Opcodes.ASM5, mv, access, mName, descriptor) {
override fun onMethodEnter() {
super.onMethodEnter()
...
}
override fun onMethodExit(opcode: Int) {
if (opcode == RETURN) {...}
super.onMethodExit(opcode)
}
}
- build.gradle配置如下:
plugins {
id 'org.jetbrains.kotlin.jvm'
id 'java-gradle-plugin'
id 'maven-publish'
}
java {
withJavadocJar()
withSourcesJar()
}
publishing {
publications {
mavenJava(MavenPublication) {
groupId "io.github.stewforani"
artifactId "methodtime"
version "1.0.0"
from components.java
}
}
repositories {
maven {
url "../app_plugin_repo"
}
}
}
gradlePlugin {
plugins {
MethodTimePlugin {
id = 'MethodTimePlugin'
implementationClass = 'com.stew.app_plugin.AppPlugin'
}
}
}
dependencies {
implementation 'com.android.tools.build:gradle:7.4.2'
implementation 'org.ow2.asm:asm:9.2'
implementation 'org.ow2.asm:asm-commons:9.2'
}
参考文章: