kuikly core-ksp 安卓

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 的页面注册机制通过以下步骤实现:

  1. 开发者使用 @Page 注解标记页面类
  2. KSP 处理器在编译时扫描这些注解
  3. 收集页面信息并创建 PageInfo 对象列表
  4. 调用 KuiklyCoreAbsEntryBuilder 或其子类生成注册代码
  5. 生成的代码在运行时调用 triggerRegisterPages() 完成实际注册

2. 注册代码生成

核心注册代码通过 addRegisterPageRouteStatement 方法生成:

kotlin 复制代码
// 生成的页面注册代码示例
BridgeManager.registerPageRouter("HomePage") {
    com.example.HomePage()
}

BridgeManager.registerPageRouter("DetailPage") {
    com.example.DetailPage()
}

这种注册方式使用 lambda 表达式作为工厂函数,每次导航到页面时都会创建新的页面实例。

六、泛化设计的优势

  1. 统一与灵活的平衡

    • 统一的代码生成框架确保了跨平台的一致性
    • 平台特定实现允许针对不同平台进行优化
  2. 高度可扩展性

    • 新平台支持只需实现 KuiklyCoreAbsEntryBuilder 的抽象方法
    • 功能扩展可以通过继承现有实现类完成
  3. 代码复用

    • 通用代码在基类中实现,避免重复
    • 平台特定代码集中在各自的实现类中
  4. 多模块支持

    • 通过 AndroidMultiEntryBuilder 实现了应用的模块化开发
    • 支持模块间的依赖管理和递归初始化

七、生成代码示例

下面是 AndroidMultiEntryBuilder 生成的主模块和子模块的完整代码示例,基于其实现逻辑进行详细展示。

1、主模块生成代码示例

isMainModule = truesubModules = "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 = falsemoduleId = "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 框架的多模块注册流程如下:

  1. 主模块初始化

    • 应用启动时,系统调用 KuiklyCoreEntry.callKotlinMethod()
    • 首次调用时,主模块会执行 triggerRegisterPages() 方法
  2. 级联注册机制

    • 主模块的 triggerRegisterPages() 先注册自己的页面
    • 然后通过 KuiklyCoreEntry_moduleX.triggerRegisterPages() 调用所有子模块的注册方法
    • 子模块也可以再调用它们依赖的其他子模块(如果有的话)
  3. 页面路由统一管理

    • 所有模块的页面都注册到同一个 BridgeManager
    • 原生代码可以通过统一的接口访问所有注册的页面

4、多模块设计的优势

  1. 代码隔离:各模块的页面注册代码独立维护,便于团队协作开发

  2. 按需加载:通过主模块统一触发,实现了集中式的页面注册管理

  3. 灵活配置 :通过 subModules 参数可以灵活配置模块间的依赖关系

  4. 统一接口:所有模块遵循相同的注册模式,保持了框架的一致性

  5. 可扩展性 :新增模块只需添加相应的 @Page 注解并在配置中添加模块ID

相关推荐
Tfly__6 小时前
Ubuntu 20.04 安装Aerial Gym Simulator - 基于 Gym 的无人机强化学习仿真器
linux·人工智能·ubuntu·github·无人机·强化学习·运动规划
CoderJia程序员甲8 小时前
GitHub 热榜项目 - 日榜(2025-10-13)
ai·开源·大模型·github·ai教程
uhakadotcom9 小时前
coze的AsyncTokenAuth和coze的TokenAuth有哪些使用的差异?
后端·面试·github
平平无奇。。。10 小时前
版本控制器之Git理论与实战
linux·git·gitee·github
kingg11 小时前
【征文计划】基于 Rokid JSAR 的 2D 粒子画廊实现:从技术概述到核心代码解析
github
绝无仅有11 小时前
面试真实经历某商银行大厂Java问题和答案总结(一)
后端·面试·github
绝无仅有11 小时前
面试真实经历某商银行大厂Java问题和答案总结(二)
后端·面试·github
whysqwhw11 小时前
KuiklyUI core-ksp 模块分析
github
whysqwhw11 小时前
KuiklyUI 架构文档
github