Phase 2.A:大厅 8 个简单 handler 落地 + BridgeData 加 nonisolated
闭合 Phase 1.17 联调最后一公里(解决 Xcode 日志 4 个 "no handler registered"
+ 提前落地 4 个无外部依赖的简单 handler)。
新增 7 个 handler 模块(Source/Bridge/Handlers/):
- ClipboardHandler.swift §3.1 [13][14]剪贴板 UIPasteboard.general
- ShakeHandler.swift §3.1 [7][8][9]摇一摇 + §3.2 [5]shakeEnd 反向
canShake / canVoice 状态 + motionEnded 转发钩子
- VoicePlayingHandler.swift §3.1 [6]actor VoiceCenter.shared 开关位
- DeviceInfoHandler.swift §3.1 [21]+ §3.2 [1]getphoneInfo 大写 I 入、
getphoneinfo 小写 i 出反向 callback
DeviceInfoSnapshot 6 字段(IDFA 用 idfv 兜底,
CLAUDE.md 不接 ATT/IDFA)
- BrowserHandler.swift §3.1 [16]UIApplication.open async(Task @MainActor
异步打开,闭包先 cb 不等 open 完成)
- OpenSaomaHandler.swift §3.1 [22]空 stub(契约要求注册)
- StartLocationHandler.swift §3.1 [20]Phase 5 完整实现,Phase 2 stub
扩展 VibratorHandler.swift:
- §3.1 [10]vibrator(原有)+ [11]repeatvibrator(msext RootVC.m:1820 沿用:
实际单次 vibrate 不真循环)+ [12]canclevibrator
BridgeProtocol.swift BridgeData 加 nonisolated:
- 项目默认 SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor 让 BridgeData 跨 actor
访问被拦;asString / asDouble / asInt / asBool / asArray / asObject /
subscript 全部标 nonisolated(纯值类型本就该是 isolation-free)
- 影响所有 @Sendable async handler 闭包内的 data?.asXxx 访问
WebContainerViewController 接入:
- 加 private let shakeHandler = ShakeHandler() 持有
- registerBridgeHandlers() 注册 8 个 handler 模块
- 加 canBecomeFirstResponder = true + viewDidAppear becomeFirstResponder
- 加 motionEnded(_:with:) 转发到 shakeHandler.handleMotionEnded
(motion 检测必需 first responder,否则不触发)
BuildProject 通过。重装 app 后 H5 启动应不再报 "no handler registered" 错误。
Plan §5 Phase 2.A 全部勾选(含 startlocation bonus stub + BridgeData
nonisolated 重构)。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
0a313afe8e
commit
d38ff0f8c4
@@ -98,47 +98,50 @@ extension BridgeData {
|
||||
}
|
||||
|
||||
// MARK: - 访问语法糖
|
||||
// 注:项目默认 SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor 让所有类型默认 main 隔离;
|
||||
// BridgeData 是纯值类型、需要在 handler 闭包(@Sendable)内自由访问,
|
||||
// 所有访问语法糖标 nonisolated 避免跨 actor 限制。
|
||||
|
||||
extension BridgeData {
|
||||
|
||||
public var asString: String? {
|
||||
nonisolated public var asString: String? {
|
||||
if case .string(let s) = self { return s }
|
||||
return nil
|
||||
}
|
||||
|
||||
public var asDouble: Double? {
|
||||
nonisolated public var asDouble: Double? {
|
||||
if case .number(let d) = self { return d }
|
||||
return nil
|
||||
}
|
||||
|
||||
public var asInt: Int? {
|
||||
nonisolated public var asInt: Int? {
|
||||
if case .number(let d) = self { return Int(d) }
|
||||
return nil
|
||||
}
|
||||
|
||||
public var asBool: Bool? {
|
||||
nonisolated public var asBool: Bool? {
|
||||
if case .bool(let b) = self { return b }
|
||||
return nil
|
||||
}
|
||||
|
||||
public var asArray: [BridgeData]? {
|
||||
nonisolated public var asArray: [BridgeData]? {
|
||||
if case .array(let a) = self { return a }
|
||||
return nil
|
||||
}
|
||||
|
||||
public var asObject: [String: BridgeData]? {
|
||||
nonisolated public var asObject: [String: BridgeData]? {
|
||||
if case .object(let o) = self { return o }
|
||||
return nil
|
||||
}
|
||||
|
||||
/// 对象字段访问:`data["title"]?.asString`
|
||||
public subscript(key: String) -> BridgeData? {
|
||||
nonisolated public subscript(key: String) -> BridgeData? {
|
||||
if case .object(let o) = self { return o[key] }
|
||||
return nil
|
||||
}
|
||||
|
||||
/// 数组索引访问:`data[0]?.asString`
|
||||
public subscript(index: Int) -> BridgeData? {
|
||||
nonisolated public subscript(index: Int) -> BridgeData? {
|
||||
if case .array(let a) = self, a.indices.contains(index) { return a[index] }
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user