--- name: AVBox项目开发规范 description: 项目规则、通用原则、通用代码规范、交付验证与审查收敛约定(验证前置、审查停止标准、改动前自查) + 项目文档地图(索引与按需检索约定) --- # 项目规则 - 新功能用 Kotlin 写,尽量别碰 Java - 禁止未经用户允许就将代码提交到远程仓库 - 禁止排除项目根目录下的 .key 文件夹(用户要求密钥入库) - 文档与代码注释中禁止硬编码本机绝对路径(盘符开头的路径、用户主目录路径、SDK/工具安装路径等):仓库所在目录的**路径与名字都不固定**,一律用相对仓库根目录的路径或环境变量表达 # 通用原则 - 优先官方文档 > 官方最佳实践 > 稳定版本文档;与官方指导冲突时以官方为准 - 可维护性优先于开发速度,简洁性优先于不必要的复杂设计 - 禁止编造 API、文档内容、版本信息、性能数据、项目事实;不确定就查官方文档或明确说明 - 保持架构模块化、单一职责、低耦合高内聚、避免循环依赖、集中管理共享功能、不重复已有实现;除非明确要求,否则不改变项目架构 - 默认最小化修改:不改无关文件/代码,不做未经请求的重构 - 新增代码必须与现有项目风格一致,统一为新写法,禁止新旧写法混用 - 优先渐进式改进,而非大规模重写 - 优先使用项目已有技术,没有充分理由不要引入新框架 # 通用代码规范 - **代码风格**:清晰命名、小型函数/类、不可变数据、可读代码、单一职责;避免超长方法、巨大类、重复代码、过深嵌套、魔法数字、不必要全局状态 - **分层职责**:UI层负责渲染与交互,业务层负责逻辑/状态/工作流程协调,数据层负责 Repository/网络请求/数据库/缓存;禁止绕过分层,业务逻辑不得直接访问具体数据源 - **状态管理**:使用单向数据流,状态集中管理,UI由状态驱动,避免维护重复状态 - **注释**:只解释"为什么"(设计原因、业务规则、兼容性、性能/安全考虑),禁止描述代码表面行为;注释尽量精简。硬性红线: - 禁止决策过程叙事:不写日期("2026-xx-xx 用户定稿")、评审编号(BugReview #N)、"旧实现…现在…"演进对比、"照搬/参考某项目"出处、规范章节号(§x.x)引用——这些属于过程记录,归 `skill/history/`,不进代码 - 单条注释 ≤2 行;逐行贴标签式注释一律不要,优先好命名/提取函数 - 只留"不写会再踩的坑",写"违反会怎样+为什么",不写"这段在做什么" - 自查:删掉某条注释不影响理解代码 ⇒ 它本不该存在 - **错误处理**:禁止静默忽略错误;使用统一错误处理方式,明确处理异常 - **并发**:遵循项目现有异步编程方式;永远不要阻塞主线程;避免共享可变状态,确保线程安全 - **配置**:禁止硬编码 URL、版本号、配置参数;版本一律走 `gradle/libs.versions.toml`;适用情况下支持多环境配置 - **技术决策**:多方案需说明优缺点及对项目影响,不将某方案描述为唯一正确方案 - **代码质量**:新增代码应易读、易维护、遵循现有架构、保持向后兼容、具备可测试性 - **重构触发**:仅在存在 Bug、可维护性较差、性能明显受影响或用户明确要求时重构 - **修改说明**:改动公共 API / 核心业务逻辑 / 项目架构时,必须说明原因、收益、可能缺点及是否需同步修改相关组件 # 交付验证与审查收敛 - **验证不得攒到最后**:每完成一组改动(或一轮审查修复)立即跑 `.\gradlew :app:assembleDebug` 与 `.\gradlew :app:testDebugUnitTest`;改配置解析 / 规则 / 字段取值的必须补单测锁口径(范例:`ConfigParserTest`、`HeaderGuardTest`)。纯人眼推理会把"会崩 / 会失效"级问题拖到很后面才暴露。 - **跑构建的三个坑(2026-09-23 实测,别再重复踩)**:①**不要用 `| Select-String … | Select-Object -First N` 过滤 gradle 输出** —— 管道会在拿到 `BUILD SUCCESSFUL/FAILED` 之前被截断,命令以非零码结束,极易误判成"构建失败"(本次为此白跑一轮)。要过滤就 `> log 2>&1` 落盘后再读。②**该日志是 UTF-16**,Git Bash 的 `grep` / `tail` 对它零命中(表现为"明明有输出却搜不到"),只能走 PowerShell 的 `Get-Content`。③Git Bash 里 `./gradlew` 报 `ClassNotFoundException: GradleWrapperMain`(jar 完好,脚本路径问题),用 PowerShell 的 `.\gradlew.bat`。判读结果以 `BUILD SUCCESSFUL` 与 `app/build/test-results/testDebugUnitTest/*.xml` 的用例计数为准,别只看退出码。 - **审查有终止线,不以"零发现"为目标**:换个角度总能找到东西,无限轮没有收益。可以收尾 = 连续一轮没有 阻断 / 高 / 中 级发现,且剩余发现全部属于"既有问题"或"口味差异"。每轮发现按「严重度」×「本次引入 / 既有 / 口味差异」两轴记账,严重度单调下降即可停。 - **改动前两项自查**:①照抄既有写法时必须连带抄它的防御与归一化,漏抄等于把既有缺陷一起复制进来;②改动全局字段 / 新增数据源 / 触碰"第 0 项""唯一"这类隐式约定时,先列出它打破的不变量与全部消费方。实例与修复过程见 `history/features.md` 的 2026-09-23 条目。 # 文档地图(先读这里,再按需检索) | 文档 | 内容 | 何时读 | | --- | --- | --- | | `skill/avbox-mobile-ui-spec.md` | **活规范**:技术基线(§2)、信息架构与主题(§3)、各页面规范(§4)、视觉与组件约定(§5)、关键技术约束与已知坑(§6,含 **§6.12 订阅源配置与站点字段**)、未决清单(§7)、历史索引(§8) | 改动 UI / 页面 / 播放内核 / 依赖 / **订阅源解析与站点字段**前**必读**(读 §0–§7) | | `skill/avbox-kv-mmkv-spec.md` | **迁移 Spec(已实施 2026-09-13)**:Hawk → MMKV 的现状盘点(键类型分布)、KV 门面设计、类型编码/加密/一次性数据迁移、分阶段实施与验收清单、决策记录 | 改动键值存储(新增/调整 KV 键、怀疑存储读写问题时)**必读**;§7 决策记录与文末修订记录是结论来源 | | `skill/avbox-playback-service-spec.md` | **播放服务化 Spec(草案,未实施)**:照搬 fongmi"播放器归前台服务、页面只挂摘视图"的所有权模型;现状差距清单、目标架构与挂摘协议、D1–D7 设计选择、P0–P5 分阶段实施、风险登记、真机验收清单 | 改动播放器归属/跨页复用/后台播放与通知/`MusicPlaybackService`/`PlayContainer` 职责划分前**必读** | | `skill/avbox-i18n-spec.md` | **多语言适配 Spec(四语全部落地:简体 / 英语 / 繁體台灣 / 繁體香港,代码完成待真机走查;2026-09-22)**:四语现状盘点(645 处硬编码文案、453 条去重)、中文参与数据与逻辑的红线清单(R1–R13)、资源组织与命名约定 + **§3.3 术语表**、`LanguageManager`+KV 方案与三处 Context 包裹、**`Trans` 门控(语言签名懒重建)**、D1–D6 决策点、四步(按语言)实施与进度表、验收清单与风险 | 改动文案/新增 UI 文案/做多语言前**必读**;§1.3 与 §9 是红线 | | `skill/history/steps.md` | **历史归档**:Step 0–7 改造实施记录、Step 1 删除清单实际对账 | 按需检索:某类/布局/依赖当初为什么删、某步架构决策 | | `skill/history/features.md` | **历史归档**:2026-09-09 起功能迭代记录(下拉刷新、隧道模式+AAC、配置管理页、主题设置页、顶栏改造、选集溢出修复、快搜删除、卡片点击分发…) | 按需检索:某功能当初怎么实现、为什么这么定、踩过什么坑 | | `示例文件/` | 上游与示例参考项目(`TV-fongmi` = fongmi/OK影视,`android` = 官方方案参考) | 需要对照上游实现时(**只读参考,不改**) | # 检索约定(按需搜索,不要通读) - `history/` 约 80KB 历史,**默认不通读**;先用关键词定位命中行,再定点展开上下文: ```powershell Select-String -Path skill\history\*.md -Pattern '顶栏','帧率' | Select-Object -First 20 Select-String -Path skill\history\features.md -Pattern '配置管理页' -Context 0,3 ``` - **单一事实来源**:仍生效的规范写在 `avbox-mobile-ui-spec.md`;`history/` 只增不改,是过程与决策的存档。 - **新内容往哪写**:规范/约束 → 活规范对应小节;实施过程、补丁、排查记录 → `history/`(改造步骤进 `steps.md`,功能迭代进 `features.md`)。不要把过程叙述堆进活规范。 - **新增文档**:必须登记到上面「文档地图」,否则等于不存在。 # 已知高危约束(动手前扫一眼,详见 spec) - **依赖裁剪不得只看宿主源码静态引用**:动态加载的爬虫 jar 需要宿主提供 gson / okhttp / **zxing** 等,删了会在运行期崩(spec §6.3)。 - **Exo 帧率匹配必须保持关闭**(`disableFrameRateMatching()`):否则 ROM 会把整机刷新率降到 60Hz,表现为"播放时卡顿"(spec §6.1)。 - **禁止自研顶栏滚动记账**:用 M3 官方 `exitUntilCollapsed` behavior(spec §6.6)。 - **爬虫阻塞调用必须在 IO 线程**(spec §6.2)。 - **KV(MMKV)复杂键必须在 `util/kv/KVKeySpec` 登记显式类型**,且禁止用匿名 `TypeToken` 捕获类型变量推元素类型(spec §6.7);另注意 `KV.contains` 才是判存在性、`KV.get(key, def)` 分不清"键不存在"与"值就是 def"。 - **配置驱动的 header 必须过字符集过滤**(`ConfigParser.isHeaderNameSendable`/`isHeaderValueSendable`):OkHttp 在构造请求时校验,越界抛 `IllegalArgumentException`,而站点请求分支没有 try/catch ⇒ 一份带中文 header 的配置会把 App 带崩(spec §6.12)。 - **规则表只能在 `parseJson` 入口清**(`VideoParseRuler.clearRule()`):放进 `resetConfigData()` 会让换源失败时规则真空(在播内容广告回归/click 失效);只在 `has("rules")` 时清则跨源残留(spec §6.12)。 - **崩溃标记只由"可能与源有关"的崩溃写入**(`BootGuard.looksSourceRelated` 的白名单 `IGNORABLE_FRAME_PREFIXES` 是唯一旋钮;无帧/判不出按"有关"):放宽它等于让坏源重新把应用锁进启动崩溃。没有崩溃标记的启动会把 `BOOT_LOADING_COUNT` 清零(spec §6.13)。