本文档描述当前 XposedSmsCode 的主项目分层、共享子模块边界与开发约束。
- Android application 壳、manifest entry、Receiver / Service 和最终 APK 打包。
- 主项目 composition root:把
presentation的 ViewModel、runtime gateway 实现和应用生命周期装配到一起。 - 负责把
smscode-rules内容子模块同步为 APK assets。 - libxposed metadata 仍由
app/src/main/resources/META-INF/xposed/打包,但 entry/runtime 实现归hook所有。 - 不重新定义已经下沉到
smscode-core的验证码主链基础设施,也不承载 Xposed runtime 实现。
- UI / presentation 层;2026-10-20 由
core更名为presentation,对齐实际语义(不是底层 core)。 - 承载 Compose UI、导航、ViewModel、主题和应用内 UI gateway 消费端。
- 只通过
runtime.bridge.Ui*Access等 gateway 使用项目运行时;Koin 对 runtime 实现的绑定归appcomposition root。 - 不直接引用
Runtime*Facade、AppDatabase、DBManager、DBProvider或 update/store 实现类。 - update 检查结果、策略判断与 Play 更新动作统一经
UiUpdateAccess。
- 主项目专属 Xposed Android 层。
- 承载 libxposed entry、hook 宿主适配、
XposedRuntimeInstaller、CorePrefsBridge和项目专属 hooks/actions。 - 可依赖
runtimegateway/实现与共享smscode-core:hook,但不得反向依赖app或 UIpresentation。 - 反射入口类名保持
io.github.magisk317.smscode.xp.LibXposedEntry,由 app 中的 metadata 引用并随最终 APK 合并。
- 项目专属运行时与数据主层。
- 承载
common/constant、runtime-onlycommon/utils、data/db、data/prefs、data/update、feature/backup、feature/store、forwarder/*。 - 允许继续保留现有 Kotlin package,不强制做包名重命名。
- 对外优先暴露 facade,减少上层直接依赖实现细节。
- 不引入 Compose/UI API。
- 继续作为验证码主链和跨项目公共能力的唯一共享实现来源。
- 当前 Gradle 子模块为
contract、db、domain、hook、rule、runtime、verification。 contract放接口、DTO、跨进程/跨模块契约。domain放领域模型和值对象。hook放共享 hook infra、libxposed 适配、系统输入与 fallback policy。runtime放日志、备份、规则目录、更新、包环境等可复用运行时能力。verification放短信分发、解析、通知、自动输入、去重等共享策略。db放跨项目共享的 Room 数据层(验证码记录/规则实体、DAO 与 schema 迁移;xinyi v32->v33 迁移时将数据层统一到本模块)。
HookHostCapabilities(io.github.magisk317.smscode.xposed.hook,smscode-core 0273466 引入)是共享 hook 层消费的唯一宿主能力契约;域 hooks(转发主链、保活、验证偏好)不进入契约。- 本仓经
hook模块XscHookHostCapabilities(io.github.magisk317.smscode.xp.hook.helper)实现契约;SmsHookBridgeHelper+SmsHookRuntimeSession负责 hook 生命周期(@Volatile字段 +synchronizedresolve/heartbeat 注入),已移除 per-hook runtime context 对象。 - xinyi-relay 为对等参考实现(
modules/hook/entry的XinyiHookHostCapabilities+ 同名SmsHookRuntimeSession)。 - 派发标记为三参:
VerificationSmsIntentHookSupport.markDispatchHandled(intent, action, DISPATCH_HANDLER_KEY),本仓DISPATCH_HANDLER_KEY = "sms_handler",与 xinyi 对齐。 - 契约测试位于
app/src/test/kotlin/io/github/magisk317/smscode/xp/hook/code/(SmsHandlerHookContractTest、MmsMessagesHookContractTest),固定"先标记 handled 再解析"的顺序与适配器接线。 - 契约变更必须同批同步两仓适配器,并 bump 所有消费
smscode-core:hook的父仓 gitlink。
- 内容型子模块,提供官方验证码规则快照与远程目录结构。
- 仅通过 generated assets 打入 APK,不作为 Gradle/Kotlin 代码模块参与编译。
- 官方规则只读展示,用户自定义规则仍由本地 DB、备份、导入导出链路承载。
app -> presentation, hook, runtime, smscode-core:*(最终 composition/packaging root)presentation -> runtime的公开 UI gateway/model、magisk-ui-kit与共享领域模型;不得绑定 runtime facade 实现hook -> runtime, magisk-xposed-kit, smscode-core:*(smscode-core全部 7 个模块)runtime -> smscode-core:*(smscode-core全部 7 个模块)smscode-rules不参与 Kotlin 依赖图,只作为 APK assets 输入。
约束:
presentation是 UI/展示层,不得被当作底层 contract 模块继续塞共享业务逻辑。presentation不得直接引用 runtime 的 facade、DB/update/store 实现类;实现绑定只能在appcomposition root。runtime不得引入 Compose/UI API。hook不得依赖app/presentation;app不得承载io.github.magisk317.smscode.xp生产源码。- 可复用短信策略应优先下沉到
smscode-core:verification或smscode-core:hook,主项目hook只保留项目专属 Android/Xposed 宿主适配。
- 统一通过
build-logicconvention plugin 提供 distribution flavor 和打包规则。 - 跨仓共享子模块 pin 矩阵(build-logic / magisk-ui-kit / magisk-xposed-kit / smscode-core / smscode-rules 的统一 sha)以 AGENTS.md「Cross-Repo Submodule Pin Matrix」一节为唯一真源;任何子模块源仓推进后,按该矩阵同批 bump 全部消费方父仓。
- 当前主线 distribution flavor:
play: Play AAB 发布渠道(发布线出 AAB;本地检查仍可用assemblePlayDebug)。github: GitHub APK 发布渠道;与已暂停的fdroid共享src/nonPlay源集。fdroid: 已暂停(与 xinyi-relay 对齐);恢复点为根build.gradle.kts中magiskDistribution {}块注释掉的flavor("fdroid")行。
- 正式发布线已收敛到 libxposed API 102 热重载主路径。
app/src/main/resources/META-INF/xposed/是当前 libxposed 元数据来源,包含module.prop、java_init.list、scope.list。legacy仅保留为独立分支和独立legacy-ci.yml工作流,不再作为当前主线 flavor 维护。
verifyModuleBoundaries: 根级汇总入口,聚合主模块 Gradle 依赖方向检查和下列局部边界 task。verifyMainModuleDependencies: 禁止runtime反向依赖app/presentation,禁止presentation依赖app, 并禁止smscode-core:*依赖主项目或magisk-ui-kit。runtime:verifyNoComposeUiLeak: 禁止 runtime 源码引入 Compose / UI API。presentation:verifyNoRuntimeStorageImplLeak: 禁止 presentation 直接绑定任意Runtime*Facade,并禁止存储、更新和 feature internals;UI 只能消费 runtime gateway/model。app:verifyNoLocalVerificationEngine: 禁止 app 重新引入共享验证码引擎基础设施,也禁止app拥有io.github.magisk317.smscode.xp生产源码;Xposed entry/runtime 必须位于hook。magisk-ci-toolkit/gradle/verify_consumer_compat.sh(配置由scripts/config/compat-check.json提供):验证根边界、smscode-coredomain 单测、 verification detekt、hook/runtime lint、presentation和app:check的兼容链路。
- 继续收窄
runtime.bridge.Ui*Access,逐步以 UI DTO/port 替代 DB entity 和 manager 暴露;runtime 实现绑定保持在appcomposition root。 - 继续把主项目
hook内可复用的短信策略下沉到smscode-core:verification,hook只保留宿主适配。 - 主项目
core→presentation更名已于 2026-10-20 完成(模块目录、Gradle 坐标、Kotlin namespace、R/BuildConfig 引用、CI/脚本任务路径同步切换)。 - 继续把测试按模块语义归位,避免
app承载 runtime/presentation 的单元测试;app 可保留最终 APK metadata/R8 集成契约测试。
| 影响等级 | 问题 | 状态 |
|---|---|---|
| 🔴 严重 | SMS_RECEIVED_ACTION 对 OTP 短信施加 3 小时延迟(SmsIntentHookSupport.kt:16)。Xposed hook 可能不受限制,需实测确认。 |
待验证 |
| 应用内存限制(基于设备 RAM)。需建立内存基准。 | 待验证 | |
| PendingIntent mutability 显式声明。 | 已合规 | |
内部文件写入权限收紧(MODE_WORLD_READABLE 在 targetSdk 37 抛异常)。 |
已合规 |