KuiklyCoreAbsEntryBuilder 对安卓平台的泛化设计全面解析
KuiklyCoreAbsEntryBuilder 是 KuiklyUI 框架中实现跨平台代码生成的核心抽象基类,它通过模板方法模式为不同平台提供了统一的代码生成框架,同时允许各平台实现自己的特定逻辑。下面对其安卓平台的泛化设计进行全面总结:
一、泛化架构设计基础
1. 模板方法模式的核心实现
KuiklyCoreAbsEntryBuilder 采用模板方法模式,在抽象基类中定义了代码生成的骨架流程,具体实现由子类完成:
kotlin
// KuiklyCoreAbsEntryBuilder.kt 核心结构
abstract class KuiklyCoreAbsEntryBuilder {
// 公共构建方法,定义整体流程
fun build(pagesAnnotations: List<PageInfo>): List<FileSpec> {
val fileSpecs = mutableListOf<FileSpec>()
val fileSpecBuilder = FileSpec.builder(packageName(), entryFileName())
// 添加公共注释和导入
// 调用子类的具体构建实现
build(fileSpecBuilder, pagesAnnotations)
fileSpecs.add(fileSpecBuilder.build())
return fileSpecs
}
// 模板方法,由子类实现具体构建逻辑
abstract fun build(builder: FileSpec.Builder, pagesAnnotations: List<PageInfo>)
// 抽象方法,由子类实现具体的入口文件名
abstract fun entryFileName(): String
// 抽象方法,由子类实现具体的包名
abstract fun packageName(): String
// 通用方法,可被子类使用
protected fun FunSpec.Builder.addRegisterPageRouteStatement(pages: List<PageInfo>): FunSpec.Builder {
pages.forEach { info ->
addStatement(createRegisterRouter(info.pageName, info.pageFullName))
}
return this
}
// 创建页面注册代码
private fun createRegisterRouter(pageName: String, pageQualifiedName: String): String {
return "BridgeManager.registerPageRouter(\"$pageName\") {\n" +
"$pageQualifiedName()\n" +
"}"
}
}
这种设计使得框架可以在保持统一接口的同时,支持不同平台的特定实现。
二、@Page注解与页面信息模型
1. @Page注解定义
kotlin
// Page.kt - 页面注解定义
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Page(
val name: String = "",
val supportInLocal: Boolean = false,
val moduleId: String = ""
)
@Page注解用于标记KuiklyUI中的页面组件,具有以下属性:
- name: 页面名称,用于路由注册
- supportInLocal: 是否支持内置打包,可用于按需加载优化
- moduleId: 页面所属模块ID,用于多模块架构
2. PageInfo数据类
kotlin
// PageInfo.kt - 页面信息数据类
data class PageInfo(
val pageName: String, // 页面名称
val pageFullName: String, // 页面完整类名
val packLocal: Boolean = false, // 是否本地打包
val moduleId: String = "" // 模块ID
)
PageInfo类用于在编译时代码生成过程中存储和传递页面信息,是连接@Page注解和生成代码的重要桥梁。
三、AndroidTargetEntryBuilder 的平台实现
AndroidTargetEntryBuilder 继承自 KuiklyCoreAbsEntryBuilder,实现了安卓平台特定的代码生成逻辑:
1. 核心实现细节
kotlin
open class AndroidTargetEntryBuilder : KuiklyCoreAbsEntryBuilder() {
override fun build(builder: FileSpec.Builder, pagesAnnotations: List<PageInfo>) {
// 创建实现 IKuiklyCoreEntry 接口的类
builder.addType(
TypeSpec.classBuilder(entryFileName())
.addSuperinterface(ClassName("com.tencent.kuikly.core", "IKuiklyCoreEntry"))
.addProperty(createHadRegisterNativeBridgeProperty())
.addProperty(createDelegateProperty())
.addFunction(createCallKtMethodFuncSpec())
.addFunction(createTriggerRegisterPagesFuncSpec(pagesAnnotations))
.build()
)
}
override fun entryFileName() = "KuiklyCoreEntry"
override fun packageName() = "com.tencent.kuikly.core.android"
// 安卓平台特定的方法实现
private fun createCallKtMethodFuncSpec(): FunSpec {
// 实现调用 Kotlin 方法的逻辑,包含 NativeBridge 集成
// 懒加载模式初始化 NativeBridge
}
private fun createTriggerRegisterPagesFuncSpec(pages: List<PageInfo>): FunSpec {
// 实现页面路由注册的逻辑
// 调用父类方法添加页面注册代码
}
}
2. 技术特点
- 接口实现 :生成实现
IKuiklyCoreEntry
接口的类,确保与框架其他部分的兼容性 - 委托模式 :使用委托属性 (
delegate
) 实现功能转发 - 懒加载 :通过懒加载机制优化性能,如
NativeBridge
的延迟注册 - KotlinPoet 集成:使用 KotlinPoet 库生成类型安全的 Kotlin 代码
四、AndroidMultiEntryBuilder 的多模块扩展
AndroidMultiEntryBuilder 继承自 AndroidTargetEntryBuilder,为安卓平台提供了多模块支持:
1. 多模块设计核心
kotlin
class AndroidMultiEntryBuilder(
private val isMainModule: Boolean,
private val subModules: String,
private val moduleId: String
) : AndroidTargetEntryBuilder() {
override fun build(builder: FileSpec.Builder, pagesAnnotations: List<PageInfo>) {
if (!isMainModule) {
// 子模块:生成简单的 object 对象
builder.addType(
TypeSpec.objectBuilder(entryFileName() + "_" + moduleId)
.addFunction(createSubModuleRegisterPagesFuncSpec(pagesAnnotations))
.build()
)
} else {
// 主模块:生成完整的 IKuiklyCoreEntry 实现类
super.build(builder, pagesAnnotations)
}
}
// 子模块间调用机制
private fun FunSpec.Builder.addSubModuleStatement(): FunSpec.Builder {
subModules.split("&").forEach { name ->
if(name.isNotEmpty()) {
addStatement(entryFileName() + "_" + name + ".triggerRegisterPages()")
}
}
return this
}
}
2. 多模块支持特性
- 主/子模块区分 :通过
isMainModule
标志区分生成不同类型的代码 - 模块标识 :使用
moduleId
唯一标识每个模块 - 模块依赖管理 :通过
subModules
字符串管理模块间依赖关系 - 递归注册机制:主模块可以递归调用所有子模块的注册函数
五、页面注册机制详解
1. 注册流程
KuiklyUI 的页面注册机制通过以下步骤实现:
- 开发者使用
@Page
注解标记页面类 - KSP 处理器在编译时扫描这些注解
- 收集页面信息并创建
PageInfo
对象列表 - 调用
KuiklyCoreAbsEntryBuilder
或其子类生成注册代码 - 生成的代码在运行时调用
triggerRegisterPages()
完成实际注册
2. 注册代码生成
核心注册代码通过 addRegisterPageRouteStatement
方法生成:
kotlin
// 生成的页面注册代码示例
BridgeManager.registerPageRouter("HomePage") {
com.example.HomePage()
}
BridgeManager.registerPageRouter("DetailPage") {
com.example.DetailPage()
}
这种注册方式使用 lambda 表达式作为工厂函数,每次导航到页面时都会创建新的页面实例。
六、泛化设计的优势
-
统一与灵活的平衡
- 统一的代码生成框架确保了跨平台的一致性
- 平台特定实现允许针对不同平台进行优化
-
高度可扩展性
- 新平台支持只需实现 KuiklyCoreAbsEntryBuilder 的抽象方法
- 功能扩展可以通过继承现有实现类完成
-
代码复用
- 通用代码在基类中实现,避免重复
- 平台特定代码集中在各自的实现类中
-
多模块支持
- 通过 AndroidMultiEntryBuilder 实现了应用的模块化开发
- 支持模块间的依赖管理和递归初始化
七、生成代码示例
下面是 AndroidMultiEntryBuilder 生成的主模块和子模块的完整代码示例,基于其实现逻辑进行详细展示。
1、主模块生成代码示例
当 isMainModule = true
且 subModules = "moduleA&moduleB&moduleC"
时,生成的主模块代码如下:
kotlin:com.tencent.kuikly.core.android.KuiklyCoreEntry.kt
package com.tencent.kuikly.core.android
import com.tencent.kuikly.core.IKuiklyCoreEntry
import com.tencent.kuikly.core.manager.BridgeManager
import com.tencent.kuikly.core.nvi.NativeBridge
/**
* 由 KSP 自动生成的代码,请勿手动修改
*/
class KuiklyCoreEntry : IKuiklyCoreEntry {
override var delegate: IKuiklyCoreEntry.Delegate? = null
private var hadRegisterNativeBridge: Boolean = false
override fun callKotlinMethod(
methodId: Int,
arg0: Any?,
arg1: Any?,
arg2: Any?,
arg3: Any?,
arg4: Any?,
arg5: Any?
) {
if (!hadRegisterNativeBridge) {
triggerRegisterPages()
hadRegisterNativeBridge = true
val nativeBridge = NativeBridge()
nativeBridge.delegate = object : NativeBridge.NativeBridgeDelegate {
override fun callNative(
methodId: Int,
arg0: Any?,
arg1: Any?,
arg2: Any?,
arg3: Any?,
arg4: Any?,
arg5: Any?
): Any? {
return delegate?.callNative(methodId, arg0, arg1, arg2, arg3, arg4, arg5)
}
}
BridgeManager.registerNativeBridge(arg0 as String, nativeBridge)
}
BridgeManager.callKotlinMethod(methodId, arg0, arg1, arg2, arg3, arg4, arg5)
}
override fun triggerRegisterPages() {
// 注册主模块的页面
BridgeManager.registerPageRouter("HomePage") {
com.example.app.pages.HomePage()
}
BridgeManager.registerPageRouter("MainDashboard") {
com.example.app.pages.MainDashboard()
}
// 调用所有子模块的页面注册方法
KuiklyCoreEntry_moduleA.triggerRegisterPages()
KuiklyCoreEntry_moduleB.triggerRegisterPages()
KuiklyCoreEntry_moduleC.triggerRegisterPages()
}
}
2、子模块生成代码示例
子模块 A (moduleId = "moduleA")
当 isMainModule = false
且 moduleId = "moduleA"
时,生成的子模块代码如下:
kotlin:com.tencent.kuikly.core.android.KuiklyCoreEntry_moduleA.kt
package com.tencent.kuikly.core.android
import com.tencent.kuikly.core.manager.BridgeManager
/**
* 由 KSP 自动生成的代码,请勿手动修改
*/
object KuiklyCoreEntry_moduleA {
fun triggerRegisterPages() {
// 注册子模块A的页面
BridgeManager.registerPageRouter("ModuleASettings") {
com.example.app.moduleA.pages.ModuleASettings()
}
BridgeManager.registerPageRouter("ModuleAProfile") {
com.example.app.moduleA.pages.ModuleAProfile()
}
BridgeManager.registerPageRouter("ModuleADetail") {
com.example.app.moduleA.pages.ModuleADetail()
}
// 如果子模块A还依赖其他子模块,也会在这里调用它们的注册方法
// 注:实际依赖关系由subModules参数决定
}
}
子模块 B (moduleId = "moduleB")
kotlin:com.tencent.kuikly.core.android.KuiklyCoreEntry_moduleB.kt
package com.tencent.kuikly.core.android
import com.tencent.kuikly.core.manager.BridgeManager
/**
* 由 KSP 自动生成的代码,请勿手动修改
*/
object KuiklyCoreEntry_moduleB {
fun triggerRegisterPages() {
// 注册子模块B的页面
BridgeManager.registerPageRouter("ModuleBHome") {
com.example.app.moduleB.pages.ModuleBHome()
}
BridgeManager.registerPageRouter("ModuleBList") {
com.example.app.moduleB.pages.ModuleBList()
}
// 如果子模块B还依赖其他子模块,也会在这里调用它们的注册方法
}
}
子模块 C (moduleId = "moduleC")
kotlin:com.tencent.kuikly.core.android.KuiklyCoreEntry_moduleC.kt
package com.tencent.kuikly.core.android
import com.tencent.kuikly.core.manager.BridgeManager
/**
* 由 KSP 自动生成的代码,请勿手动修改
*/
object KuiklyCoreEntry_moduleC {
fun triggerRegisterPages() {
// 注册子模块C的页面
BridgeManager.registerPageRouter("ModuleCFeature1") {
com.example.app.moduleC.pages.ModuleCFeature1()
}
BridgeManager.registerPageRouter("ModuleCFeature2") {
com.example.app.moduleC.pages.ModuleCFeature2()
}
BridgeManager.registerPageRouter("ModuleCFeature3") {
com.example.app.moduleC.pages.ModuleCFeature3()
}
// 如果子模块C还依赖其他子模块,也会在这里调用它们的注册方法
}
}
3、模块间的调用关系
KuiklyUI 框架的多模块注册流程如下:
-
主模块初始化:
- 应用启动时,系统调用
KuiklyCoreEntry.callKotlinMethod()
- 首次调用时,主模块会执行
triggerRegisterPages()
方法
- 应用启动时,系统调用
-
级联注册机制:
- 主模块的
triggerRegisterPages()
先注册自己的页面 - 然后通过
KuiklyCoreEntry_moduleX.triggerRegisterPages()
调用所有子模块的注册方法 - 子模块也可以再调用它们依赖的其他子模块(如果有的话)
- 主模块的
-
页面路由统一管理:
- 所有模块的页面都注册到同一个
BridgeManager
中 - 原生代码可以通过统一的接口访问所有注册的页面
- 所有模块的页面都注册到同一个
4、多模块设计的优势
-
代码隔离:各模块的页面注册代码独立维护,便于团队协作开发
-
按需加载:通过主模块统一触发,实现了集中式的页面注册管理
-
灵活配置 :通过
subModules
参数可以灵活配置模块间的依赖关系 -
统一接口:所有模块遵循相同的注册模式,保持了框架的一致性
-
可扩展性 :新增模块只需添加相应的
@Page
注解并在配置中添加模块ID