// // LocalAudioHandler.swift // ylgamehall // // H5 → Native handler:srcIsloop — 本地音频播放(背景循环 / 按钮单次) // 契约:docs/H5-Native-Contract.md §3.1 [3] // 原项目:daoqi/msext NewRootVC.m initJSdata 关联 buttunPlayer / backgroundPlayer // // 本地音频文件路径:`{Caches}/{gamedir}/{gamestart}/assets/wav/{src}` // 与 SandboxPaths.lobbyIndex 同一根目录下 assets/wav 子目录 // import Foundation @MainActor public enum LocalAudioHandler { public static func register(on bridge: any BridgeProtocol) { // 【3】srcIsloop — 本地音频播放 // 入参 src : string 音频文件名(位于 lobbyAssets/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 = audioFileURL(src: 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 } } } /// `{lobbyAssets}/assets/wav/{src}` —— 与 msext NewRootVC 路径约定一致。 /// H5 业务调用前会先用 zip 升级(gamehall.zip 内含 assets/wav/*.wav 音频文件)。 nonisolated private static func audioFileURL(src: String) -> URL { SandboxPaths.lobbyIndex .deletingLastPathComponent() // {Caches}/{gamedir}/{gamestart}/ .appendingPathComponent("assets") .appendingPathComponent("wav") .appendingPathComponent(src) } }