集成AspectJ
在项目根目录的build.gradle中添加:
classpath 'org.aspectj:aspectjtools:1.9.6'
在app的build.gradle中添加:
...省略部分代码
dependencies {
...省略部分代码
implementation 'org.aspectj:aspectjrt:1.9.6'
}
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
// 注意这里控制debug下生效,可以自行控制是否生效
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return
}
JavaCompile javaCompile = variant.javaCompileProvider.get()
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.8", // java1.8
"-inpath", javaCompile.destinationDir.toString(), //需要处理的class文件目录
"-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)
def buildType = variant.buildType.name
String[] kotlinArgs = ["-showWeaveInfo",
"-1.8",
"-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
"-aspectpath", javaCompile.classpath.asPath,
"-d", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
MessageHandler handler = new MessageHandler(true)
new Main().run(args, handler)
new Main().run(kotlinArgs, 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
}
}
}
编写插桩类
由于Kotlin插桩既可以支持源代码为Java也可以支持源代码为Kotlin所以这里的插桩代码我用的Kotlin编写
//必须
@Aspect
class InterceptClickAspectJ {
// 最后一次点击的时间
private var lastTime = 0L
//正常点击事件
@Around("execution(* android.view.View.OnClickListener.onClick(..))")
@Throws(Throwable::class)
fun clickIntercept(joinPoint: ProceedingJoinPoint) {
// 大于间隔时间可点击
if (System.currentTimeMillis() - lastTime >= INTERVAL) {
// 记录点击时间
lastTime = System.currentTimeMillis()
// 执行点击事件(执行这句代码的话会执行原代码逻辑)
// joinPoint.proceed()
ToastUtils.showShort("你好")
} else {
Log.e("weilu", "重复点击")
}
}
//使用lambda的点击事件
@Around("execution(* *..*lambda*(..))")
@Throws(Throwable::class)
fun clickInterceptLambda(joinPoint: ProceedingJoinPoint) {
// 大于间隔时间可点击
if (System.currentTimeMillis() - lastTime >= INTERVAL) {
// 记录点击时间
lastTime = System.currentTimeMillis()
// 执行点击事件(执行这句代码的话会执行原代码逻辑)
// joinPoint.proceed()
ToastUtils.showShort("你好lambda")
} else {
Log.e("weilu", "重复点击")
}
}
companion object {
// 点击间隔时长
private const val INTERVAL = 1000L
}
}
编写点击事件类
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.bt_click).setOnClickListener {
Toast.makeText(
this@MainActivity,
"点击12",
Toast.LENGTH_SHORT
).show()
}
}
}
java
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_click).setOnClickListener(view -> Toast.makeText(TestActivity.this,"点击",Toast.LENGTH_SHORT).show());
}
}
运行点击后的效果如下