KuiklyUI 框架对 iOS 平台的泛化设计
1. iOS 平台泛化概述
KuiklyUI 框架通过抽象基类与平台特定实现相结合的方式,实现了对 iOS 平台的深度适配。iOS 平台的实现主要体现在 IOSTargetEntryBuilder
和 IOSMultiTargetEntryBuilder
两个核心类中,它们共同构建了一套高效的跨平台桥接机制,使 Kotlin 代码能够与 iOS 原生代码无缝通信。
iOS 平台的泛化设计具有以下特点:
- 采用典型的 iOS 委托模式(Delegate Pattern)实现跨语言调用
- 基于 Kotlin/Native 技术实现与 Objective-C/Swift 的互操作
- 支持灵活的单模块和多模块架构
- 完整的异常捕获和处理机制
2. 核心实现类分析
2.1 IOSTargetEntryBuilder - 基础平台实现
IOSTargetEntryBuilder
是 iOS 平台的基础实现类,负责生成单模块场景下的核心桥接代码:
kotlin:/Users/hfq/codes/KuiklyUI/core-ksp/src/main/kotlin/impl/IOSTargetEntryBuilder.kt
open class IOSTargetEntryBuilder : KuiklyCoreAbsEntryBuilder() {
override fun build(builder: FileSpec.Builder, pagesAnnotations: List<PageInfo>) {
builder.addType(
TypeSpec.classBuilder(entryFileName())
.addProperty(createDelegateProperty())
.addProperty(createHadRegisterNativeBridgeProperty())
.addFunction(createCallKtMethodFuncSpec(pagesAnnotations))
.addType(createDelegateTypeSpec())
.addType(createCompanionObject(pagesAnnotations))
.build()
)
}
override fun entryFileName(): String { return "KuiklyCoreEntry" }
override fun packageName(): String { return "" }
// 其他私有方法...
}
该类的核心职责是:
- 构建
KuiklyCoreEntry
类,作为 Kotlin 与 iOS 原生代码通信的桥梁 - 定义
Delegate
接口,由 iOS 原生代码实现以处理 Kotlin 到原生的调用 - 实现页面注册和方法调用的核心逻辑
- 提供异常捕获和处理机制
2.2 IOSMultiTargetEntryBuilder - 多模块支持实现
IOSMultiTargetEntryBuilder
扩展了基础实现,提供了 iOS 平台的多模块支持:
kotlin:/Users/hfq/codes/KuiklyUI/core-ksp/src/main/kotlin/impl/submodule/IOSMultiTargetEntryBuilder.kt
class IOSMultiTargetEntryBuilder(
private val isMainModule: Boolean,
private val subModules: String,
private val moduleId: String
) : IOSTargetEntryBuilder() {
override fun build(builder: FileSpec.Builder, pagesAnnotations: List<PageInfo>) {
if (!isMainModule) {
// 子模块:创建单例对象
builder.addType(
TypeSpec.objectBuilder(entryFileName() + "_" + moduleId)
.addFunction(createSubModuleRegisterPagesFuncSpec(pagesAnnotations))
.build()
)
} else {
// 主模块:创建完整的核心入口类
builder.addType(
TypeSpec.classBuilder(entryFileName())
.addProperty(createDelegateProperty())
// ... 其他属性和方法
.build()
)
}
}
// 其他方法...
}
该类通过构造参数控制生成不同类型的代码:
isMainModule
:标识是否为主模块subModules
:主模块包含的子模块列表,用&
分隔moduleId
:当前模块的唯一标识
3. 关键功能实现分析
3.1 委托模式实现
iOS 平台采用典型的委托模式实现 Kotlin 到原生的调用,核心是通过 createDelegateProperty
和 createDelegateTypeSpec
方法:
kotlin
fun createDelegateProperty(): PropertySpec {
return PropertySpec.builder(
VAR_NAME_DELEGATE, // "hrCoreDelegate"
ClassName("", HR_CORE_ENTRY_DELEGATE).copy(true) // "Delegate?"
)
.mutable()
.initializer("null")
.build()
}
fun createDelegateTypeSpec(): TypeSpec {
return TypeSpec.interfaceBuilder(HR_CORE_ENTRY_DELEGATE) // "Delegate"
.addFunction(
FunSpec.builder(AndroidTargetEntryBuilder.FUNC_NAME_CALL_NATIVE) // "callNative"
.addParameters(createKtMethodParameters())
.addModifiers(KModifier.ABSTRACT)
.returns(Any::class.asTypeName().copy(nullable = true))
.build()
)
.build()
}
这种设计允许 iOS 原生代码通过实现 Delegate
接口,并将其赋值给 hrCoreDelegate
属性,从而接收来自 Kotlin 的调用。
3.2 方法调用与注册机制
createCallKtMethodFuncSpec
方法是整个桥接机制的核心,负责处理从原生到 Kotlin 的方法调用:
kotlin
fun createCallKtMethodFuncSpec(pagesAnnotations: List<PageInfo>): FunSpec {
return FunSpec.builder(FUNC_NAME_CALL_KT_METHOD)
.addParameters(createKtMethodParameters()) // 方法ID和6个参数
.addStatement("try {")
// 初始化和页面注册
.addStatement("if (!BridgeManager.isDidInit()) {\n" +
"BridgeManager.init()\n")
.addStatement("$METHOD_NAME_TRIGGER_REGISTER_PAGES()") // "triggerRegisterPages()"
.addStatement("}\n")
// 注册NativeBridge
.addStatement(" if (!hadRegisterNativeBridge) {\n" +
" hadRegisterNativeBridge = true\n" +
" val nativeBridge = NativeBridge()\n" +
" nativeBridge.iosNativeBridgeDelegate = object : NativeBridge.IOSNativeBridgeDelegate {\n" +
" override fun callNative(...) {\n" +
" return hrCoreDelegate?.callNative(...)\n" +
" }\n" +
" }\n" +
" BridgeManager.registerNativeBridge(arg0 as String, nativeBridge)\n" +
" }")
// 调用Kotlin方法
.addStatement("BridgeManager.callKotlinMethod(methodId, arg0, arg1, arg2, arg3, arg4, arg5)")
// 异常处理
.addStatement("}")
.addStatement("catch(t: Throwable) {")
.addStatement("BridgeManager.callExceptionMethod(t.stackTraceToString())")
.addStatement("}")
.build()
}
该方法实现了以下关键功能:
- 首次调用时初始化 BridgeManager 并注册页面路由
- 创建并注册 NativeBridge 实例,设置 iOSNativeBridgeDelegate
- 委托实现将 Kotlin 对原生的调用转发给 iOS 实现的 Delegate
- 完整的异常捕获和处理机制
3.3 页面注册与检查
createCompanionObject
方法创建了伴生对象,提供页面注册和检查功能:
kotlin
private fun createCompanionObject(pagesAnnotations: List<PageInfo>): TypeSpec {
return TypeSpec.companionObjectBuilder()
.addProperty(
PropertySpec.builder(PROP_NAME_HAD_REGISTER_PAGES, Boolean::class.asTypeName())
.mutable(true)
.addModifiers(KModifier.PRIVATE)
.initializer("false")
.build()
)
.addFunction(
FunSpec.builder(METHOD_NAME_PAGE_EXIST)
.addParameter(ParameterSpec.builder(PARAM_NAME_PAGE_NAME, String::class.asTypeName()).build())
.addStatement("$METHOD_NAME_TRIGGER_REGISTER_PAGES()")
.addStatement("return BridgeManager.$METHOD_NAME_PAGE_EXIST($PARAM_NAME_PAGE_NAME)")
.returns(Boolean::class.asTypeName())
.build()
)
.addFunction(
FunSpec.builder(METHOD_NAME_TRIGGER_REGISTER_PAGES)
.addModifiers(KModifier.PRIVATE)
.addStatement("if(!$PROP_NAME_HAD_REGISTER_PAGES) {")
.addRegisterPageRouteStatement(pagesAnnotations)
.addStatement("$PROP_NAME_HAD_REGISTER_PAGES=true")
.addStatement("}")
.build()
)
.build()
}
该伴生对象的主要功能:
- 通过
triggerRegisterPages
方法注册所有页面路由 - 通过
isPageExist
方法检查指定页面是否存在 - 使用
hadRegisterPages
标志确保页面只注册一次
3.4 多模块支持机制
多模块支持是 iOS 平台实现的重要特性,通过 createSubModuleRegisterPagesFuncSpec
和 addSubModuleStatement
方法实现:
kotlin
private fun createSubModuleRegisterPagesFuncSpec(pagesAnnotations: List<PageInfo>): FunSpec {
return FunSpec.builder("triggerRegisterPages")
.addRegisterPageRouteStatement(pagesAnnotations)
.addSubModuleStatement()
.build()
}
private fun FunSpec.Builder.addSubModuleStatement(): FunSpec.Builder {
subModules.split("&").forEach { moduleName ->
val name = moduleName.trim()
if(name.isNotEmpty()) {
addStatement(entryFileName() + "_" + name + ".triggerRegisterPages()")
}
}
return this
}
多模块机制的工作原理:
- 主模块通过
subModules
参数指定所有子模块,以&
分隔 - 主模块在初始化时,通过
addSubModuleStatement
方法调用所有子模块的triggerRegisterPages
方法 - 每个子模块生成名为
KuiklyCoreEntry_${moduleId}
的单例对象,只负责注册自己的页面路由
4. 平台特性适配
iOS 平台的泛化设计充分考虑了其独特的技术特性:
4.1 委托模式的应用
iOS 开发中广泛使用委托模式(Delegate Pattern),KuiklyUI 框架在 iOS 平台的实现也遵循了这一设计模式:
- 通过
hrCoreDelegate
属性接收 iOS 原生代码设置的委托对象 - 定义
Delegate
接口规范原生代码需要实现的方法 - 使用
iosNativeBridgeDelegate
处理反向调用
这种设计使得 Kotlin 代码能够无缝集成到 iOS 开发环境中,符合 iOS 开发者的习惯。
4.2 单例对象的使用
在多模块场景下,子模块生成的是单例对象而非类:
kotlin
TypeSpec.objectBuilder(entryFileName() + "_" + moduleId)
.addFunction(createSubModuleRegisterPagesFuncSpec(pagesAnnotations))
.build()
这一设计简化了子模块的访问方式,无需创建实例即可调用其方法,符合 Kotlin/Native 在 iOS 平台上的使用惯例。
4.3 异常处理机制
iOS 平台实现了完整的异常捕获和处理机制:
kotlin
try {
// 核心逻辑
} catch(t: Throwable) {
BridgeManager.callExceptionMethod(t.stackTraceToString())
}
通过 BridgeManager.callExceptionMethod
将 Kotlin 层的异常传递到原生层,便于统一的错误追踪和处理。
5. 生成代码示例
5.1 单模块场景生成代码
在单模块场景下,IOSTargetEntryBuilder
会生成类似以下的代码:
kotlin
class KuiklyCoreEntry {
var hrCoreDelegate: Delegate? = null
private var hadRegisterNativeBridge: Boolean = false
fun callKotlinMethod(methodId: Int, arg0: Any?, arg1: Any?, arg2: Any?, arg3: Any?, arg4: Any?, arg5: Any?) {
try {
if (!BridgeManager.isDidInit()) {
BridgeManager.init()
triggerRegisterPages()
}
if (!hadRegisterNativeBridge) {
hadRegisterNativeBridge = true
val nativeBridge = NativeBridge()
nativeBridge.iosNativeBridgeDelegate = object : NativeBridge.IOSNativeBridgeDelegate {
override fun callNative(methodId: Int, arg0: Any?, arg1: Any?, arg2: Any?, arg3: Any?, arg4: Any?, arg5: Any?): Any? {
return hrCoreDelegate?.callNative(methodId, arg0, arg1, arg2, arg3, arg4, arg5)
}
}
BridgeManager.registerNativeBridge(arg0 as String, nativeBridge)
}
BridgeManager.callKotlinMethod(methodId, arg0, arg1, arg2, arg3, arg4, arg5)
} catch(t: Throwable) {
BridgeManager.callExceptionMethod(t.stackTraceToString())
}
}
interface Delegate {
fun callNative(methodId: Int, arg0: Any?, arg1: Any?, arg2: Any?, arg3: Any?, arg4: Any?, arg5: Any?): Any?
}
companion object {
private var hadRegisterPages: Boolean = false
fun isPageExist(pageName: String): Boolean {
triggerRegisterPages()
return BridgeManager.isPageExist(pageName)
}
private fun triggerRegisterPages() {
if(!hadRegisterPages) {
BridgeManager.registerPageRoute("PageA", PageA::class)
BridgeManager.registerPageRoute("PageB", PageB::class)
hadRegisterPages = true
}
}
}
}
5.2 多模块场景生成代码
主模块生成代码
kotlin
// 主模块代码 (isMainModule = true, subModules = "moduleA&moduleB")
class KuiklyCoreEntry {
// ... 与单模块相同的属性和方法
companion object {
private var hadRegisterPages: Boolean = false
fun isPageExist(pageName: String): Boolean {
triggerRegisterPages()
return BridgeManager.isPageExist(pageName)
}
private fun triggerRegisterPages() {
if(!hadRegisterPages) {
// 注册主模块页面
BridgeManager.registerPageRoute("MainPage", MainPage::class)
// 调用子模块注册
KuiklyCoreEntry_moduleA.triggerRegisterPages()
KuiklyCoreEntry_moduleB.triggerRegisterPages()
hadRegisterPages = true
}
}
}
}
子模块生成代码
kotlin
// 子模块代码 (isMainModule = false, moduleId = "moduleA")
object KuiklyCoreEntry_moduleA {
fun triggerRegisterPages() {
// 注册子模块页面
BridgeManager.registerPageRoute("ModuleAPage1", ModuleAPage1::class)
BridgeManager.registerPageRoute("ModuleAPage2", ModuleAPage2::class)
}
}
6. 泛化设计的优势
KuiklyUI 框架对 iOS 平台的泛化设计具有以下优势:
-
统一的抽象层 :通过继承自
KuiklyCoreAbsEntryBuilder
,iOS 平台实现与其他平台保持一致的核心接口 -
平台特性适配:充分利用 iOS 开发中的委托模式和单例对象,符合 iOS 开发习惯
-
模块化支持 :通过
IOSMultiTargetEntryBuilder
支持灵活的模块化架构 -
完整的异常处理:全链路的异常捕获和上报机制,确保稳定性
-
高效的跨语言调用:基于 Kotlin/Native 技术实现高效的跨语言调用