状态:提案 / 渐进执行基线(2026-08-20)。本文区分“当前事实”“目标结构”和“计划门禁”;未创建的模块与 Gradle task 都不是现有 API。
目标是在不牺牲 Android 行为、阅读性能和规则兼容性的前提下,把仓库演进为可验证的 Kotlin Multiplatform / Compose Multiplatform 工程:
非目标:不一次性重写 :app;不承诺首个非 Android 目标功能齐平;不把所有代码移入 commonMain;不以
Compose 替换成熟阅读器渲染为前置;不在同一批同时替换数据库、网络、导航、DI、UI 和模块系统;不照搬 Now in
Android 的模块数量。
设计参考:
api/impl、core 模块和
convention plugin
思路,以及其 架构说明
与 模块化说明。2026-08-20 盘点快照:
:app、:modules:book、:modules:rhino、:baselineprofile;modules/web 独立构建。app/src/main/java/io/legado/app 约有 803 个 UI Kotlin 文件,UI、领域、数据、平台服务仍集中在 :app。domain/ 中仍存在 Android import、File、InputStream、java.time、JCA 等 JVM 类型,不满足直接搬入
commonMain 的条件。verifyConfigArchitecture、lint、unit test、debug assemble 的 CI 门禁。:modules:book 的解析职责相对独立,但源码以 Java/JDK API 为主且含少量 Android
API,适合作为早期依赖审计与边界试点,不能直接视为 commonMain;:modules:rhino 依赖 Rhino、OkHttp 和
JVM 生态,应先作为平台实现保留。docs/dev/mad-modernization-plan.md 已确立“行为优先、基线棘轮、阅读器渲染岛”的纪律,本路线不能推翻它。docs/dev/feature-first-structure.md
,现有目录到 canonical owner 的初始映射见 docs/dev/feature-catalog.md;它们是本路线进入真实 Gradle
模块前的过渡规范。盘点数字会变化。实施前重新运行 inventory,不把数字写进自动门禁。
目标结构是方向图,不要求一次创建全部模块:
build-logic/convention/ # 模块类型、编译、Compose、测试、lint 约定
app/android/ # Android Application、DI、服务与兼容入口
app/desktop/ # 首个低成本非 Android 证明宿主
app/ios/ # capability 与产品范围成熟后再创建
core/model/ # 可序列化领域值
core/domain/ # Gateway、UseCase、纯规则
core/platform/ # Clock、FileAccess、RuleEngine 等窄契约
core/data/ # Repository 接口与可共享组合逻辑
core/designsystem/ # CMP tokens、theme、稳定基础组件
core/ui/ # 跨 Feature UI
feature/<domain>/ # presentation、Feature UI、内部 DI
feature/<domain>/api/ # 仅在真实跨模块契约出现后拆分
feature/<domain>/impl/ # 与 api 成对且有真实消费者时存在
platform/android/{database,network,ruleengine,services,reader}/
platform/jvm/ruleengine/ # Rhino 可复用时的 JVM 实现
modules/{book,rhino,web}/ # 现有能力渐进演进
impl 和平台实现。api 不依赖其他 Feature;Feature impl 只能依赖其他 Feature 的 api,不能依赖其 impl。commonMain 不依赖 Android、JDK、Room DAO、文件 URI、资源 ID 或平台服务类型。api 只暴露真实稳定契约;默认使用 implementation,需要下游编译可见时才使用 Gradle api。core:common 或 utils。跨 Feature 复用必须有稳定职责名称。commonMain:平台无关实现;至少由一个非 Android target 编译,才算完成共享。commonTest:领域不变量、序列化、Repository 组合、状态归约和规则契约测试。androidMain:Context、Room/SQLite 驱动、服务、通知、URI、Cronet/OkHttp、Activity 兼容等。desktopMain / iosMain:只实现 capability matrix 承诺的能力;不支持项显式返回不可用状态。expect/actual。expect class URL/File/InputStream、OkHttp API 镜像或 Any
类型擦除维持旧公开签名;先改成领域值、source/sink、request/response 或 capability 契约。每新增 target,先在 PR 中更新矩阵;不允许用空实现把红格伪装成绿格。
| 能力 | Android | Desktop/JVM 试点 | iOS 候选 | 初始策略 |
|---|---|---|---|---|
| 领域模型 / 纯规则 / UDF reducer | 支持 | 支持 | 支持 | 第一批 commonMain |
| TXT/EPUB 解析 | 支持 | 待验证 | 待验证 | 先审计 modules:book 的 Android/JVM API |
| Room 数据 | 支持 | 待 PoC | 待 PoC | 先抽 Gateway,保留 Android actual |
| HTTP / Cronet | 支持 | 部分 | 部分 | 共享请求语义,客户端留平台侧,之后再评估 Ktor |
| Rhino JS 规则 | 支持 | JVM 可评估 | 不支持/替代引擎 | RuleEngine capability + 兼容测试 |
| 前台服务 / 通知 / 媒体会话 | 支持 | 不适用 | 平台实现 | 永不进入 commonMain |
| 阅读器渲染 / 手势 / 翻页动画 | Android 专业岛 | 不承诺 | 不承诺 | 共享 render model,不强制共享 renderer |
| Compose 设计系统 / 低风险页面 | 支持 | 试点 | 后续 | 先 tokens 和叶子组件,再 Feature |
| WebService / 远程书架 | 支持 | 可选 | 可选 | 协议模型可共享,server lifecycle 平台化 |
退出条件:现有 CI 全绿;每个候选切片有 owner、输入输出、平台依赖表和回滚点。
build-logic convention plugins,先覆盖新模块,不一次改写 :app 全部构建脚本。feature-first-structure.md 建立 Feature catalog 与 :app 内 canonical package;新代码先停止扩大旧
ui/... 混杂结构。verifyConfigArchitecture 作为 Android 遗留棘轮;新增规则逐步拆成职责明确的 task 或静态分析。退出条件:代表性模块可用 convention plugin 构建;依赖违规有可读错误;Android 产物不变。
按风险从低到高抽取:值对象与序列化模型 → 纯函数/解析规则 → Gateway → UseCase → Repository 组合。
Context、File、InputStream、Room entity、资源 ID 和 JVM-only 时间/加密类型。modules:book 先做 dependency audit;能纯化的源码进入 common,平台文件访问留 adapter。expect/actual 声明在审查中写明为何普通接口 + DI 不足,并由门禁统计新增量。退出条件:commonTest 通过,至少一个非 Android target 编译,同一 Android 行为测试仍通过,历史泄漏基线下降。
退出条件:Android adapter contract tests 通过;共享层没有平台类型;故障、取消、事务与序列化语义有测试。
退出条件:Android 行为与视觉基线通过;选定 target 能编译并完成主路径;无平台调用泄入 shared UI。
api/impl;应用宿主聚合所有 impl 和导航 graph。ReadView 可长期保留。新 renderer 必须先过真机性能与交互
parity。只有 capability matrix、产品范围、发布链、崩溃/性能观察和数据兼容方案明确后,才把 Desktop/iOS 从架构证明提升为正式产品 target。
| 级别 | 适用范围 | 必须通过 | 状态 |
|---|---|---|---|
| G0 Android 基线 | 所有 PR | unit test、lint、verifyConfigArchitecture、debug assemble、git diff --check |
已存在 |
| G1 模块边界 | 新/改 Gradle 模块 | convention plugin、依赖图规则、无循环、无禁止方向 | 计划 |
| G2 Common 纯度 | commonMain 变化 |
禁止平台 API、commonTest、metadata + 非 Android target compile、公共 API 检查 |
随首个 KMP 模块启用 |
| G3 数据/平台适配 | Gateway/Repository/actual | contract tests、取消/线程/错误/事务语义、序列化和迁移兼容 | 按切片启用 |
| G4 CMP Feature | shared UI | Android UI/行为验证、目标平台 smoke、导航/effect parity、accessibility/insets | 按 Feature 启用 |
| G5 高风险能力 | reader/rules/services | 真机 parity、性能基线、脚本兼容、release/noR8 或专项验证 | 强制人工审批 |
| G6 发布 | 正式 target | target 测试/打包/签名、数据升级回退、观测与 capability 文档 | 产品化后启用 |
门禁规则:新门禁先 report 再冻结 baseline 最后 blocking;baseline 减少时必须下调,新增违规不得抬高;未创建的 task 只能写成计划名称;主分支 CI 跑对应级别完整矩阵;平台状态分别记录 compile、contract-test、smoke、package、release-ready,不能用一个“支持”覆盖所有等级;编译成功不替代行为、视觉、数据兼容和性能验证。
优先顺序:
build/generated,不包装成第二套自研框架。生成器门禁:至少两个手工样本已证明结构稳定;支持 --dry-run 且拒绝覆盖;已有 graph/DI
只结构化追加或输出人工补丁;不生成空层;有 fixture 和编译验证;生成结果继续接受普通审查。
建议 Phase 1/2 稳定后再实现 tools/new-kmp-feature,本文不提前固定其 CLI/API。
推荐顺序:characterization test → contract/adaptor → 调用方迁移 → 删除旧入口 → baseline 下调。
PR 必备证据:前后依赖变化、行为不变量与测试、expect/actual 数量净变化、精确验证命令、capability matrix
的 compile/test/smoke/package 状态变化、未验证项、兼容入口的移除条件与回滚路径。
AGENTS.md 全局不变量、资料优先级、最低验证
.agents/skills/ 专项执行与审查流程
docs/dev/ 架构理由、路线图、能力矩阵
source + tests + Gradle 当前真实 API、行为和可执行证据
推荐流程:明确目标/验收 → AGENTS → 专项 Skill → 设计文档与相邻实现 → 依赖/行为基线 → 单一切片 → 风险匹配门禁 → diff 与未验证项报告。
AI 不得根据目标结构虚构当前模块、task 或 API;文档建议 KMP 不等于获得大规模移动或删除权限。
build-logic,仅给一个 KMP smoke module 使用,验证 convention plugin。domain/model 选择 3–5 个纯值对象建立 shared:core:model PoC 和 commonTest。File/InputStream 暴露点设计 source/sink capability,不改底层实现。modules:book 的 Java/JDK/Android 依赖,输出 common-ready、需改写/adapter、必须 JVM 三类清单。完成以上项目后,再基于构建时间、模块图和真实跨平台收益决定下一批,不预先创建整棵目标目录树。