Skip to content

CMP 共享 UI 开发指导 ​

项目约定,自 2026-10-26 起适用于所有 UI 的后续演进。

目标 ​

Android 和桌面优先使用同一套 Compose Multiplatform 呈现。Windows 与 macOS 使用同一个 desktop-app,共同消费共享组件。修复共享界面时,让所有消费端在重新构建后获得同一份修改。

共享覆盖页面结构、组件、状态模型、状态派生、交互规则和文案语义。代码放在共享目录但只有一个端 使用,或者两个页面仅使用同一批基础控件,都不足以证明整个页面已共享。

当前仓库是渐进迁移状态:core-ui 已共享部分界面,但仍有 Android 页面与桌面页面分别实现。 这些存量实现是迁移对象,不作为新页面继续分叉的模板。

放置边界 ​

内容默认位置
Compose 页面、列表、卡片、标签栏、搜索与筛选呈现core-ui/src/commonMain
跨端业务规则、排序、过滤、状态合并等纯逻辑对应的 core-domain、core-source 或现有共享功能模块
Android 导航、Activity、Hilt 装配、权限、系统文件选择app 或相应 androidMain
桌面入口、窗口、文件选择、运行时与服务装配现有桌面模块
WebView、原生播放、安装更新等系统能力相应平台适配器,通过接口或回调注入

共享呈现消费明确的状态和事件回调,保持对 Activity、Hilt、Swing、java.io.File、平台资源 ID 和平台运行时的隔离。已有 Android 页面若绑定这些对象,先拆出所需的呈现边界,而非重写桌面版本。 系统差异可使用接口、回调或适合该边界的 expect/actual,无需为每个差异新增框架。

共享文案优先使用项目现有的 UiStrings/uiString 与 Android 资源目录。平台说明使用平台侧文案, 避免把 Windows 的运行时术语带入所有平台的共用流程。

实施顺序 ​

现有页面的盘点、优先级与分批验收见 CMP UI 收敛计划。执行具体批次前复核其工作树快照与源码依据。

  1. 查现有实现。 定位 Android 页面、桌面对应页面和 core-ui 组件,记录状态来源、操作及平台依赖。
  2. 确定最小共享边界。 优先提取真实页面或具有完整交互语义的组件;仅因文件太大而拆分,不能解决重复实现。
  3. 提取并接回 Android。 把可共享呈现放入 commonMain,让原 Android 页面调用它,保持既有行为。
  4. 接入桌面。 桌面提供状态与系统操作;页面布局和相同操作继续调用共享实现。移除本次被替换的重复呈现。
  5. 验证消费端。 编译受影响的 Android 和桌面目标;检查共享交互与各端适配,记录实际运行过的平台。

修改存量页面时按当前功能范围逐步迁移,无需一次重写整应用。尚未收敛的部分应明确记录,后续继续 迁移;不以“以后会共享”为理由再新增一套同功能页面。

合理的平台差异 ​

  • 手机单栏、平板或桌面分栏,优先通过窗口约束与共享自适应布局表达。
  • 触摸、鼠标、键盘和遥控器操作,接入同一状态与事件,保持可访问性和操作结果一致。
  • 文件选择、权限、系统菜单、窗口、浏览器和原生播放保留平台实现,共享页面通过能力与回调消费。
  • 平台暂不支持的能力由宿主明确声明,共享页面提供合适的可用状态与说明。

平台实现的差异应有具体的系统 API、能力或交互依据。单纯为了在桌面上运行,不能成为复制一套页面、 状态机或业务规则的依据。实现中把系统判断集中在能力边界,页面消费能力而非散布操作系统分支。

当前 iOS 使用原生 UI,core-ui 尚未配置 iOS 目标;本规则要求所有 UI 改动先评估共享, 不代表现有 SwiftUI 页面已经能直接消费 CMP。iOS 继续共享适用的业务与数据模型,UI 目标迁移需要 在相应任务中明确处理,而不是在普通页面修复中顺带重写。

完成标准 ​

  • 能指出共享实现的具体位置,以及 Android/桌面各自的调用入口。
  • 共同的页面结构和交互修改进入共享实现;平台侧保留的部分有明确职责。
  • 保留或验证搜索、筛选、选择、展开、安装、删除确认及状态恢复等本次涉及的行为。
  • UI 改动检查宽窄窗口、滚动和输入方式;提供实际截图或交互测试结果。
  • 列出编译、测试和实际运行的平台。Mac 验证通过不等于 Windows 系统适配已回归。
  • 描述共享范围时区分组件共享、页面共享与功能共享,不把局部提取宣称为全应用共享。

项目结构依据:Kotlin Multiplatform 官方建议。

Documentation for Kototoro