diff --git a/CLAUDE.md b/CLAUDE.md index 634fac0..38fb900 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,6 +23,61 @@ daoqi 仓库当前并存两条工作线: --- +## 原项目 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 时会被迷惑 + +--- + ## 文档索引 | 文档 | 角色 | 何时读 | @@ -31,6 +86,7 @@ daoqi 仓库当前并存两条工作线: | `docs/H5-Native-Contract.md` | H5 ↔ 原生 桥接**契约**(黑盒可观察行为) | 涉及桥接接口必读 | | `docs/H5-Native-Implementation-Design.md` | 新外壳实施蓝图(架构、模块、代码骨架) | 实现新外壳必读 | | `docs/Development-Plan.md` | 开发执行计划(Phase 0–10、依赖图、进度追踪) | 排期 / 进度更新必读 | +| `../daoqi/`(仓库同级目录) | 原项目 msext 工作参照实现 | 遇到 iOS 行为差异 / 渠道注入 / 桥接 / SDK 初始化等不确定问题时,**优先参考此处**而非凭推测,详见下文「原项目 daoqi:遇到问题时的参考来源」 | ---