From 829cc8f8253838f6d70e02801feb9e4daaf1eb0d Mon Sep 17 00:00:00 2001 From: joywayer Date: Mon, 22 Jun 2026 12:44:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=B1=82=E8=90=BD=E5=9C=B0?= =?UTF-8?q?=20AppDataWriter=20+=20NetworkMonitor=20+=20WebContainer=20?= =?UTF-8?q?=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按 Design §7.5 蓝图落地,让 H5 启动时能从沙盒读到实际渠道/启动/设备 值,闭合 Phase 1.17 联调"app_gameconfig 不正确"现象。 新增 Source/WebView/AppDataWriter.swift: - public struct AppDataWriter(@MainActor) - ContainerRole enum:.lobby / .subGame(name:, dir:) - writeInitial():写 app_data.js(12 项)+ app_gamesname.js(暂只写当前 gameStart 一项,Phase 6 子游戏完整时扩为扫描已装列表) - writeBattery(level:):写 app_battery.js(var app_getbattery=N;) - writeNetwork(code:):写 app_network.js(var app_getnetwork=N;) - 字面严格对齐 msext: * 字符串单引号包裹 'value' * 数值无引号(version=1 / Launchtype=0 / getwifisignalLevel=1) * app_gamesname 用 "var app_gamesname=new Array(...)"(var 后两空格) * 大小写硬约束:Launchtype L 大、getwifisignalLevel wifi 小 + signal/Level 区分 - escape 转义反斜杠 / 单引号 / 换行(避免渠道字段含单引号导致 H5 JS 解析错) - Logger debug 输出文件路径 + 每个 key=value 一行,便于 §7.5.8 联调对账 新增 Source/Resource/NetworkMonitor.swift: - @MainActor public final class NetworkMonitor - NWPathMonitor 最简 wrap:currentCode 同步快照(默认 2 WiFi,启动后被 首次 path 更新)+ onChange MainActor 回调 - shared 单例 + 幂等 start() WebContainer.runBootPipelineSteps 接入: - switch outcome 前提取 let resolved: ResolvedVersion,避免变量作用域 限制 case 内 - 新增 writeAppDataFiles(resolved:):启动 NetworkMonitor + 开 battery 监控 + 写 4 个文件首次值 + 挂 addObserver(battery) + onChange(network) - 调用位置:step 5 LobbyZipUpgrader 之后、step 6 loadFileURL 之前 (与 msext NewRootVC.initJSdata 等价时序) BuildProject 通过 Plan §6.4 里程碑加一行。 Phase 1.17 联调验证:启动后 H5 console 应读到实际 app_channel / app_gameconfig 等值,不再是 H5 zip 包内默认占位。 Co-Authored-By: Claude Opus 4.7 --- docs/Development-Plan.md | 3 +- .../Source/Resource/NetworkMonitor.swift | 48 +++++ ylgamehall/Source/WebView/AppDataWriter.swift | 171 ++++++++++++++++++ .../WebView/WebContainerViewController.swift | 52 +++++- 4 files changed, 267 insertions(+), 7 deletions(-) create mode 100644 ylgamehall/Source/Resource/NetworkMonitor.swift create mode 100644 ylgamehall/Source/WebView/AppDataWriter.swift diff --git a/docs/Development-Plan.md b/docs/Development-Plan.md index 85f7431..dcc8cc8 100644 --- a/docs/Development-Plan.md +++ b/docs/Development-Plan.md @@ -768,7 +768,8 @@ H5 调 `OpenurlTitleData` 打开弹层 WebView,弹层内 H5 用 `window.settin | 2026-06-22 | CLAUDE.md 新增第 2 个典型案例「H5 与原生通讯接口的真实路径」记录"凭语义猜测会一字之差犯错、必须 grep 字面字符串验证"的教训 | `fae7b3d` | | 2026-06-22 | **§7.5 重大路径调整**:从「原生 `writeToFile` 写 4 个 `app_*.js` 文件」改为「H5 团队 zip 自带 + 原生 `WKUserScript(.atDocumentEnd)` / `evaluateJavaScript` 覆盖 `window.app_xxx` 全局变量」 | `246f215` | | 2026-06-22 | **CLAUDE.md 原则 A 升级为第一准则**:H5 端零修改不可妥协,禁止任何"H5 改一行 / 改一个文件 / 加 polyfill / 调时机"的妥协方案。加典型案例 3 复盘 `app_*` 注入时序问题 | `3039daf` | -| 2026-06-22 | **§7.5 路径再次回退(最终)**:撤销 `246f215`,回到 msext 原写文件路径 `AppDataWriter`。原因:WKUserScript 时序(documentStart 被 H5 自带 var 覆盖、documentEnd 又太晚)无法 1:1 等价 msext,任何要求 H5 配合改动的方案违反原则 A 第一准则。Design §7.5 + Contract §4.2 + §10 全面同步回退 | 本次 commit | +| 2026-06-22 | **§7.5 路径再次回退(最终)**:撤销 `246f215`,回到 msext 原写文件路径 `AppDataWriter`。原因:WKUserScript 时序(documentStart 被 H5 自带 var 覆盖、documentEnd 又太晚)无法 1:1 等价 msext,任何要求 H5 配合改动的方案违反原则 A 第一准则。Design §7.5 + Contract §4.2 + §10 全面同步回退 | `13cc24b` | +| 2026-06-22 | **AppDataWriter 代码落地**:新增 `Source/WebView/AppDataWriter.swift` + `Source/Resource/NetworkMonitor.swift`;WebContainer.runBootPipelineSteps 在 step 5 后、step 6 loadFileURL 前调 `writeAppDataFiles(resolved:)` 写 4 个 app_*.js 文件 + 挂 battery/network 变化重写监听。BuildProject 通过 | 本次 commit | > **§3.4.1 撤销说明**:早期 commit `82bad8a` 实现的 `window.settings.getXxx()` polyfill 已撤销 — Contract §附录 A 自身明示「iOS<9 路径,新外壳如最低系统 ≥ iOS 14 可不实现」,本项目最低 iOS 15.6 → polyfill 路径未启用,H5 用 §7.5 的 `app_*.js` 文件路径作为唯一主路径。详细缘由见 Design §3.4.1(撤销说明)和 CLAUDE.md「典型案例」段。 diff --git a/ylgamehall/Source/Resource/NetworkMonitor.swift b/ylgamehall/Source/Resource/NetworkMonitor.swift new file mode 100644 index 0000000..2f86eb5 --- /dev/null +++ b/ylgamehall/Source/Resource/NetworkMonitor.swift @@ -0,0 +1,48 @@ +// +// NetworkMonitor.swift +// ylgamehall +// +// NWPathMonitor 的最简 wrap:提供 currentCode 同步快照 + onChange 事件回调。 +// 用于 AppDataWriter.writeNetwork(_:) 拿首次值 + 变化重写 app_network.js。 +// 详见 docs/H5-Native-Implementation-Design.md §7.5 / §8.4。 +// + +import Foundation +import Network + +/// `app_getnetwork` 的语义码(与 msext 沿用): +/// 1 = 无网,2 = WiFi,3 = 蜂窝 +@MainActor +public final class NetworkMonitor { + + public static let shared = NetworkMonitor() + + public private(set) var currentCode: Int = 2 + + /// 网络变化回调。每次状态变化时主线程触发。 + public var onChange: (@MainActor (Int) -> Void)? + + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "ylgamehall.networkmonitor", qos: .utility) + private var started = false + + public init() {} + + public func start() { + guard !started else { return } + started = true + monitor.pathUpdateHandler = { [weak self] path in + let code: Int = { + if path.status != .satisfied { return 1 } + if path.usesInterfaceType(.wifi) { return 2 } + return 3 + }() + Task { @MainActor in + guard let self else { return } + self.currentCode = code + self.onChange?(code) + } + } + monitor.start(queue: queue) + } +} diff --git a/ylgamehall/Source/WebView/AppDataWriter.swift b/ylgamehall/Source/WebView/AppDataWriter.swift new file mode 100644 index 0000000..af9911d --- /dev/null +++ b/ylgamehall/Source/WebView/AppDataWriter.swift @@ -0,0 +1,171 @@ +// +// AppDataWriter.swift +// ylgamehall +// +// H5 app_*.js 预注入文件机制 — 在 loadFileURL 之前写 4 个 .js 文件到沙盒, +// H5 业务通过