# 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-C(MRC,未启用 ARC),最低 iOS 9.0;原生外壳 + 内置 H5(`gamehall.zip` 解压到沙盒)+ WebViewJavascriptBridge 桥接。 2. **新外壳设计(greenfield 重写)** — 计划中的下一代版本。设计原则、接口契约、实施蓝图见 `docs/` 下两份文档。 --- ## 原项目 daoqi:遇到问题时的参考来源 **原 daoqi 项目代码位于** `/Users/joywayer/Documents/Works/YouleApps/iOS/youle_app_ios/daoqi/`(与 ylgamehall 同级目录)。该项目已稳定运行多年(msext target),是同一 H5 业务、同一渠道分发模式、同一启动流程的"工作参照实现"。 ### 何时主动去读原项目 新项目实施过程中**遇到任何一类下述问题,第一动作是去 daoqi 找参照**,而不是凭推测搭方案: - **iOS 行为不符合预期 / 与文档描述有差异**(如本次的 LaunchScreen orientation 问题:iOS 26 + Xcode 26 默认 Build Settings 写法导致启动图被 portrait 渲染再旋转 90°) - **某个 Info.plist key / Build Settings 不确定该不该加 / 加哪种变体** - **某个 H5 桥接 handler 的返回值结构 / 字段命名 / 类型不确定** - **某个三方 SDK 的初始化时序 / 回调链疑似有顺序依赖** - **渠道注入 / 启动流水线 / 升级逻辑某一步与设计文档对不齐** - **某个看似可改的"老 hack"想清掉,但不确定该 hack 是否解决过某个具体问题** ### 怎么用原项目 1. **先查关键文件**:`daoqi/msext/Info.plist`、`daoqi/msext/Class/AppDelegate.{h,m}`、`daoqi/msext/Class/UI/NewRootVC.m`(启动流水线全部在此)、`daoqi/Podfile`(看用了什么三方) 2. **grep 同名 key / 同名 handler**:例如 `grep -r "UISupportedInterfaceOrientations" daoqi/msext/Info.plist` 3. **看 git log / git blame**:原项目积累的"看似古怪的写法"通常都有当年的修复故事 4. **对照差异**:原项目稳定运行的写法是事实基准;新项目偏离它的部分必须有明确的"为什么改"的理由(通常出现在 `docs/H5-Native-Implementation-Design.md` 的 ADR 或 §6.3.6 等差异表里) ### 与「原则 B:内部自由重构」不冲突 - 参考原项目 ≠ 照抄原项目的实现细节 - 参考原项目 = 把它当作 **"哪些事必须做"的清单** 和 **"哪些坑已经踩过"的备忘** - 新项目的现代化重构(Swift 6 / SwiftUI / actor 隔离 / SPM 依赖等)依然按原则 B 自由设计;只是设计前先确认"我没有漏掉原项目实际需要解决的事" ### 典型案例:LaunchScreen orientation(启动图方向错误) - **症状**:新项目启动图渲染成竖向矩形再被整体旋转 90°,画面横躺在中间 - **错误做法**:凭 Xcode 26 文档推测、纯调整 storyboard / contentMode / 反复换素材 - **去原项目找答案**:`daoqi/msext/Info.plist` + `msext.xcodeproj/project.pbxproj` - 发现 1:Info.plist 用的是**顶层无后缀的 `UISupportedInterfaceOrientations`**(值 = landscape),**没有** `~iphone` / `~ipad` 后缀变体 - 发现 2:根本**没有** `UILaunchStoryboardName`,用的是 `ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-1"`(iOS 8 时代的 LaunchImage Asset Catalog 机制) - **原项目为什么稳**: - 它的所有 LaunchImage PNG(`Default-568h@2x` / `LaunchImage-1-800-667h@2x` 等)**物理像素都是竖向、画面内容横躺** - iOS 8 LaunchImage Asset Catalog 内置"按 device idiom + orientation 自动选图 + 系统级 90° 旋转"魔法,会读 Info.plist 顶层 `UISupportedInterfaceOrientations` 决定是否旋转 portrait 资源 - 因此一张物理 portrait 的 PNG 在横屏设备上能被正确旋转后铺满 - **不能照搬到新项目**: - LaunchImage Asset Catalog 在 iOS 14+ 已 deprecated,新项目按苹果推荐用 `LaunchScreen.storyboard` - LaunchScreen.storyboard **没有自动旋转 portrait 资源**的魔法,UIImageView 直接渲染 PNG 物理像素 - 把 `docs/res/Res/Default-568h@2x` 这类**物理 portrait + 画面横躺**的 msext 残留素材直接塞进 LaunchScreen.storyboard 就会看到躺倒画面 - **新项目(LaunchScreen.storyboard)的正确组合**: 1. **素材必须物理像素就是横屏的**(必要时用 `sips -r -90 -s format png` 一次性把 msext 残留 portrait 素材逆时针 90° 输出为标准 PNG,物理像素正确) 2. **Info.plist 显式补一份无后缀 `UISupportedInterfaceOrientations = landscape`**(Xcode 26 General → Deployment Info UI 只写带后缀的 `~iphone` / `~ipad`,少了无后缀 key 会让 LaunchScreen 阶段——device idiom 尚未识别的早期窗口——fallback 到 portrait 渲染再被旋转) 3. UIImageView `contentMode = scaleAspectFit` + 黑底(比 16:9 更宽的现代横屏设备左右补黑边,保画面完整不裁切 logo) - **iOS launch snapshot 缓存粘滞(开发期 iteration 坑)**: - iOS 为加速启动,会把首次渲染的 LaunchScreen 缓存为 PNG snapshot 存到 app sandbox(`Library/Caches/Snapshots//com.apple.UIKit.SplashBoard/`),后续启动不重渲染 - **Xcode 覆盖安装 .app 不会清 sandbox 缓存**,所以改了 Info.plist / LaunchScreen.storyboard / 启动图素材后,Run 出来仍可能是旧 snapshot - 改完启动相关任意一项**必须做**:长按 app → 删除 → Xcode 重新 Run;或模拟器 Erase All Content and Settings;或 `xcrun simctl uninstall booted ` - **终端用户不受影响**:从 IPA 首次安装、或升级新 IPA 第一次启动后即被 iOS 自动刷新;只是开发期反复迭代同一台 device 时会被迷惑 ### 典型案例:H5 与原生通讯接口的真实路径 - **症状**:Design / Contract 文档描述 H5 用 `window.settings.getXxx()` 同步函数读渠道值(如 `getothername` / `getchannelName`);按文档实现完 polyfill 后 H5 业务行为不对,user 反馈"H5 读不到数据" - **错误做法**:基于 Contract §附录 A 列出的旧桥 JSExport 28 方法实现 polyfill,把 9 项 getter 注入到 `window.settings`,认为这是 H5 端的主路径 - **去原项目找答案**:grep `var app_` 在 `daoqi/msext/Class/RootVC/NewRootVC.m:1204` / `gameController.m:2160` / `AppDelegate.m:259` - 发现 1:原项目 `initJSdata()` 是 `[NSString stringWithFormat:@"var app_xxx=...;"]` + `writeToFile:` **写 .js 文件到沙盒**,H5 业务用 `