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
@@ -0,0 +1,49 @@
//
// AppLifecycleObserver.swift
// ylgamehall
//
// UIApplication / onBackground / onForeground
//
// docs/H5-Native-Contract.md §3.2 4appservice callback
// "1" = / "2" = 沿
// Phase 2.11
//
import UIKit
@MainActor
public final class AppLifecycleObserver {
public static let shared = AppLifecycleObserver()
public var onBackground: (@MainActor () -> Void)?
public var onForeground: (@MainActor () -> Void)?
private var started = false
public init() {}
public func start() {
guard !started else { return }
started = true
let nc = NotificationCenter.default
nc.addObserver(
forName: UIApplication.didEnterBackgroundNotification,
object: nil,
queue: .main
) { [weak self] _ in
MainActor.assumeIsolated {
self?.onBackground?()
}
}
nc.addObserver(
forName: UIApplication.willEnterForegroundNotification,
object: nil,
queue: .main
) { [weak self] _ in
MainActor.assumeIsolated {
self?.onForeground?()
}
}
}
}
@@ -0,0 +1,49 @@
//
// BatteryMonitor.swift
// ylgamehall
//
// UIDevice.batteryLevelDidChangeNotification wrap
// currentLevel + onChange 线
//
// docs/H5-Native-Contract.md §3.2 2getBattery callback
// Phase 2.9
//
import UIKit
@MainActor
public final class BatteryMonitor {
public static let shared = BatteryMonitor()
/// 0.01.0 -1BatteryMonitor.start() 0
public private(set) var currentLevel: Float = 0
/// 线
public var onChange: (@MainActor (Float) -> Void)?
private var started = false
public init() {}
public func start() {
guard !started else { return }
started = true
UIDevice.current.isBatteryMonitoringEnabled = true
currentLevel = max(UIDevice.current.batteryLevel, 0)
NotificationCenter.default.addObserver(
forName: UIDevice.batteryLevelDidChangeNotification,
object: nil,
queue: .main
) { [weak self] _ in
// forName: + queue: .main block main
// MainActor.assumeIsolated main actor
MainActor.assumeIsolated {
guard let self else { return }
let level = max(UIDevice.current.batteryLevel, 0)
self.currentLevel = level
self.onChange?(level)
}
}
}
}