Phase 2.B:3 项反向 callback 落地(getBattery / getnetwork / appservice)

完成大厅业务期实时状态推送给 H5 的事件驱动链路。每次变化时同时(1)
重写对应 app_*.js 文件供下次 reload,(2)bridge.call 反向推送给当前
页 H5 — 双轨与原 msext 行为等价。

新增 Source/Resource/BatteryMonitor.swift:
  - @MainActor public final class BatteryMonitor,shared 单例 + 幂等 start()
  - 监听 UIDevice.batteryLevelDidChangeNotification + 启动期读首次值
  - currentLevel 同步快照(max(level, 0) 兜底模拟器 -1)+ onChange 回调
  - notification block 内 MainActor.assumeIsolated 安全跨到 main actor

新增 Source/Resource/AppLifecycleObserver.swift:
  - @MainActor public final class AppLifecycleObserver,shared 单例 + 幂等 start()
  - 监听 didEnterBackgroundNotification + willEnterForegroundNotification
  - onBackground / onForeground 双钩子;assumeIsolated 同上

WebContainerViewController.writeAppDataFiles 接入(替换 inline addObserver):
  - 3 个 monitor 启动统一聚合(NetworkMonitor + BatteryMonitor + AppLifecycle)
  - BatteryMonitor.onChange:writeBattery + bridge.call("getBattery", "%.2f")
  - NetworkMonitor.onChange:writeNetwork + bridge.call("getnetwork", "1"/"2"/"3")
  - AppLifecycle.onBackground/Foreground:bridge.call("appservice", "1"/"2")
  - 首次值改读 BatteryMonitor.currentLevel 而非 UIDevice 原始值

至此 Phase 2.B 全部完成(5 项反向 callback:getphoneinfo / getBattery /
getnetwork / appservice / shakeEnd 全部接好)。

剩 Phase 2.C ExternalSubscriptions 生命周期管理(防双发,栈深 ≥ 2 时
下层不发桥事件)。

BuildProject 通过

Plan §5 Phase 2.B 全部勾选

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
joywayer
2026-06-22 18:45:03 +08:00
co-authored by Claude Opus 4.7
parent d38ff0f8c4
commit 23b3a1fdad
4 changed files with 139 additions and 24 deletions
@@ -216,8 +216,10 @@ public final class WebContainerViewController: UIViewController {
)
}
/// 写 4 个 app_*.js 文件,并挂钩 battery / network 变化的重写监听。
/// 与原 msext NewRootVC.initJSdata + changebattery + changenetstate 等价。
/// 写 4 个 app_*.js 文件,并挂钩 battery / network / appservice 三组钩子:
/// 每次变化时同时(1)重写对应 .js 文件(下次 reload 读到新值)
/// 和(2)`bridge.call` 反向推送给当前页 H5(§3.2 [2][3][4])。
/// 与原 msext NewRootVC.initJSdata + changebattery + changenetstate + appservice 等价。
private func writeAppDataFiles(resolved: ResolvedVersion) throws {
let writer = AppDataWriter(
bundleConfig: .shared,
@@ -225,28 +227,43 @@ public final class WebContainerViewController: UIViewController {
containerRole: .lobby
)
// 启动 NetworkMonitor(幂等:内部 started 标记)
// 启动 3 个 monitor(幂等:内部 started 标记)
NetworkMonitor.shared.start()
UIDevice.current.isBatteryMonitoringEnabled = true
BatteryMonitor.shared.start()
AppLifecycleObserver.shared.start()
// 首次写入:4 个文件全部落盘
try writer.writeInitial()
try writer.writeBattery(UIDevice.current.batteryLevel)
try writer.writeBattery(BatteryMonitor.shared.currentLevel)
try writer.writeNetwork(NetworkMonitor.shared.currentCode)
// 持续监听:battery / network 变化时重写对应文件。
// 注意:H5 此次加载已读到首次写入的值,下次 reload 才会读到新值;
// 业务期间的实时变化由 §3.2 [2][3]反向 callback 推送(Phase 2 实现)。
NotificationCenter.default.addObserver(
forName: UIDevice.batteryLevelDidChangeNotification,
object: nil,
queue: .main
) { _ in
try? writer.writeBattery(UIDevice.current.batteryLevel)
let bridge = bridgedWebView.bridge
// §3.2 [2] getBattery — UIDevice 电量变化
// data: 字符串 "%.2f" 形式的小数电量
BatteryMonitor.shared.onChange = { level in
try? writer.writeBattery(level)
bridge.call("getBattery",
data: .string(String(format: "%.2f", level)),
callback: nil)
}
// §3.2 [3] getnetwork — NWPath 变化
// data: 字符串 "1"=无网 / "2"=WiFi / "3"=蜂窝
NetworkMonitor.shared.onChange = { code in
try? writer.writeNetwork(code)
bridge.call("getnetwork",
data: .string("\(code)"),
callback: nil)
}
// §3.2 [4] appservice — App 前后台切换(命名错位沿用历史)
// data: "1"=进入后台 / "2"=回到前台
AppLifecycleObserver.shared.onBackground = {
bridge.call("appservice", data: .string("1"), callback: nil)
}
AppLifecycleObserver.shared.onForeground = {
bridge.call("appservice", data: .string("2"), callback: nil)
}
}