Files
youle_app_ios_v2/.claude/skills/daoqi-lessons/SKILL.md
T

52 lines
6.2 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.
---
name: daoqi-lessons
description: 从原项目 daoqi/msext 排查出来的典型案例存档(LaunchScreen 启动图方向错误、H5 与原生通讯接口的真实路径)。在处理启动图 / LaunchScreen / 启动方向问题,或处理 H5 读取渠道值、app_*.js 变量、window.settings polyfill 相关问题时阅读。
---
# 原项目 daoqi 排查案例存档
> 这些是从 `../daoqi/` 实际排查出来的完整案例,佐证 CLAUDE.md「原项目 daoqi:遇到问题时的参考来源」一节的方法论。
> 注意:`典型案例:app_* 注入时序问题(原则 A 不可妥协)` 仍保留在 CLAUDE.md 正文中,因为它是原则 A 的规范性说明,必须常驻。
## 典型案例:LaunchScreen orientation(启动图方向错误)
- **症状**:新项目启动图渲染成竖向矩形再被整体旋转 90°,画面横躺在中间
- **错误做法**:凭 Xcode 26 文档推测、纯调整 storyboard / contentMode / 反复换素材
- **去原项目找答案**`daoqi/msext/Info.plist` + `msext.xcodeproj/project.pbxproj`
- 发现 1Info.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/<bundleID>/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 <bundleID>`
- **终端用户不受影响**:从 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 业务用 `<script src="app_data.js">` 同步引入预生成的 12 个全局变量直接读
- 发现 2:Contract §附录 A 自身标注「iOS<9 路径使用的旧协议,新外壳如最低系统 ≥ iOS 14 可不实现」,新项目最低 iOS 15.6 → 旧桥 polyfill **完全不必要**
- 发现 3Contract §4.2 之前列的 11 项变量与原项目代码不一致 — 漏 6 项(version / Launchtype / getwifisignalLevel / gamename / invitationcode / gamesname)、多 2 项(gameid / compareCode 原项目根本不写)、文件名与变量名混淆(文件 `app_battery.js` 内的变量名是带 get 的 `app_getbattery`,文件名不带 get
- **修复**
1. 撤销已实现的 `window.settings.getXxx()` polyfill 章节(Design §3.4.1
2. 新增 Design §7.5「H5 `app_*.js` 预注入文件机制」覆盖 15 个变量的写入逻辑
3. 按原项目代码全面修订 Contract §4.2(删 gameid/compareCode、补 6 项、修正 battery/network 变量名带 get、注明大厅/子游戏字面差异、加修订记录小节)
- **教训**
- **文档与代码冲突时,原项目代码是真理**。Contract 也可能写错(一份 10 年前写就的文档遗漏 / 误传是常态),必须用 `grep` 验证字面字符串
- **优先验证字面字符串、不要依赖语义猜测**:`app_getbattery``app_battery` 一字之差,AI 助手凭语义"应该就是 app_battery 吧" 100% 会犯错
- **iOS 最低系统版本是契约边界的天然过滤器**:契约里 iOS<9 路径明示可不实现的接口(如 §附录 A 旧桥),新项目最低 iOS 15.6 应当主动剔除,不要"出于完备性"反而实现一份用不到的 polyfill