本文技术路线与案例参考自 Krzysztof Dąbrowski 在 ProAndroidDev 的
《Multiplatform — built-in SwiftPM import with Kotlin 2.4.x》,
并结合 iOS/Android 应用上架、审核说明、离线/P2P 场景 进行改写,方便在 WordPress 发布与团队落地参考。

2026 年(原文写作语境下的“未来视角”)做跨平台移动应用,共享业务逻辑与 UI 已是常见诉求;Kotlin Multiplatform(KMP/CMP)让 Android 与 iOS 共享代码变得更自然。
但**“能跑”不等于“能稳定发版/过审”**——尤其当你依赖:

  • 本地网络发现
  • 蓝牙 / Nearby Connections
  • 离线消息/音视频
  • P2P 直连
  • 无网协同

这类能力时,商店(App Store / Google Play / 国内商店)会关注:权限用途、数据流向、是否上传统计/位置、是否仅本机/同网络通信。

本文以“将既有 Flight Chat(类 Nearby/离线聊天)集成迁移到 Kotlin 2.4.x + SwiftPM 导入”为线索,讲清楚:

  • Kotlin 侧如何接 SwiftPM / 本地包
  • Objective-C 兼容与模块边界
  • Xcode/CI 还要做什么
  • 提交上架时如何说明“无网/近场/本地网络”能力,减少被拒风险

场景:离线聊天与 Nearby 能力

Flight Chat 可理解为“无网/弱网下,通过本地网络或近场能力在设备间通信”的示例/产品形态(类似借助 Nearby/MQTT/本地桥接思路)。
原生 SDK 侧常涉及:

  • Android:Nearby Connections / 本地网络
  • iOS:对应 Nearby/本地网络/蓝牙 能力(以及 Objective-C/Swift 暴露面)
  • 共享层:消息状态机、重连/重试、会话管理、错误码、UI 状态映射

上架关联点:
如果你在 App Store 说“无需联网即可聊天/协作”,审核员会看你是否:

  • 真的走本地/近场
  • 没偷偷走服务器上传
  • 对“本地网络/蓝牙”权限说明清晰
  • 提供可复现的测试步骤/录屏

Swift 互操作:底层仍是 Objective-C 兼容问题

原集成可能依赖 cinterop/手动桥接来消费 Swift/本地接口。
重点不是“Kotlin 直接吃任意 Swift”,而是:

  • Kotlin/Native 与 Swift/OC 的互操作受 Objective-C 兼容表面 约束
  • 不是所有 Swift 语法/泛型/协议都能被自动暴露
  • 常见做法:把需要跨边界的 API 设计成 OC 兼容包装层(wrapper)
  • 在 Kotlin 侧消费这些稳定模块,而非直接咬“完整 Swift SDK 全部符号”

Nearby SDK 相关能力常包含 Swift 实现与本地/跨平台产物,Kotlin 侧通过封装暴露给共享代码;广告/发现/连接状态等由原生侧驱动,共享层只处理“业务语义”。


上架提示:桥接越“自研黑盒”,审核沟通越难;
建议把“本地通信边界”做成可解释、可日志、可关闭的模块。


Kotlin 2.4.x + SwiftPM 导入:坑在“模块/包名/解析”

从 Kotlin 2.4 附近版本开始,对 SwiftPM 导入支持更“内置/可走标准路径”,但并非“零配置”:

  • SwiftPM 包与 Kotlin 调用的“包/模块”并非完全同一概念
  • SwiftPM import ≠ Kotlin 突然能消费任意 Swift
  • 仍要关注 Objective-C 兼容 API
  • 升级 Kotlin 期间可能遇到“模块找不到/链接失败/解析锁不一致”
  • 某些场景下需要本地 Swift 包 + 显式 Gradle 配置,不要依赖自动发现

常见报错方向(概括):

  • module 'XXX' not found
  • SwiftPM 解析与 Xcode 侧不一致
  • 生成绑定指向旧符号/旧包名
  • CI 上能跑、Xcode Archive 失败
  • TestFlight 安装后崩溃(链接/权限/运行期缺失)

