在KMP iOS模块用Kotlin调用UIActivityViewController分享文本的问题
关于KMP iOS端文本分享的问题解答
「[ShareSheet] connection invalidated」日志说明
这个是iOS系统的正常调试日志,和KMP无关。当UIActivityViewController(分享弹窗)关闭后,系统会销毁其底层的IPC连接以回收资源,该提示不影响功能运行,无需特殊处理。
Kotlin与Swift属性名称差异原因
主要源于Kotlin/Native的Objective-C桥接规则:
- 命名风格转换:Objective-C采用下划线分隔的命名规范,而Kotlin和Swift使用驼峰式,桥接层会自动将Objective-C的命名转为Kotlin的驼峰风格(反之亦然),导致部分属性/方法名看起来不一致。
- Swift独有API的桥接限制:未标记
@objc的Swift专属API无法直接被Kotlin调用,若通过@objc暴露,可能会为了兼容Objective-C的命名规则调整名称。 - 关键字冲突规避:如果Swift属性名与Kotlin关键字重名,桥接层会自动重命名该属性(比如Swift的
class属性在Kotlin中会被改为clazz)。
更安全的文本分享实现方案
当前直接调用旧API的方式可能存在内存泄漏、未适配多设备或线程不安全等问题,推荐基于KMP的expect/actual机制实现,同时规范iOS端的UI生命周期管理:
1. 跨平台抽象接口(commonMain)
expect class ShareManager { fun shareText(text: String, hostViewController: Any?) }
2. iOS端具体实现(iosMain)
import platform.UIKit.* import platform.Foundation.NSString import platform.darwin.dispatch_async import platform.darwin.dispatch_get_main_queue actual class ShareManager { // 持有分享控制器的强引用,避免提前被回收 private var currentShareController: UIActivityViewController? = null actual fun shareText(text: String, hostViewController: Any?) { val vc = hostViewController as? UIViewController ?: return // 确保UI操作在主线程执行 dispatch_async(dispatch_get_main_queue()) { val activityItems = listOf(text as NSString) val shareController = UIActivityViewController(activityItems, null) // 适配iPad的popover展示(必须设置,否则iPad上会崩溃) shareController.popoverPresentationController?.apply { sourceView = vc.view sourceRect = vc.view.bounds } // 分享完成后释放引用,避免内存泄漏 shareController.completionWithItemsHandler = { _, _, _, _ -> currentShareController = null } currentShareController = shareController vc.presentViewController(shareController, animated = true, completion = null) } } }
方案优势
- 跨平台兼容:通过
expect/actual抽象,可在Android端实现对应的分享逻辑,保持业务逻辑的一致性。 - 内存安全:持有分享控制器的强引用直到分享完成,避免因对象提前回收导致的异常。
- 多设备适配:处理了iPad上的popover展示要求,避免崩溃。
- 线程安全:强制在iOS主线程执行UI操作,符合iOS的UI线程规则。
内容的提问来源于stack exchange,提问作者Eel
相关产品推荐
相关产品推荐

