Android使用AspectJ拦截点击事件

集成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());
    }
}

运行点击后的效果如下


参考文章

https://juejin.cn/post/6977152381343498270

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容