构建配置:本地 Swift 包 / 显式声明

实践中可让 SwiftPM/桥接以“本地包”方式存在,Gradle 侧明确指向源/依赖,避免魔法发现。
上架提醒:若最终二进制包含本地网络发现/广播,建议:

在“功能描述/审核备注”写清“仅本机与同 Wi‑Fi/蓝牙直连设备通信、不上传服务器”

提供测试账号/测试步骤(如两设备同网络、开启权限后发送消息)

对“无网也能用”的功能,准备录屏,方便审核员理解


Xcode 绑定:不是只配 Kotlin 就完事

Kotlin 生成中间包/绑定后,iOS 应用仍需在 Xcode 侧:

  • 引入对应 native 依赖/链接的包
  • 更新 SwiftPM 解析锁/依赖版本
  • 在 CI 中显式设置相关路径/项目文件
  • 注意生成的包名与 Kotlin 侧命名变化(避免链接错旧符号)
  • 处理签名、能力(Capabilities)、隐私清单(如适用)

这步是“应用能打包、能提交、能在真机跑”的关键;否则容易出现“本地能跑、归档失败 / TestFlight 装上去崩 / 审核时功能不可复现”。


迁移“值不值”(从发版/上架角度)

从作者经验与落地视角看:

  • 初次迁移可工作,能移除旧桥接、走更标准 SwiftPM 路径
  • 后续 Kotlin 版本迭代需要跟进(Kotlin 2.4.x 时间窗相关)
  • swift-export/Kotlin 对 Swift 包导入仍在演进,文档与“开箱即用”程度有限
  • 若你现有集成稳定、能过审、能发版,不一定值得为“纯技术替换”强行重做
  • 若你正做 新项目/新模块/需要长期共享逻辑/准备多端上架,提前走这条线能省重复工作

与上架收益直接挂钩的点

  1. 减少双端重复实现 → 减少“Android 能过 / iOS 被拒因行为差异”的扯皮
  2. 共享连接状态机/错误码/重试策略 → 审核反馈可定位到统一逻辑
  3. 离线能力明确 → 适合出行、展会、弱网、教育/协作等场景,作为上架卖点
  4. 构建更标准(SwiftPM) → 降低发版前“换机器打包失败”的概率
  5. 权限与隐私说明可对齐 → 避免“本地网络用途说不清”被拒
  6. 日志/诊断开关统一 → 给审核/客服/线上问题定位留证据

审核/上架检查清单(推荐直接照用)

  • 应用描述与“离线/近场/本地网络”行为一致
  • iOS:本地网络权限用途字符串(NSLocalNetworkUsageDescription)清晰
  • 蓝牙/定位相关说明(如触发)写清“仅用于设备发现,不上传”
  • 提供两设备测试步骤 / 测试账号
  • 准备“无网演示录屏”
  • 共享逻辑层有版本号/日志标识,便于定位
  • CI 能复现 Xcode Archive / Gradle 产物
  • 不在后台静默扫描/上传,避免被判定为异常跟踪
  • 隐私政策与数据流向一致(即使只走本地)
  • 对商店备注写“本功能不依赖远端服务器中转”

小结(给准备上架的团队)

  • KMP/CMP 适合承载“业务核心”,但平台 SDK(Nearby/本地网络/蓝牙)仍需原生桥接
  • Kotlin 2.4.x + SwiftPM import 是可行方向,但本质仍要处理 Objective-C 兼容 / 模块 / 链接
  • 推荐用本地 Swift 包 + 显式 Gradle/Xcode 配置,别依赖自动发现
  • 对“离线/P2P/近场”类 App:
    • 提前准备 权限说明、测试步骤、录屏、日志开关
    • 在 App Store / Google Play / 国内商店提交时保持“功能—说明—代码行为”一致
    • 把共享逻辑与桥接边界写清,能显著加快审核沟通与版本迭代

如果你也在做 Kotlin Multiplatform + iOS 原生 SDK + 上架合规 的落地,希望这篇整理能帮你少走弯路——尤其在“从能跑”到“能稳定发版/过审”这一段。