Phase 1.F: WebView 加载从 file:// 迁到 ylgame://h5 自定义 scheme

为未来 Cocos 子游戏 H5 build 适配铺路(file:// 下 Cocos XHR/fetch 受
null-origin 限制几乎必踩坑),同时保留大厅 + 子游戏跨页 localStorage
共享语义(用单虚拟 host `h5` 让所有 H5 same-origin)。

变更:
- 新增 AppSchemeHandler(WKURLSchemeHandler 单例 + Range/MIME/异步 IO/
  取消语义;闭包只携 Sendable ObjectIdentifier,不捕获 task)
- SandboxPaths 加 lobbyIndexAppURL / subGameIndexAppURL builders
- BridgedWebView 注册 scheme handler(WKWebView init 前)
- WebContainerViewController / SubGameViewController 的 loadFileURL
  → webView.load(URLRequest),OverlayViewController 不变

文档:
- Plan 新增 Phase 1.F (1.18-1.21) + ADR-010 决策记录 + 进度勾选
- Design 新增 §7.6 包含 URL 结构 / 实现要点 / 等价性表 / Cocos 预检脚本
- Contract §0.2 / §4.1 / §10 验收清单同步切换说明(H5 可观察差异:
  location.protocol "file:" → "ylgame:",项目方已 grep 确认现网 H5
  不依赖此字面)

存量影响:file:// → ylgame:// origin 切换时老用户 localStorage 一次性
清零,已与项目方确认业务可接受、不做迁移补偿。

BuildProject 通过。Plan 进度已勾选 1.18/1.19/1.20。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
joywayer
2026-06-29 08:58:00 +08:00
co-authored by Claude Opus 4.7
parent 960adc5491
commit 04e702a99b
8 changed files with 686 additions and 17 deletions
@@ -68,4 +68,30 @@ public enum SandboxPaths {
.appendingPathComponent(start)
.appendingPathComponent("index.html")
}
// MARK: - App scheme URL(Phase 1.F WKURLSchemeHandler 迁移)
//
// 由 AppSchemeHandler 接管的自定义 scheme URL。大厅 + 所有子游戏共用
// 同一虚拟 host (`ylgame://h5`),从而 same-origin → 共享 localStorage。
// 路径前缀区分目标 (`lobby` / `subgame/<dir>`),handler 内反向映射回
// 上面 lobbyRoot / subGameRoot(_:) 的沙盒物理路径。
/// 大厅 H5 入口的 app:// URL:`ylgame://h5/lobby/<gameStart>/index.html`
nonisolated public static var lobbyIndexAppURL: URL {
var c = URLComponents()
c.scheme = AppScheme.scheme
c.host = AppScheme.host
c.path = "/\(AppScheme.lobbyPrefix)/\(BundleConfig.shared.gameStart)/index.html"
// 字面下 path 不含空格 / 中文,force-unwrap 安全
return c.url!
}
/// 子游戏 H5 入口的 app:// URL:`ylgame://h5/subgame/<dir>/<start>/index.html`
nonisolated public static func subGameIndexAppURL(_ dir: String, _ start: String) -> URL {
var c = URLComponents()
c.scheme = AppScheme.scheme
c.host = AppScheme.host
c.path = "/\(AppScheme.subGamePrefix)/\(dir)/\(start)/index.html"
return c.url!
}
}