业务期 app_getbattery / app_getnetwork 改为 evaluateJavaScript 重新赋值
按用户指示调整变化时机制:
启动期(保持):loadFileURL 之前写 4 个 app_*.js 文件,H5 同步
<script src> 引入读到实际值
业务期(调整):变化时**不重写文件**,改为
webView.evaluateJavaScript("window.app_getbattery=N;") 直接重新赋值
全局变量。原因:H5 已加载完后 <script src> 不会再 fetch,重写文件
对当前页面无影响(仅影响下次 reload),改 evaluateJavaScript 即时
生效 + 无文件 IO 开销。
与 §3.2 反向 callback 双轨同时执行:
- evaluateJavaScript 让 H5 业务期同步读 app_xxx 永远拿到最新值
- bridge.call 让 H5 注册的 callback handler 收到事件主动响应
WebContainerViewController.writeAppDataFiles 改动:
- BatteryMonitor.onChange:Task @MainActor await
webView.evaluateJavaScript("window.app_getbattery=N;") + bridge.call
- NetworkMonitor.onChange:同款 evaluateJavaScript + bridge.call
- AppLifecycleObserver:appservice 无对应 app_* 全局变量,只走 bridge.call
文档同步:
- Design §7.5.2 改为「两阶段」表述:启动期写文件 + 业务期 evaluateJavaScript
- Design §7.5.4 接入点代码示例同步
- Contract §4.2 app_battery.js / app_network.js 子节更新时机段
- Contract §4.2 修订记录加一行
- Plan §6.4 里程碑加一行 + 前两轮 commit hash 补充
BuildProject 通过
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
23b3a1fdad
commit
4986f36967
@@ -2006,16 +2006,29 @@ done
|
||||
| 14 | `app_getbattery` | `String(format: "%.2f", UIDevice.batteryLevel)` | 同 | `UIDevice.current.batteryLevel`,每次 viewWillAppear + battery 变化通知 | `app_battery.js` |
|
||||
| 15 | `app_getnetwork` | `"1"`/`"2"`/`"3"` | 同 | `NWPathMonitor` 状态映射(1 无网 / 2 WiFi / 3 蜂窝),每次 viewWillAppear + network 变化通知 | `app_network.js` |
|
||||
|
||||
#### 7.5.2 4 个文件的写入时机与内容
|
||||
#### 7.5.2 写入时机与机制(**两阶段:启动期写文件 + 业务期 evaluateJavaScript**)
|
||||
|
||||
```
|
||||
{gamedir}/{gamestart}/app_data.js 一次性,loadFileURL 前(含 #1-#12 共 12 个 var)
|
||||
{gamedir}/{gamestart}/app_gamesname.js 一次性 + 新装子游戏后增量重写(#13)
|
||||
{gamedir}/{gamestart}/app_battery.js loadFileURL 前一次 + viewWillAppear + 前台 + batteryLevelDidChange(#14)
|
||||
{gamedir}/{gamestart}/app_network.js loadFileURL 前一次 + viewWillAppear + NWPathMonitor 变化(#15)
|
||||
启动期(loadFileURL 之前,原生写文件到沙盒,供 H5 同步 <script src> 引入):
|
||||
{gamedir}/{gamestart}/app_data.js 一次性写(#1-#12 共 12 个 var)
|
||||
{gamedir}/{gamestart}/app_gamesname.js 一次性写(#13)
|
||||
{gamedir}/{gamestart}/app_battery.js loadFileURL 前补一次(首次值)
|
||||
{gamedir}/{gamestart}/app_network.js loadFileURL 前补一次(首次值)
|
||||
|
||||
业务期(H5 已加载完后,原生 evaluateJavaScript 直接重新赋值 window.app_*):
|
||||
battery 变化 → webView.evaluateJavaScript("window.app_getbattery=N;") (不重写文件)
|
||||
network 变化 → webView.evaluateJavaScript("window.app_getnetwork=N;") (不重写文件)
|
||||
子游戏装新 → 重新进入大厅时调 writer.writeGamesName 一次(增量更新文件)
|
||||
```
|
||||
|
||||
**为什么是写文件**(保留与 msext 等价的时序):H5 业务页面用 `<script src="app_data.js">` **同步**引入,必须在 `loadFileURL` 之前文件已存在于沙盒;H5 启动时 `<script>` 直接读到正确值,H5 业务代码顶层 `var x = app_xxx` 也能直接拿到实际值。
|
||||
**为什么启动期写文件**(保留与 msext 等价的时序):H5 启动时用 `<script src="app_data.js">` **同步**引入,必须在 `loadFileURL` 之前文件已存在于沙盒;H5 业务代码顶层 `var x = app_xxx` 直接拿到实际值。
|
||||
|
||||
**为什么业务期不重写文件,改用 evaluateJavaScript**:H5 加载完成后,`<script src>` 不会再 fetch,所以重写文件对当前页面无影响(仅影响下次 reload)。直接 `evaluateJavaScript("window.app_xxx = N;")` 重新赋值全局变量,H5 业务期同步读 `app_xxx` 立即拿到最新值,效率更高、无文件 IO 开销。
|
||||
|
||||
> **与 §3.2 反向 callback 的关系**:两条路径并存、互为补充:
|
||||
> - **`window.app_xxx` 重新赋值**:H5 业务代码任何时刻同步读 `app_getbattery` 都拿到最新值
|
||||
> - **`bridge.call("getBattery", ...)` 反向推送**:H5 注册的 callback 收到事件主动响应(业务期变化感知)
|
||||
> 两路同时执行(onChange 闭包内一次完成),与原 msext changebattery + js eval 双轨等价。
|
||||
|
||||
> **不要照搬 `WKUserScript` 注入路径**(曾在 commit `246f215` 尝试过,已撤回):
|
||||
> - `.atDocumentStart` 注入会被 H5 自带 `app_*.js` 内的 `var app_xxx = "默认值"` 声明覆盖
|
||||
@@ -2183,10 +2196,15 @@ private func runBootPipelineSteps() async throws {
|
||||
containerRole: .lobby
|
||||
)
|
||||
|
||||
// 1. loadFileURL 前一次性写 4 个 app_*.js 文件(覆盖 H5 zip 包内自带的版本)
|
||||
try writer.writeInitial() // app_data.js + app_gamesname.js
|
||||
try writer.writeBattery(UIDevice.current.batteryLevel) // app_battery.js
|
||||
try writer.writeNetwork(networkMonitor.currentCode) // app_network.js
|
||||
// 1. 启动期:loadFileURL 前一次性写 4 个 app_*.js 文件
|
||||
// H5 通过 <script src> 同步引入即可读到实际值
|
||||
NetworkMonitor.shared.start()
|
||||
BatteryMonitor.shared.start()
|
||||
AppLifecycleObserver.shared.start()
|
||||
|
||||
try writer.writeInitial() // app_data.js + app_gamesname.js
|
||||
try writer.writeBattery(BatteryMonitor.shared.currentLevel) // app_battery.js
|
||||
try writer.writeNetwork(NetworkMonitor.shared.currentCode) // app_network.js
|
||||
|
||||
splash.update(text: "加载大厅...", progress: nil)
|
||||
bridgedWebView.webView.loadFileURL(
|
||||
@@ -2194,18 +2212,30 @@ private func runBootPipelineSteps() async throws {
|
||||
allowingReadAccessTo: SandboxPaths.lobbyRoot
|
||||
)
|
||||
|
||||
// 2. 持续监听 battery / network 变化,重写对应 .js 文件
|
||||
// (H5 此次加载已读到首次写入的值;下次 reload 才会读到新值,
|
||||
// 业务期间的实时变化由 §3.2 [2][3]反向 callback 推送)
|
||||
UIDevice.current.isBatteryMonitoringEnabled = true
|
||||
NotificationCenter.default.addObserver(
|
||||
forName: UIDevice.batteryLevelDidChangeNotification,
|
||||
object: nil, queue: .main
|
||||
) { _ in
|
||||
try? writer.writeBattery(UIDevice.current.batteryLevel)
|
||||
// 2. 业务期:变化时**不重写文件**,改为 evaluateJavaScript 重新赋值 window.app_*
|
||||
// + bridge.call 反向通知(双轨同时进行)
|
||||
let bridge = bridgedWebView.bridge
|
||||
let webView = bridgedWebView.webView
|
||||
|
||||
BatteryMonitor.shared.onChange = { level in
|
||||
let value = String(format: "%.2f", level)
|
||||
Task { @MainActor in
|
||||
_ = try? await webView.evaluateJavaScript("window.app_getbattery=\(value);")
|
||||
}
|
||||
bridge.call("getBattery", data: .string(value), callback: nil)
|
||||
}
|
||||
networkMonitor.stateDidChange = { code in
|
||||
try? writer.writeNetwork(code)
|
||||
NetworkMonitor.shared.onChange = { code in
|
||||
Task { @MainActor in
|
||||
_ = try? await webView.evaluateJavaScript("window.app_getnetwork=\(code);")
|
||||
}
|
||||
bridge.call("getnetwork", data: .string("\(code)"), callback: nil)
|
||||
}
|
||||
// appservice 无对应 app_* 全局变量,只走 bridge.call
|
||||
AppLifecycleObserver.shared.onBackground = {
|
||||
bridge.call("appservice", data: .string("1"), callback: nil)
|
||||
}
|
||||
AppLifecycleObserver.shared.onForeground = {
|
||||
bridge.call("appservice", data: .string("2"), callback: nil)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user