// // SandboxPaths.swift // ylgamehall // // 集中管理沙盒与 Bundle 路径,避免散落 NSSearchPathFor...。 // 详见 docs/H5-Native-Implementation-Design.md §7.1。 // import Foundation /// 沙盒、Bundle、H5 资源路径的统一入口。所有 ResourceUnzipper / WebView 加载 /// 等模块通过此命名空间获取路径,禁止重新写 `urls(for:in:)` 等散落调用。 public enum SandboxPaths { // MARK: - 基础沙盒目录 /// `Library/Caches/`(系统空间不足时可能被清,需可重建) nonisolated public static var caches: URL { FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0] } /// `Documents/`(用户级持久化,iCloud 备份) nonisolated public static var documents: URL { FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] } /// `.app/` nonisolated public static var bundle: URL { Bundle.main.bundleURL } // MARK: - 大厅 H5 路径(基于 BundleConfig.shared 的当前渠道) /// 大厅 H5 解压根目录:`{Caches}/{gamedir}/` nonisolated public static var lobbyRoot: URL { caches.appendingPathComponent(BundleConfig.shared.gameDir) } /// 大厅 H5 入口 HTML:`{Caches}/{gamedir}/{gamestart}/index.html` nonisolated public static var lobbyIndex: URL { let cfg = BundleConfig.shared return caches .appendingPathComponent(cfg.gameDir) .appendingPathComponent(cfg.gameStart) .appendingPathComponent("index.html") } /// 大厅 H5 版本标记文件:`{Caches}/{gamedir}/{gamestart}/version.xml` /// 由 ResourceUnzipper 判断是否需要解压初始 gamehall.zip。 nonisolated public static var lobbyVersionXML: URL { let cfg = BundleConfig.shared return caches .appendingPathComponent(cfg.gameDir) .appendingPathComponent(cfg.gameStart) .appendingPathComponent("version.xml") } // MARK: - 子游戏 H5 路径(参数化,由 SwitchOverGameData 传入) /// 子游戏 H5 解压根目录:`{Caches}/{dir}/` nonisolated public static func subGameRoot(_ dir: String) -> URL { caches.appendingPathComponent(dir) } /// 子游戏 H5 入口 HTML:`{Caches}/{dir}/{start}/index.html` nonisolated public static func subGameIndex(_ dir: String, _ start: String) -> URL { caches.appendingPathComponent(dir) .appendingPathComponent(start) .appendingPathComponent("index.html") } // MARK: - App scheme URL(Phase 1.F WKURLSchemeHandler 迁移) // // 由 AppSchemeHandler 接管的自定义 scheme URL。大厅 + 所有子游戏共用 // 同一虚拟 host (`ylgame://h5`),从而 same-origin → 共享 localStorage。 // 路径前缀区分目标 (`lobby` / `subgame/`),handler 内反向映射回 // 上面 lobbyRoot / subGameRoot(_:) 的沙盒物理路径。 /// 大厅 H5 入口的 app:// URL:`ylgame://h5/lobby//index.html` nonisolated public static var lobbyIndexAppURL: URL { var c = URLComponents() c.scheme = AppScheme.scheme c.host = AppScheme.host c.path = "/\(AppScheme.lobbyPrefix)/\(BundleConfig.shared.gameStart)/index.html" // 字面下 path 不含空格 / 中文,force-unwrap 安全 return c.url! } /// 子游戏 H5 入口的 app:// URL:`ylgame://h5/subgame///index.html` nonisolated public static func subGameIndexAppURL(_ dir: String, _ start: String) -> URL { var c = URLComponents() c.scheme = AppScheme.scheme c.host = AppScheme.host c.path = "/\(AppScheme.subGamePrefix)/\(dir)/\(start)/index.html" return c.url! } }