Files
youle_app_ios_v2/CLAUDE.md
T
joywayer 87304552c3 docs:勾选 Plan §5 / §8 Phase 1.10-1.13 进度 + CLAUDE.md 新增「进度同步规范」
把 Plan 任务清单和进度追踪 checklist 同步到当前实际进度(1.10-1.13
均已完成 + 实测验证),并在 CLAUDE.md 写入"每完成 Phase 子项必须立即
更新 Plan 进度"的硬约束。

- Plan §5 Phase 1.10-1.13 任务清单 [ ] → [x]
- Plan §8 进度追踪同步:标注算法名 / 端到端实测结果(260→261 验证)
- CLAUDE.md 新增「进度同步规范」节,规定:
  - Plan §5 + §8 每完成子项立即勾选,与 commit 同 commit 内完成
  - 任务描述与实现有差异时同步修订(不允许 Plan 与代码长期不一致)
  - commit message 末尾备注"Plan 进度已勾选"
  - 理由:Plan 是项目记忆的唯一权威进度视图,新人 clone 后看 Plan
    §8 即可知整体进度;与 commit log 双写互为校验

Plan 进度已勾选
2026-06-22 02:30:31 +08:00

198 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# daoqi 项目协作约定(面向 Claude / AI 助手)
> 本文件随 daoqi 仓库分发,任意设备 clone 后均按此约定执行。
---
## 适用范围声明
**本 CLAUDE.md 仅适用于 daoqi 项目自身**
- 父目录(任何上级目录)下可能存在其它 CLAUDE.md 文件,那些文件**不是为本项目编写**的,与 daoqi 项目无关,**不参照、不继承、不引用**。
- Claude / AI 助手在本项目工作时,只读取并遵循本文件(`./CLAUDE.md`)与本项目 `docs/` 下的文档,不向上递归引用父级 CLAUDE.md。
- 如果在对话上下文中出现父级 CLAUDE.md 的内容(由工具自动加载),应当忽略,以本文件为唯一权威。
---
## 项目内容
daoqi 仓库当前并存两条工作线:
1. **现有 iOS 外壳(`msext` target** — 已上线版本。Objective-CMRC,未启用 ARC),最低 iOS 9.0;原生外壳 + 内置 H5`gamehall.zip` 解压到沙盒)+ WebViewJavascriptBridge 桥接。
2. **新外壳设计(greenfield 重写)** — 计划中的下一代版本。设计原则、接口契约、实施蓝图见 `docs/` 下两份文档。
---
## 文档索引
| 文档 | 角色 | 何时读 |
|------|------|--------|
| `CLAUDE.md`(本文件) | 项目协作约定、契约边界声明 | 每次对话先读 |
| `docs/H5-Native-Contract.md` | H5 ↔ 原生 桥接**契约**(黑盒可观察行为) | 涉及桥接接口必读 |
| `docs/H5-Native-Implementation-Design.md` | 新外壳实施蓝图(架构、模块、代码骨架) | 实现新外壳必读 |
| `docs/Development-Plan.md` | 开发执行计划(Phase 0–10、依赖图、进度追踪) | 排期 / 进度更新必读 |
---
## 依赖管理约定
新项目采用**纯 SPM + Vendor `.xcframework` 两层管理****禁止引入 CocoaPods**(详见 `docs/Development-Plan.md` ADR-006)。
- **首选 SPM**:开源 / 官方提供 Swift Package 的库(Sentry / ZIPFoundation / 七牛 `https://github.com/qiniu/objc-sdk` v8.9.x 等)
- **Vendor `.xcframework` 手动**:所有闭源二进制(微信 / QQ / 高德 AMap / opencore-amr 等),按 Design §14.1「Vendor 接入标准流程」放 `Vendor/<SDKName>/` + Target → General → Frameworks 加入 + `Vendor/<SDKName>/README.md` 记录版本与来源
- **禁止 CocoaPods**:项目内不放 `Podfile` / `Podfile.lock` / `Pods/` / `.xcworkspace`。工程入口固定为 `ylgamehall.xcodeproj`
- **新增第三方依赖时**:按 SPM → Vendor 顺序尝试,PR 描述写明选型理由;若发现某 SDK 既无 SPM 又无 XCFramework,回到 ADR-006 决策框架重新评估
---
## docs/res/ 与项目资源的关系
`docs/res/` 是**项目维护者的私人原始素材池**,**与项目架构无关**:
- 仅作为开发期可能用到的素材的随手存放点(H5 团队提供的 zip / 美术给的 png / 原 msext 沉淀的 mp3 / 历史 Asset Catalog 等)
- **项目代码 / 构建脚本 / Xcode 工程都不感知它的存在**,不依赖它的目录结构,不引用它的任何文件
- 内容、结构、命名随时可由维护者调整,不影响构建
- git 跟踪它只是为了多机同步素材,而不是因为项目需要它
### 项目自己的资源目录由项目独立规划
**禁止把 `docs/res/` 当作项目的资源目录使用**(即不要在代码 / 脚本 / Build Phase 中直接引用 `docs/res/xxx`)。当某项工作需要某个素材时:
1.`docs/res/` **拷贝一份**到项目按现代 iOS 实践规划的目标目录(如 `ylgamehall/Resources/``ylgamehall/Assets.xcassets/``Vendor/<SDK>/` 等)
2. 由 Xcode 工程结构 / synchronized group / Build Phase 接管该素材的打包流程
3. 后续维护与 `docs/res/` 不再有任何关联——`docs/res/` 那份是"原始备份",工程内那份是"在用版本"
**约定**:项目实际需要的资源目录结构由 Design / Plan 在各 Phase 实施时按需定义并落到工程内;不预先把"所有未来可能用到的资源"硬塞进某个固定 Resources 目录。
---
## 核心约定:两条平行原则
新项目(新外壳)开发同时遵循以下两条原则。两条**地位对等**,互为补充:
### 原则 A:H5 端完美适配(外部契约)
**H5 端零修改即可适配新外壳**。这是不可越界的硬约束,详见下方 §五类必须一致的内容。
### 原则 B:原生内部实现自由重构(内部架构)
**原生内部的实现可以也应当与原项目不一致**。新外壳不是旧 msext 的复刻,是按现代标准重新设计的产物,应当主动追求:
- **架构优雅** — 模块边界清晰、依赖单向、单一职责;不再受旧项目 PCH 全局注入、MRC、UIWebView、JSContext 等历史包袱约束
- **高效 / 高性能** — 启动并发优化、WKWebView ProcessPool 复用、桥消息批处理、actor 隔离的并发模型;性能指标可度量、有 SLO
- **专业** — 完整的单测覆盖、CI 流水线、代码规约、文档体系;不留"等会再补"的口子
- **成熟** — 选用社区主流、长期维护的库(URLSession、SPM、ZIPFoundation、async/await);摒弃 ASIHttpRequest、SBJSON、UIWebView、AFNetworking 等已废弃技术
→ 详细技术选型与架构设计见 `docs/H5-Native-Implementation-Design.md`
**两条原则的交叉判定**
- 如果某项决策影响 H5 可观察行为(接口名/字段/数据/JS 协议)→ 必须遵循原则 A,照搬旧项目
- 如果某项决策只影响原生内部(技术栈/模块结构/状态管理/SDK 选型/代码风格)→ 必须遵循原则 B,按现代标准设计,**不要照搬旧项目**
- 当两者冲突时,**原则 A 优先**:宁可让原生内部多一层适配层去保住契约,也不能为了内部优雅破坏 H5 契约
---
## 原则 A 详述:H5 适配的五类必须一致
为达到 H5 端零修改适配,以下五类内容**必须 1:1 与现网一致**:
### 1. 桥接接口名(handler 名字符串)
H5 端通过字符串名调用原生 handler,例如 `bridge.callHandler('mediaTypeAudio', ...)``bridge.callHandler('friendsSharetypeUrlToptitleDescript', ...)`
- **新外壳注册的 handler 名必须字面一致**,少一个字符、改一个大小写、改一个驼峰都视为契约违反
- 含历史包袱命名照搬:`SwitchOverGameData`(驼峰首字母大写)/ `friendsSharetypeUrlToptitleDescript`(长形式)/ `gameui_play_voice`(下划线)/ `OpenurlTitleData`
- 完整 39 项 handler / callback 名见 `docs/H5-Native-Contract.md` §3
### 2. 参数字段名
H5 → Native 时 data 字典中的 key,以及 Native → H5 callback payload 中的 key。
- **字段名字面一致**,含历史包袱:
- `sharelogin` 回包中 `Province` 是**大写 P**(不是 `province`
- `OpenurlTitleData` 入参中 `"title "` 末尾**有一个空格**(不是 `"title"`
- `getphoneinfo` 回包用**小写 i**(H5 调用方是 `getphoneInfo` 大写 I
- `appservice` 用字符串 `"1"`(后台)/ `"2"`(前台),不是数字
- `getlocationinfo``latitude` / `longitude`**string** 而不是 number`stringWithFormat:@"%f"` 产生)
### 3. 参数数据结构
- H5 → Native 入参类型(string / number / bool / object / array
- Native → H5 回包结构(每个字段的类型、嵌套层次)
- 字段是否可缺、缺时如何 fallback
→ 完整结构见 `docs/H5-Native-Contract.md` §3.1 / §3.2 表 A/B/C
### 4. H5 端注册方式(JS 协议)
H5 页面通过特定的 JavaScript 协议初始化桥并注册自己的 handler。**新外壳必须使用 H5 端代码一致的 JS 协议**:
- **大厅 / 子游戏页**:H5 使用 `WebViewJavascriptBridge` 的 JS 协议(`_setupWebViewJavascriptBridge` 握手、`bridge.callHandler(...)``bridge.registerHandler(...)`)。新外壳实现必须支持这套握手协议(推荐做法:直接复用 marcuswestin/WebViewJavascriptBridge 的 JS 端源码,原生侧自实现)
- **弹层(threeView 等价容器)页**H5 使用 `window.settings.xxx(...)` 直接同步调用形式(JSExport 协议)。新外壳如改用 WKWebView,需注入 polyfill 让 `window.settings.{backgameData, browser, finishweb}` 仍然按相同形式可用
任何打破 H5 端注册方式的实现(如换用自创 JS 协议、改变 `window.settings` 名字)都视为契约违反。
### 5. 空实现接口也必须保留注册
当前现网中 `opensaoma``getGameplay` 等 handler 是空实现(`responseCallback("opensaoma")` 后无副作用),但 H5 仍然会调用。
- **新外壳必须以同名空 handler 注册**,否则 H5 调用时触发 "bridge handler not found" 错误分支,导致业务流程中断
- 完整空实现清单见 `docs/H5-Native-Contract.md` §3.1
---
## 不属于契约的部分(自由实现)
除上述五类外,原生内部一切自由:
- 技术栈(Swift / Objective-C / SwiftUI / UIKit 任选)
- 桥接库选型(自实现 WKScriptMessageHandler / 引用 WebViewJavascriptBridge 都行)
- 网络层(URLSession / Alamofire / AFNetworking
- 状态管理、并发模型、命名风格、SDK 选型
- 启动时序内部并发优化、解压实现、零拷贝优化
- NSNotification 内部模块通讯命名(不是 H5 可见)
- 监控、日志、CI 选型
**判断某项是不是契约的方法**:问"H5 代码能不能感知到?"。能感知 → 契约;不能感知 → 自由。
---
## 验收原则
新外壳完成后,**在不修改 H5 任何一行代码**的前提下,逐项跑 `docs/H5-Native-Contract.md` §10 的 26 项验收清单。任意一项 H5 表现与现网不一致即视为契约违反,需要排查;表现一致即视为通过,原生内部实现自由。
---
## 提交规范
- 提交信息使用中文短句,描述"做了什么 + 为什么"
- 不在未授权情况下执行 `git push``git reset --hard``git rebase``git push --force` 等不可逆操作
- 涉及桥接接口名 / 参数字段名 / 数据结构的改动,提交信息必须明示 "契约影响" 并附 `docs/H5-Native-Contract.md` 对应章节
- 工作树有多个不相关改动时,按职责拆 commit,不混提
- **及时提交**:每完成一个可独立验证的工作单元(一项 bug 修复 / 一处配置变更 / 一次文档更新 / 一次依赖升级 / 一个 M 里程碑的子项),就应在工作树干净时主动提议提交。理由:
- 项目处于 greenfield 重写阶段,commit 颗粒越小越容易在出错时二分定位 / 回滚
- 长时间不提交容易让 pbxproj / Info.plist / SDK 二进制等结构化文件互相耦合,git diff 失去可读性
- CLAUDE.md / docs 与 git log 一起构成项目记忆——commit message 是"为什么"的第一现场,比事后补文档更可信
- 主动提议提交的时机判定:
- 改动已通过最小验证(BuildProject 通过 / 关键路径手测通过 / 单测通过)→ 立即提议
- 工作树还有其它无关待提交内容 → 先帮用户分类、按职责拆 commit,**不混提**
- 用户未明确同意前不直接执行 `git commit`,但应当**清晰地告诉用户"现在适合提交了"**,并附上建议的 commit message
---
## 进度同步规范
**每完成一个 Phase 子项(如 1.10 / 1.11 / 1.12 ...)必须立即更新 `docs/Development-Plan.md` 的进度标记**,不允许"代码提交但 Plan 未同步"的滞后。具体:
- Plan §5 各 Phase 任务清单:完成的子项把 `- [ ]``- [x]`,附简短结果或耗时
- Plan §8 进度追踪 checklist:同步勾选 + 简短补充(如算法名 / 端到端测试结果)
- 时机:通常与该子项的 `git commit` 同一 commit 内完成,commit message 末尾备注"Plan 进度已勾选"
- 若改动跨多个 Phase 子项(极少见),逐项勾选不能漏
- 当任务清单中的描述与最终实现有差异(如新增子任务、合并子任务、改变实现策略)时,**同步修改任务描述**,不允许 Plan 文档与代码长期不一致
理由:
- Plan 是项目记忆的唯一权威进度视图,新人 clone 后只看 Plan §8 就能立刻知道整体进度
- 若代码已完成但 Plan 未勾选,新人会误判项目状态、做重复工作
- 若 Plan 描述与代码实现不一致,未来 Phase 验收 / 回归测试时会基于错误前提
- 与 commit message 双写互为校验:commit log 是细节,Plan 是全局视角