KMM Compose如何实现共享模块与iOS原生的回调及结果返回?
KMM共享模块调用iOS原生后台操作并获取结果的解决方案
1. 定义共享模块的平台抽象接口
在commonMain目录下创建平台操作的抽象类/函数,用expect声明需要各平台实现的方法:
// commonMain/kotlin/[你的包名]/PlatformOperations.kt import kotlinx.coroutines.suspendCancellableCoroutine // 声明后台处理数据的挂起函数,适配异步操作 expect suspend fun processBackgroundData(input: String): String // 可选:如果需要获取平台信息,也可以用expect/actual expect fun getPlatform(): String
2. 实现Android端的具体逻辑
在androidMain目录下实现actual函数:
// androidMain/kotlin/[你的包名]/PlatformOperations.kt import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext actual suspend fun processBackgroundData(input: String): String { // 在IO线程执行后台操作,避免阻塞UI return withContext(Dispatchers.IO) { // 模拟耗时操作,替换为实际业务逻辑 Thread.sleep(1000) "Android 处理结果: $input" } } actual fun getPlatform(): String = "Android"
3. 实现iOS端的原生逻辑
第一步:编写iOS原生Swift工具类
在iOS项目中创建Swift文件,实现后台操作的原生逻辑:
// iOS项目/PlatformHelpers.swift import Foundation @objc class PlatformHelpers: NSObject { // 后台队列执行操作,通过回调返回结果 @objc static func processBackgroundData(_ input: String, completion: @escaping (String) -> Void) { DispatchQueue.global(qos: .background).async { // 模拟耗时操作,替换为实际iOS原生逻辑 Thread.sleep(forTimeInterval: 1) let result = "iOS 处理结果: \(input)" // 切回主队列返回结果(如果需要更新UI,否则可直接调用completion) DispatchQueue.main.async { completion(result) } } } @objc static func getPlatform() -> String { return "iOS" } }
第二步:在共享模块iosMain中对接原生代码
将Swift的回调风格代码转换为Kotlin协程,实现actual函数:
// iosMain/kotlin/[你的包名]/PlatformOperations.kt import kotlinx.coroutines.suspendCancellableCoroutine actual suspend fun processBackgroundData(input: String): String = suspendCancellableCoroutine { continuation -> PlatformHelpers.processBackgroundData(input) { result -> continuation.resume(result) } } actual fun getPlatform(): String = PlatformHelpers.getPlatform()
4. 修改共享模块UI组件调用逻辑
更新Compose组件,在协程作用域内调用后台操作函数:
@Composable fun App() { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.SpaceAround ) { var counter by remember { mutableIntStateOf(0) } var processResult by remember { mutableStateOf<String?>(null) } Button( onClick = { counter++ // 启动协程执行后台操作 LaunchedEffect(counter) { val result = processBackgroundData("来自 ${getPlatform()} 的请求") processResult = result android.util.Log.d("TAG", "处理结果: $result") } } ) { Text("触发后台操作") } Text("点击次数: $counter") processResult?.let { Text("后台返回结果: $it") } } }
5. 简化iOS端UI层代码
移除原有的回调参数,直接初始化Compose视图:
import UIKit import SwiftUI import shared struct ComposeView: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController { return Main_iosKt.MainViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } struct ContentView: View { var body: some View { ComposeView() .ignoresSafeArea(.all, edges: .bottom) } }
关键注意点
- 后台操作必须放在对应平台的后台线程执行,避免阻塞UI线程
- 用Kotlin协程的
suspendCancellableCoroutine将iOS的回调风格代码转为协程,适配共享模块的挂起函数 expect函数的签名必须与各平台actual函数完全一致- 如果需要处理取消逻辑,可在
suspendCancellableCoroutine中添加continuation.invokeOnCancellation
内容的提问来源于stack exchange,提问作者Bekzhan Omirzak
相关产品推荐
相关产品推荐

