// // ShakeHandler.swift // ylgamehall // // H5 → Native handler 三件套 + 反向 callback: // startshake / stopshake / SwitchShake → shakeEnd // // 契约:docs/H5-Native-Contract.md §3.1 [7][8][9] + §3.2 [5] // Design:§8.7 ShakeKit // import UIKit /// 摇一摇状态控制 + 反向 callback 桥接器(@MainActor 实例化,VC 注入)。 /// /// 由 WebContainerViewController 在 viewDidLoad 时创建,并: /// - 调用 `register(on:)` 注册 3 个 handler /// - 重写 `motionEnded(_:with:)` 转发到 `handleMotionEnded(_:)` /// - `viewDidAppear` 时调 `becomeFirstResponder()`(否则 motionEnded 不触发) @MainActor public final class ShakeHandler { /// 摇一摇总开关(startshake / stopshake 控制) public private(set) var canShake: Bool = false /// 摇一摇音效开关(SwitchShake 控制) public private(set) var canVoice: Bool = true private weak var bridge: (any BridgeProtocol)? public init() {} public func register(on bridge: any BridgeProtocol) { self.bridge = bridge // 【7】startshake — 开摇 // 入参忽略 → canshake = YES // cb:"startshake from accreditlogin"(字面字符串带后缀,沿用历史; // H5 不依赖此值,但严格拷贝保留契约等价) bridge.register("startshake") { [weak self] _, callback in Task { @MainActor in self?.canShake = true } callback?(.string("startshake from accreditlogin")) } // 【8】stopshake — 关摇 // 入参忽略 → canshake = NO;cb 同 startshake bridge.register("stopshake") { [weak self] _, callback in Task { @MainActor in self?.canShake = false } callback?(.string("startshake from accreditlogin")) } // 【9】SwitchShake — 摇一摇音效开关 // 入参 int 1 → canvoice = YES,其它 → canvoice = NO // cb:"SwitchShake" bridge.register("SwitchShake") { [weak self] data, callback in let on = (data?.asInt ?? 0) == 1 Task { @MainActor in self?.canVoice = on } callback?(.string("SwitchShake")) } } /// 由 WebContainerViewController.motionEnded(_:with:) 转发调用。 /// 触发反向 callback `shakeEnd`(仅 `canshake=YES` 时)。 public func handleMotionEnded(_ motion: UIEvent.EventSubtype) { guard motion == .motionShake, canShake else { return } // Phase 2.3 暂不播放摇一摇音效(依赖 AudioKit / shake_sound_male.mp3, // 留待 Phase 3 AudioKit 完整时补;canVoice 状态保留供后续使用) bridge?.call("shakeEnd", data: nil, callback: nil) } }