// // BundleConfig.swift // ylgamehall // // 渠道注入配置:从 Bundle 内的 ChannelConfig.plist 读 11 个 string 值。 // 设计模式与契约见 docs/H5-Native-Implementation-Design.md §7 / ADR-007。 // import Foundation /// 渠道注入配置(11 项),由 `BundleConfig.shared` 在 App 启动时一次性加载,运行期不变。 /// /// 多渠道分发:构建后用 `plutil` 修改 `.app/ChannelConfig.plist` + 重签, /// 不需要重新 Xcode build。详见 ADR-007。 nonisolated public final class BundleConfig: Sendable { /// App 启动期默认读 main bundle 的 `ChannelConfig.plist`,业务代码统一通过此单例访问。 public static let shared = BundleConfig() public let qiniuDomain: String public let gameId: String public let channel: String public let gameDir: String public let gameStart: String public let gameConfig: String public let market: String public let agent: String public let appVersion: String public let other: String public let appleConfig: String /// 单测可注入任意 bundle 验证不同 plist fixture。 public init(bundle: Bundle = .main) { let dict = Self.loadPlist(bundle: bundle) qiniuDomain = dict["qiniudomain"] ?? "" gameId = dict["gameid"] ?? "" channel = dict["channel"] ?? "" gameDir = dict["gamedir"] ?? "" gameStart = dict["gamestart"] ?? "" gameConfig = dict["gameconfig"] ?? "" market = dict["market"] ?? "" agent = dict["agent"] ?? "" appVersion = dict["appversion"] ?? "" other = dict["other"] ?? "" appleConfig = dict["appleconfig"] ?? "" } private static func loadPlist(bundle: Bundle) -> [String: String] { guard let url = bundle.url(forResource: "ChannelConfig", withExtension: "plist"), let data = try? Data(contentsOf: url), let plist = try? PropertyListSerialization.propertyList( from: data, format: nil) as? [String: String] else { return [:] } return plist } }