docs:Plan + Design 扩展 Phase 1.14 为 5 子项(含 AppIcon / LaunchScreen / progress / splash UI)
原 Phase 1.14 仅含"WebContainer 16:9 letterbox + 串接整链路",
漏掉了用户实际能看到的三件事:AppIcon / LaunchScreen 启动图 / zip
下载进度条。msext 上线时这三件都有,新外壳上线必须对齐。按用户偏好
方案 A 合并到 Phase 1.14,避免做两遍 WebContainer。
- Plan §5 Phase 1.14 拆为 1.14.a–e 五个子项
- 1.14.a AppIcon:拷贝 docs/res/Images.xcassets/AppIcon-1.appiconset
(9 个 png + Contents.json) 到 ylgamehall/Assets.xcassets
- 1.14.b LaunchScreen:Default-568h@2x~iphone.png → SplashImage
imageset;改写 LaunchScreen.storyboard 横屏铺满 UIImageView
- 1.14.c LobbyZipUpgrader 加 onProgress 回调(@Sendable (Double) -> Void)
- 1.14.d WebContainerViewController:splash 覆盖层(启动图 +
UIProgressView + 状态文字)+ 16:9 letterbox + 启动流水线串接
- 1.14.e webView didFinish 淡出 splash(0.3s 动画 + removeFromSuperview)
- Plan §8 进度追踪同步:5 个子项独立勾选条目
- Design §6.3.5 WebContainer 调用串完整重写:
- Splash UI 6 状态切换表(拼命启动中... / 拉取配置中... /
下载更新中 XX% / 加载大厅... / 淡出)
- runBootPipeline 完整 swift 骨架:含 .shortText 短文本响应处理 /
showmessage 阻塞处理 / IPA 升级 alert / zip 升级 onProgress 回调
- 所有失败 / 阻塞终态都用 UIAlertController(非 splash 文字):
短文本 / showmessage / IPA 升级 / 网络错误 / zip 下载失败
各场景的按钮文案 + tap 行为表
This commit is contained in:
@@ -1236,36 +1236,118 @@ public actor LobbyZipUpgrader {
|
||||
}
|
||||
```
|
||||
|
||||
#### 6.3.5 WebContainer 调用串
|
||||
#### 6.3.5 WebContainer 调用串 + Splash UI 状态机(Phase 1.14)
|
||||
|
||||
WebContainerViewController 同时承担两层:
|
||||
- **下层**:BridgedWebView 嵌入 + 16:9 letterbox(屏幕比 < 16:9 上下黑边;> 16:9 左右黑边)
|
||||
- **上层(Splash 覆盖)**:与 LaunchScreen.storyboard 同款启动图(横屏铺满)+ UIProgressView + 状态文字标签
|
||||
- 启动瞬间:LaunchScreen 静态图(iOS 系统级,0 延迟)
|
||||
- viewDidLoad:WebContainer 把自己的 Splash 覆盖在 BridgedWebView 之上(两者 alpha 0/1 由状态切换)
|
||||
- 启动流水线推进时:updateSplash(text: ..., progress: ...) 更新文字 + 进度条
|
||||
- WKWebView didFinish 后:UIView.animate(duration: 0.3) splash.alpha = 0 → removeFromSuperview
|
||||
|
||||
```swift
|
||||
// Source/WebView/WebContainerViewController.swift(Phase 1.14)
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .black
|
||||
|
||||
setupBridgedWebView() // 16:9 letterbox 嵌入
|
||||
setupSplashOverlay() // 启动图 + 进度条 + 文字标签
|
||||
|
||||
bridgedWebView.webView.navigationDelegate = self
|
||||
|
||||
Task { @MainActor in
|
||||
try await ResourceUnzipper.shared.ensureReady() // 首装解压 Bundle 内 zip
|
||||
let config = try await RemoteConfigClient.shared.fetch()
|
||||
let resolved = VersionResolver.resolve(
|
||||
config: config,
|
||||
agentId: BundleConfig.shared.agent,
|
||||
channelId: BundleConfig.shared.channel,
|
||||
marketId: BundleConfig.shared.market,
|
||||
gameId: BundleConfig.shared.gameId
|
||||
)
|
||||
if resolved.appVersion > LocalVersionReader.localAppVersion {
|
||||
// 弹窗 + Safari 外链 → resolved.appDownload
|
||||
return showAppUpgradeAlert(resolved.appDownload)
|
||||
await runBootPipeline()
|
||||
}
|
||||
}
|
||||
|
||||
private func runBootPipeline() async {
|
||||
do {
|
||||
updateSplash(text: "拼命启动中...", progress: nil)
|
||||
try await ResourceUnzipper.shared.ensureReady()
|
||||
|
||||
updateSplash(text: "拉取配置中...", progress: nil)
|
||||
let outcome = try await RemoteConfigClient.shared.fetch()
|
||||
|
||||
switch outcome {
|
||||
case .shortText(let msg):
|
||||
// 运营杀手锏 #1:弹 alert,App 永停(msext NewRootVC.m:1239-1243 契约)
|
||||
showBlockingAlert(msg)
|
||||
return
|
||||
case .parsed(let cfg):
|
||||
let bc = BundleConfig.shared
|
||||
let resolved = VersionResolver.resolve(
|
||||
config: cfg,
|
||||
agentId: bc.agent,
|
||||
channelId: bc.channel,
|
||||
marketId: bc.market,
|
||||
gameId: bc.gameId
|
||||
)
|
||||
|
||||
// 运营杀手锏 #2:showmessage 非空 → 弹 alert + 完全阻塞
|
||||
if let msg = resolved.showmessage, !msg.isEmpty {
|
||||
showBlockingAlert(msg)
|
||||
return
|
||||
}
|
||||
|
||||
// IPA 升级:弹窗 + Safari 外链(msext NewRootVC.m:1510-1520)
|
||||
if resolved.appVersion > LocalVersionReader.localAppVersion,
|
||||
let dl = resolved.appDownload {
|
||||
showIPAUpgradeAlert(dl)
|
||||
return
|
||||
}
|
||||
|
||||
// H5 zip 升级:进度条实时更新
|
||||
_ = try await LobbyZipUpgrader.shared.upgradeIfNeeded(
|
||||
resolved: resolved,
|
||||
onProgress: { @MainActor [weak self] p in
|
||||
self?.updateSplash(
|
||||
text: String(format: "下载更新中 %d%%", Int(p * 100)),
|
||||
progress: p
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
_ = try await LobbyZipUpgrader.shared.upgradeIfNeeded(
|
||||
remoteGameVersion: resolved.gameVersion,
|
||||
remoteGameZip: resolved.gameZip
|
||||
)
|
||||
|
||||
updateSplash(text: "加载大厅...", progress: nil)
|
||||
bridgedWebView.webView.loadFileURL(
|
||||
SandboxPaths.lobbyIndex,
|
||||
allowingReadAccessTo: SandboxPaths.lobbyRoot
|
||||
)
|
||||
// didFinish 回调里淡出 splash(见 WKNavigationDelegate 扩展)
|
||||
} catch {
|
||||
showFatalAlert(error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - WKNavigationDelegate
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
UIView.animate(withDuration: 0.3, animations: { [weak self] in
|
||||
self?.splash.alpha = 0
|
||||
}, completion: { [weak self] _ in
|
||||
self?.splash.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**Splash UI 状态切换表**:
|
||||
|
||||
| 阶段 | 文字 | progress | 持续时长(典型) |
|
||||
|------|------|----------|---------------|
|
||||
| viewDidLoad 起 | "拼命启动中..." | 隐藏 | ~50 ms |
|
||||
| 首装解压 zip 中 | "拼命启动中..." | 隐藏 | ~50-500 ms |
|
||||
| 拉远端配置中 | "拉取配置中..." | 隐藏 | ~500-2000 ms |
|
||||
| H5 zip 下载中 | "下载更新中 XX%" | 0.0-1.0 | ~1000-3000 ms |
|
||||
| WebView 加载 H5 中 | "加载大厅..." | 隐藏 | ~500-1000 ms |
|
||||
| WebView didFinish | (淡出消失)| - | 300 ms 动画 |
|
||||
|
||||
**所有失败 / 阻塞终态都用 UIAlertController(非 splash 文字)**:
|
||||
- 短文本响应:弹 alert,标题 `gamehallname + 提醒`,单按钮"确定",无 tap 处理(永停)
|
||||
- showmessage 非空:同上
|
||||
- IPA 升级:弹 alert,单按钮"确定"→ openURL(appDownload),永停
|
||||
- 网络错误 / 解析失败:弹 alert,单按钮"重试",点击重新 runBootPipeline()
|
||||
- zip 下载失败:弹 alert,单按钮"重试" + 单按钮"使用旧版本"(回退用 IPA 内 Bundle zip)
|
||||
```
|
||||
|
||||
#### 6.3.6 与 msext 历史实现的差异(不要照抄的部分)
|
||||
|
||||
Reference in New Issue
Block a user