组件化开发过程中,各个模块内往往需要感知Application的生命周期,以获取context完成初始化工作等,业务上模块间或存在初始化顺序要求,比较常规的做法有:
在common模块定义 AppLifecycleCallback
interface AppLifecycleCallback { fun getPriority(): Int = 0 fun onCreate(context: Context)}复制代码
各个模块实现 AppLifecycleCallback ,如Home模块
class HomeAppLifecycle : AppLifecycleCallback { override fun getPriority(): Int = 0 override fun onCreate(context: Context) { //todo }}复制代码
然后在 MainApplication 中实现生命周期分发
class MainApplication : Application() { private val callbacks = mutableListOf() override fun onCreate() { super.onCreate() callbacks.add(HomeAppLifecycle()) callbacks.add(UserAppLifecycle()) // add whatever you want // 排序实现模块顺序分发 callbacks.sortBy { it.getPriority() } callbacks.forEach { it.onCreate(this) } } }复制代码
这样能实现需求,但每增加一个模块,就得回到MainApplication中添加一个,不够优雅不够装,这时候就可以用上 APT + Transform
此方案主要是为了解学习apt,gradle transform,实际上有更好的实现方案。各位大佬畅所欲言,提出此方案的短板
创建android-library,定义 AppLifecycleCallback 、 AppLifecycleManager
interface AppLifecycleCallback { fun getPriority(): Int = 0 fun onCreate(context: Context)}复制代码
AppLifecycleManager中 onCreate 是对外的API,在MainAppkication中调用; registerAppLifecycleCallback 则是在transform阶段使用asm在AppLifecycleManager的构造方法中调用,将代理类路径传入,最终通过反射存储在callbacks中
object AppLifecycleManager { private var callbacks: MutableList? = null fun onCreate(context: Context) { callbacks?.run { sortBy { it.getPriority() } forEach { it.onCreate(context) } } } private fun registerAppLifecycleCallback(name: String) { try { if (callbacks == null) { callbacks = mutableListOf() } val instance = Class.forName(name).getConstructor().newInstance() if (instance is AppLifecycleCallback && !callbacks!!.contains(instance)) { callbacks!!.add(instance) } } catch (e: Exception) { e.printStackTrace() } }}复制代码
@Target(AnnotationTarget.CLASS)@Retention(AnnotationRetention.SOURCE)annotation class AppLifecycle()复制代码
@AutoService(Processor::class)class AppLifecycleProcessor : AbstractProcessor() { // 省略部分代码 override fun process(p0: MutableSet?, environment: RoundEnvironment?): Boolean { environment?.run { getElementsAnnotatedWith(AppLifecycle::class.java) .filter { it.kind == ElementKind.CLASS } .filter { (it as TypeElement).interfaces.contains( elements.getTypeElement(callbackName).asType() ) } .forEach { AppLifecycleProxyBuilder(it as TypeElement, elements).build().writeTo(filer) } } return true }}复制代码
KotlinPoet生成Proxy类
class AppLifecycleProxyBuilder(private val typeElement: TypeElement, elements: Elements) { // 省略部分代码 fun build(): FileSpec { return FileSpec.builder(packageName, fileName) .addType(getTypeSpec()) .build() } private fun getTypeSpec(): TypeSpec { return TypeSpec.classBuilder(fileName) .addProperty(getProperty()) .addSuperinterface(superInterface) .addFunction(getOnCreate()) .addFunction(getPriority()) .build() } private fun getProperty(): PropertySpec { // 对应注解类实例 return PropertySpec.builder("callback", typeElement.asClassName(), KModifier.PRIVATE) .initializer("%T()", typeElement.asType()) .build() } private fun getOnCreate(): FunSpec { // onCreate(context: Context) return FunSpec.builder("onCreate") .addModifiers(KModifier.OVERRIDE) .addParameter("context", contextType) .addStatement("callback.onCreate(context)") .build() } private fun getPriority(): FunSpec { // getPriority(): Int return FunSpec.builder("getPriority") .addModifiers(KModifier.OVERRIDE) .returns(Int::class) .addStatement("return callback.getPriority()") .build() }}复制代码
注:kotlin使用apt,要在build.gradle要有以下两个声明
plugins { id 'kotlin-kapt'}dependencies { kapt (project(":processor"))}复制代码
创建kotlin-library
定义AppLifecyclePlugin,继承Transform,实现Project接口
class AppLifecyclePlugin : Transform(), Plugin { private val appLifecycleClassNames = mutableListOf() private var appLifecyclesJar:File? = null override fun transform(transformInvocation: TransformInvocation?) { // transform中遍历.class文件,类名以“_Proxy”结尾并且实现AppLifecycleCallback ... if (name.endsWith(proxySuffix) && classReader.interfaces.contains(callbackInfo)) { appLifecycleClassNames.add(name) } ... // 定位到包含 ApplifecycleManager的JarEntry if(jarEntity.name == managerClassFile){ appLifecyclesJar = outputJar } // 最终使用ClassVistor将所有Proxy类加入到Manager中的callbacks里 val cv: ClassVisitor = AppLifecycleVisitor(classWriter,appLifecycleClassNames) classReader.accept(cv, ClassReader.EXPAND_FRAMES) classWriter.toByteArray() }}复制代码
AppLifecycleVisitor
class AppLifecycleVisitor(classVisitor: ClassVisitor,private val callbacks: List) : ClassVisitor(Opcodes.ASM9,classVisitor) { override fun visitMethod( access: Int, name: String?, descriptor: String?, signature: String?, exceptions: Array? ): MethodVisitor { var visitor = super.visitMethod(access, name, descriptor, signature, exceptions) if ("" == name && "()V" == descriptor && access and Opcodes.ACC_PRIVATE != 0) { visitor = object : AdviceAdapter(ASM9, visitor, access, name, descriptor) { override fun onMethodExit(opcode: Int) { for (item in callbacks) { mv.visitVarInsn(ALOAD, 0) mv.visitLdcInsn(item.replace("/", ".")) mv.visitMethodInsn( INVOKESPECIAL, "com/lauter/applifecycle/AppLifecycleManager", "registerAppLifecycleCallback", "(Ljava/lang/String;)V", false ) } } } } return visitor }}复制代码
创建完AppLifecyclePlugin,创建文件src/main/resources/META-INF/gradle-plugins/lauter.applifecycle.properties
implementation-class=com.lauter.applifecycle.AppLifecyclePlugin复制代码
到此,工作基本完成。只需要将plugin发布到本地,就可以测试功能了
在上文创建的plugin项目下build.gradle中添加:
plugins { ... // 添加publish id 'maven-publish'}...// 发布到本地publishing { publications { mavenJava(MavenPublication) { from components.java groupId = "io.github.chenlauter" artifactId = "applifecycle" version = "1.0" } } repositories { mavenLocal() maven { url = '../local-plugin-repository' } }}复制代码
在gradle中执行publish,发布完成后项目中会新增 local-plugin-repository 文件夹
在project的build.gradle中添加依赖
buildscript { repositories { ... // 添加依赖,gradle7.1之后是到setting.gralde-pluginManagement中添加 maven { url './local-plugin-repository' } } dependencies { ... classpath('io.github.chenlauter:applifecycle:1.0') }}复制代码
最后在app的build.gradle中添加
plugins { ... // 这里跟第三步创建的lauter.applifecycle.properties文件名对应 id 'lauter.applifecycle'}复制代码
至此,所以依赖都配置完毕,运行工程,在app-build下,用Android Studio直接打开apk查看 AppLifecycleManager的字节码,可以看到,在构造方法中已加入两个Proxy类路径调用:
通过查看日志打印,也能看到功能正常
D/AppLifecycle: HomeAppLifecycle onCreate D/AppLifecycle: MainAppLifecycle onCreate复制代码
github.com/ChenLauter/…
juejin.cn/post/702921…
原文链接:https://juejin.cn/post/7126419784471674887
留言与评论(共有 0 条评论) “” |