更新 ChannelConfig.plist 中的渠道和游戏目录配置,修正 SKILL.md 文件以存档典型案例

This commit is contained in:
joywayer
2026-08-08 16:18:06 +08:00
parent 7fe089577b
commit 707abcb9d3
4 changed files with 72 additions and 45 deletions
+51
View File
@@ -0,0 +1,51 @@
---
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
+5 -38
View File
@@ -51,47 +51,14 @@ daoqi 仓库当前并存两条工作线:
- 参考原项目 = 把它当作 **"哪些事必须做"的清单** 和 **"哪些坑已经踩过"的备忘**
- 新项目的现代化重构(Swift 6 / SwiftUI / actor 隔离 / SPM 依赖等)依然按原则 B 自由设计;只是设计前先确认"我没有漏掉原项目实际需要解决的事"
### 典型案例: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 时会被迷惑
以下两个完整案例已移到 `.claude/skills/daoqi-lessons/SKILL.md`(用到时再加载,不常驻上下文):
### 典型案例:H5 与原生通讯接口的真实路径
- **典型案例:LaunchScreen orientation(启动图方向错误)** — 处理启动图 / 启动方向问题时读
- **典型案例:H5 与原生通讯接口的真实路径** — 处理 H5 读渠道值 / `app_*.js` 变量 / `window.settings` polyfill 时读
- **症状**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
下面保留的 `app_*` 注入时序案例是原则 A 的规范性说明,常驻不移出。
### 典型案例:`app_*` 注入时序问题(原则 A 不可妥协)
+13 -4
View File
@@ -208,9 +208,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NX5W3B4QP3;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NX5W3B4QP3;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Vendor/AMap",
@@ -242,6 +244,8 @@
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = com.skyapp.ylgamehall;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "iOS dev";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
@@ -258,9 +262,12 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = NX5W3B4QP3;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NX5W3B4QP3;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Vendor/AMap",
@@ -292,6 +299,8 @@
OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = com.skyapp.ylgamehall;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = ios_ad_hoc;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
+3 -3
View File
@@ -5,9 +5,9 @@
<key>gameid</key>
<string>G2hw0ubng0zcoI0r4mx3H2yr4GejidwO</string>
<key>channel</key>
<string>frdt0C1GG0t91P0McFo0rbA1he5yurbS</string>
<string>aouv0LotK0pYyQ0Pdrx0CsdcaezfzrcG</string>
<key>gamedir</key>
<string>frdt0C1GG0t91P0McFo0rbA1he5yurbS</string>
<string>aouv0LotK0pYyQ0Pdrx0CsdcaezfzrcG</string>
<key>gamestart</key>
<string>gamehall</string>
<key>gameconfig</key>
@@ -15,7 +15,7 @@
<key>market</key>
<string>2</string>
<key>agent</key>
<string>00bA05haB0d9ZC0fwGD09Q2OA30insbQ</string>
<string>1B2h0ccl205c390Y28m1Ajdplkuu4wgy</string>
<key>appversion</key>
<string>44</string>
<key>other</key>