## Context 当前 `SmsReceive` 目录几乎为空,只有 macOS 生成的 `.DS_Store`,没有 Android 工程和既有 OpenSpec 目录。用户要求先生成完整 spec 方案,再开始编码;同时明确 Android Studio、Gradle、JDK 等环境不在本次方案范围内,后续实现要参考 `Weather reference project` 的构建环境。 目标设备是小米 12S、澎湃 OS 3、Android 15。需求本质是个人自用工具:收到手机短信后,应用读取短信原文并展示。由于不是 Play Store 上架应用,方案可以直接使用短信权限,但仍要面对 Android 运行时权限、Android 15 受限权限策略、厂商后台管理和短信广播分发行为。 官方 API 判断如下: - Android `Telephony.Sms.Intents.SMS_RECEIVED_ACTION` 是收到文本短信的系统广播,需要 `RECEIVE_SMS` 权限。它是读取任意短信原文最直接的路径。 - Google `SMS Retriever API` 不需要 `READ_SMS` 或 `RECEIVE_SMS`,但短信必须包含 app hash,适合服务端短信模板可控的场景,不适合读取所有第三方短信。 - Google `SMS User Consent API` 可以请求用户授权读取单条短信,不要求 app hash,但需要弹出用户确认,适合作为受限权限或广播异常时的对比验证路径。 ## Goals / Non-Goals **Goals:** - 先形成可执行 spec,不直接写业务代码。 - 建立 Android 15 上读取短信原文的主路径和备选路径。 - 明确短信原文展示、权限状态、诊断状态和真机验证标准。 - 后续实现应保持最小化:一个主界面、一个接收链路、一组诊断信息,不做复杂产品化。 - 保持短信内容本地处理,默认展示短信原文、来源、时间和短诊断摘要。 **Non-Goals:** - 不做完整短信客户端,不替代系统短信 App。 - 不实现发送短信、删除短信、读取历史短信库或同步短信到云端。 - 不处理 Android Studio、Gradle、JDK 的重新安装和环境拉取。 - 不以 Google Play 上架合规作为约束目标。 - 不保证所有银行、平台、运营商短信都能被无条件读取;必须通过真机验证确认。 ## Decisions ### Decision 1: 主路径使用 `SMS_RECEIVED_ACTION` + `RECEIVE_SMS` 主路径选择系统短信广播。原因是目标是读取“我自己的手机收到的短信原文”,短信来源不可控,很多短信不会带当前 app 的 hash,`SMS Retriever API` 无法覆盖任意短信。系统广播能拿到完整 PDU,再通过 `Telephony.Sms.Intents.getMessagesFromIntent(Intent)` 合并为正文,是最符合目标的能力。 实现要求: - Manifest 声明 `android.permission.RECEIVE_SMS`。 - 对 Android 6.0+ 执行运行时权限申请。 - 注册接收 `android.provider.Telephony.SMS_RECEIVED` 的 receiver。 - receiver 内只做轻量解析和状态分发,避免长耗时。 - 记录最近一次接收时间、sender、body 摘要、读取结果和失败原因。 备选方案: - `READ_SMS` 可读取短信数据库,但需求是监听新短信,不需要读取历史短信;默认不纳入主路径。 - 默认短信应用角色权限更强,但目标不是做短信客户端;不作为一期要求。 ### Decision 2: 备选验证路径引入 `SMS User Consent API` `SMS User Consent API` 用于验证两类问题: - 当系统广播路径在 HyperOS 上被后台策略影响时,前台触发 consent flow 是否能拿到单条短信。 - 当用户不愿或系统不允许直接授予短信权限时,是否仍能通过一次性确认读取短信原文。 限制: - 它不是静默读取,需要用户确认。 - 它适合前台验证流程,不适合后台长期监听所有短信。 - 它依赖 Google Play services;国内 ROM 环境下需要确认设备实际可用性。 ### Decision 3: `SMS Retriever API` 只作为受控短信模板能力 `SMS Retriever API` 的优点是无需短信权限,体验干净;但它要求短信包含 app hash,且通常需要服务端发送符合格式的短信。对于读取第三方平台短信,它大概率不适用。因此一期只实现或预留为“自发测试短信/未来自控服务端短信”的能力,不作为读取任意短信的主线。 ### Decision 4: 最近结果直接以短信原文为主 当前目标不再是从短信中提取结构化业务字段,而是直接保留收到的短信原文。因此最近结果与诊断数据应围绕“是否成功读取到完整短信正文”展开,而不是围绕解析命中策略。 建议顺序: 1. 优先保证 PDU 合并后的短信正文完整。 2. 记录 sender、timestamp、source 和 body 摘要。 3. 读取失败时保留失败原因,例如无权限、未收到广播、正文为空。 4. 默认展示最近一条短信原文,不额外推断正文中的业务字段。 ### Decision 5: UI 首版只做诊断型工具界面 首版 UI 应该服务验证,而不是做复杂产品。建议显示: - 当前短信权限状态。 - 主路径 receiver 状态。 - Google Play services / SMS User Consent 可用性。 - 最近一次收到短信的时间、发送方、来源和短信原文。 - 最近失败原因,例如无权限、未收到广播、正文为空、API timeout。 - 手动清空最近结果按钮。 ### Decision 6: 本地隐私边界 即使是自用 app,也应尽量控制短信内容扩散。建议: - 默认只持久化最近一条短信原文、时间、sender 摘要和读取状态。 - 核心能力不以网络上传为前提。 - 日志避免输出完整短信正文;debug 模式如需输出,必须集中开关控制。 ## Android 15 And HyperOS Risk Analysis - [Risk] `RECEIVE_SMS` 在 Android 15 或厂商系统上被标记为高风险/受限权限,安装来源和系统设置可能影响授权。 → Mitigation: 首次启动展示权限状态;如果权限申请失败,引导到应用详情页检查“受限权限/权限管理”;同时使用 consent API 做对比验证。 - [Risk] 后台接收被 HyperOS 省电策略限制。 → Mitigation: 首轮验证覆盖前台、后台、锁屏三种状态;如后台不稳定,增加前台服务或引导关闭省电限制作为后续任务。 - [Risk] Google Play services 在目标设备上不可用或版本不满足。 → Mitigation: Google API 作为备选路径,主路径不依赖它;诊断页显示可用性。 - [Risk] 双卡、国际短信、长短信 PDU 合并导致 sender 或正文异常。 → Mitigation: 使用官方 `getMessagesFromIntent` 解析,按 message body 拼接,记录 subscription id 如可用。 - [Risk] 正则误识别。 → Mitigation: 解析结果带命中策略和置信度;测试用例覆盖误判样本。 ## Migration Plan 本项目当前没有既有代码,迁移计划等同于实施顺序: 1. 完成本次 OpenSpec 评审。 2. 参考 Weather 项目创建或复制最小 Android 构建骨架。 3. 实现权限和诊断 UI。 4. 实现系统短信广播主路径。 5. 实现短信读取结果存储和展示逻辑。 6. 在小米 12S 上跑真机验证。 7. 根据真机结果决定是否补 `SMS User Consent API` 或后台稳定性处理。 Rollback 策略: - 如果系统广播路径被目标设备限制,保留解析器和 UI,降级为 `SMS User Consent API` 前台读取验证。 - 如果 Google API 不可用,不影响系统广播主路径。 ## Validation Strategy 上下文验证: - 确认 Weather 项目可作为构建环境参考。 - 确认 `SmsReceive` OpenSpec 通过 CLI validate。 - 确认 spec 任务列表不包含重装 Android Studio、Gradle、JDK。 代码验证: - 短信读取与结果存储测试覆盖多段短信、正文为空、权限缺失和最近结果刷新样本。 - receiver 解析逻辑可通过构造 Intent/PDU 或抽象 message input 测试核心逻辑。 - 权限状态和诊断状态可通过 ViewModel/unit test 验证。 真机验证: - 前台打开应用后,向目标号码发送测试短信:`【测试】这是一条短信原文样本。` - 应用退到后台后,重复发送不同短信正文。 - 锁屏状态下发送短信,解锁后检查最近结果。 - 若可以控制短信格式,发送带 app hash 的 SMS Retriever 测试短信。 - 若广播路径失败,打开前台 consent flow 再发送短信,观察是否弹出授权并读取正文。 ## Open Questions - 目标小米 12S 当前是否安装并启用了 Google Play services。 - 用户是否接受为了后台稳定性关闭 HyperOS 对该 app 的省电限制。 - 首版是否需要常驻通知显示最近短信结果,还是只在 app 内展示。 - 是否需要支持短信原文快捷复制;这会带来额外隐私和系统提示问题,建议先不做。