// // LocalAudioHandler.swift // ylgamehall // // H5 → Native handler:srcIsloop — 本地音频播放(背景循环 / 按钮单次) // 契约:docs/H5-Native-Contract.md §3.1 [3] // 原项目: // - 大厅 daoqi/msext NewRootVC.m 用 lobby gamedir/gamestart // - 子游戏 daoqi/msext gameController.m:359-419 用 self.gamefilepath/self.game_name // 两边各自注册,路径根不同。新外壳保留同一 enum 注册器,但调用方注入 assetsRoot。 // // 音频文件实际路径:`{assetsRoot}/assets/wav/{src}` // - lobby:assetsRoot = SandboxPaths.lobbyIndex.deletingLastPathComponent() // - subGame:assetsRoot = SandboxPaths.subGameIndex(dir,name).deletingLastPathComponent() // import Foundation @MainActor public enum LocalAudioHandler { /// 注册 srcIsloop handler。 /// - Parameters: /// - bridge: 桥接器 /// - assetsRoot: 该容器(lobby / subGame)的 H5 资源根目录; /// 音频文件实际路径会拼接 `assets/wav/{src}` 在该根下查找。 public static func register(on bridge: any BridgeProtocol, assetsRoot: URL) { // 【3】srcIsloop — 本地音频播放 // 入参 src : string 音频文件名(位于 {assetsRoot}/assets/wav/{src}) // 入参 isloop : int 0 单次 / 1 循环背景 / -1 停同名循环 // cb: "Response from srcIsloop" bridge.register("srcIsloop") { data, callback in defer { callback?(.string("Response from srcIsloop")) } guard let obj = data?.asObject, let src = obj["src"]?.asString, let isloop = obj["isloop"]?.asInt else { return } let url = assetsRoot .appendingPathComponent("assets") .appendingPathComponent("wav") .appendingPathComponent(src) switch isloop { case 0: await AudioPlayer.shared.playOnce(url) case 1: await AudioPlayer.shared.loopBackground(url, type: src) case -1: await AudioPlayer.shared.stopBackground(type: src) default: break } } } }