300 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Swift
		
	
	
		
		
			
		
	
	
			300 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Swift
		
	
	
|  | // StrategyConfig.swift | ||
|  | // Defines configuration structures for ad strategies | ||
|  | // Corresponds to StrategyConfig.kt in Android implementation | ||
|  | 
 | ||
|  | import Foundation | ||
|  | 
 | ||
|  | // MARK: - Strategy Types | ||
|  | 
 | ||
|  | public enum InterstitialStrategy: Int { | ||
|  |     case `default` = 0 | ||
|  |     case mab = 1 | ||
|  | } | ||
|  | 
 | ||
|  | public enum RewardedStrategy: Int { | ||
|  |     case `default` = 0 | ||
|  |     case mab = 1 | ||
|  | } | ||
|  | 
 | ||
|  | public enum BannerStrategy: Int { | ||
|  |     case `default` = 0 | ||
|  | } | ||
|  | 
 | ||
|  | protocol StrategyConfig: Decodable {} | ||
|  | 
 | ||
|  | // MARK: - Default Config Classes | ||
|  | 
 | ||
|  | public struct DefaultInterstitialConfig: Codable, StrategyConfig { | ||
|  |     public let adPlatform: String | ||
|  |     public let adUnitId: String | ||
|  |     public let adAmazonSlotId: String? | ||
|  |      | ||
|  |     public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) { | ||
|  |         self.adPlatform = adPlatform | ||
|  |         self.adUnitId = adUnitId | ||
|  |         self.adAmazonSlotId = adAmazonSlotId | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case adPlatform = "ad_platform", | ||
|  |              adUnitId = "ad_unit_id", | ||
|  |              adAmazonSlotId = "ad_amz_slot_id" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct DefaultRewardedConfig: Codable, StrategyConfig { | ||
|  |     public let adPlatform: String | ||
|  |     public let adUnitId: String | ||
|  |     public let adAmazonSlotId: String? | ||
|  |      | ||
|  |     public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) { | ||
|  |         self.adPlatform = adPlatform | ||
|  |         self.adUnitId = adUnitId | ||
|  |         self.adAmazonSlotId = adAmazonSlotId | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case adPlatform = "ad_platform", | ||
|  |              adUnitId = "ad_unit_id", | ||
|  |              adAmazonSlotId = "ad_amz_slot_id" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct DefaultBannerConfig: Codable, StrategyConfig { | ||
|  |     public let adPlatform: String | ||
|  |     public let adUnitId: String | ||
|  |     public let adAmazonSlotId: String? | ||
|  |      | ||
|  |     public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) { | ||
|  |         self.adPlatform = adPlatform | ||
|  |         self.adUnitId = adUnitId | ||
|  |         self.adAmazonSlotId = adAmazonSlotId | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case adPlatform = "ad_platform", | ||
|  |              adUnitId = "ad_unit_id", | ||
|  |              adAmazonSlotId = "ad_amz_slot_id" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct DefaultMRecConfig: Codable, StrategyConfig { | ||
|  |     public let adPlatform: String | ||
|  |     public let adUnitId: String | ||
|  |     public let adAmazonSlotId: String? | ||
|  |      | ||
|  |     public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) { | ||
|  |         self.adPlatform = adPlatform | ||
|  |         self.adUnitId = adUnitId | ||
|  |         self.adAmazonSlotId = adAmazonSlotId | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case adPlatform = "ad_platform", | ||
|  |              adUnitId = "ad_unit_id", | ||
|  |              adAmazonSlotId = "ad_amz_slot_id" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct MabRewardedConfig: Codable, StrategyConfig { | ||
|  |     public let aggregatorConfigs: [AggregatorConfig] | ||
|  |      | ||
|  |     public let showTimeoutInSecond: Double? | ||
|  |      | ||
|  |     init(aggregatorConfigs: [AggregatorConfig], showTimeoutInSecond: Double?) { | ||
|  |         self.aggregatorConfigs = aggregatorConfigs | ||
|  |         self.showTimeoutInSecond = showTimeoutInSecond | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case aggregatorConfigs = "aggregator_configs", | ||
|  |              showTimeoutInSecond = "show_timeout_second" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct MabInterstitialConfig: Codable, StrategyConfig { | ||
|  |     public let aggregatorConfigs: [AggregatorConfig] | ||
|  |      | ||
|  |     public let showTimeoutInSecond: Double? | ||
|  |      | ||
|  |     init(aggregatorConfigs: [AggregatorConfig], showTimeoutInSecond: Double?) { | ||
|  |         self.aggregatorConfigs = aggregatorConfigs | ||
|  |         self.showTimeoutInSecond = showTimeoutInSecond | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case aggregatorConfigs = "aggregator_configs", | ||
|  |              showTimeoutInSecond = "show_timeout_second" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct AggregatorConfig: Codable { | ||
|  |     public let aggregatorId: String | ||
|  |     public let adPlatform: String | ||
|  |     public let raiseRate: Double | ||
|  |     public let selfRaiseRate: Double? | ||
|  |     public let cacheExpireInSecond: Double | ||
|  |     public let priority: Int | ||
|  |     public let adUnitIds: [AdUnitSpec] | ||
|  |     public let loadTimeoutInSecond: Double? | ||
|  |      | ||
|  |     init(aggregatorId: String, adPlatform: String, raiseRate: Double, selfRaiseRate: Double?, cacheExpireInSecond: Double, priority: Int, adUnitIds: [AdUnitSpec], loadTimeoutInSecond: Double?) { | ||
|  |         self.aggregatorId = aggregatorId | ||
|  |         self.adPlatform = adPlatform | ||
|  |         self.raiseRate = raiseRate | ||
|  |         self.selfRaiseRate = selfRaiseRate | ||
|  |         self.cacheExpireInSecond = cacheExpireInSecond | ||
|  |         self.priority = priority | ||
|  |         self.adUnitIds = adUnitIds | ||
|  |         self.loadTimeoutInSecond = loadTimeoutInSecond | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case aggregatorId = "aggregator_id", | ||
|  |              adPlatform = "ad_platform", | ||
|  |              raiseRate = "raise_rate", | ||
|  |              selfRaiseRate = "self_raise_rate", | ||
|  |              cacheExpireInSecond = "cache_expire_second", | ||
|  |              priority = "priority", | ||
|  |              adUnitIds = "ad_unit_ids", | ||
|  |              loadTimeoutInSecond = "load_timeout_second" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | public struct AdUnitSpec: Codable { | ||
|  |     public let adUnitId: String | ||
|  |     public let adAmazonSlotId: String? | ||
|  |      | ||
|  |     public let floorEcpm: Double | ||
|  |      | ||
|  |     public var floor: Double { | ||
|  |         return floorEcpm / 1000 | ||
|  |     } | ||
|  |      | ||
|  |     init(adUnitId: String, adAmazonSlotId: String?, floorEcpm: Double = 0.0) { | ||
|  |         self.adUnitId = adUnitId | ||
|  |         self.adAmazonSlotId = adAmazonSlotId | ||
|  |         self.floorEcpm = floorEcpm | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys : String, CodingKey { | ||
|  |         case adUnitId = "ad_unit_id", | ||
|  |              adAmazonSlotId = "ad_amz_slot_id", | ||
|  |              floorEcpm = "floor_ecpm" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | // MARK: - AdEngineConfig | ||
|  | 
 | ||
|  | 
 | ||
|  | public struct AdEngineConfig: Codable { | ||
|  |     public let strategy: Int | ||
|  |     public let faUnitId: String | ||
|  |     public let config: [String: Any] | ||
|  |      | ||
|  |     public init(strategy: Int, faUnitId: String, config: [String: Any]) { | ||
|  |         self.strategy = strategy | ||
|  |         self.faUnitId = faUnitId | ||
|  |         self.config = config | ||
|  |     } | ||
|  |      | ||
|  |     public func encode(to encoder: Encoder) throws { | ||
|  |         var container = encoder.container(keyedBy: CodingKeys.self) | ||
|  |         try container.encode(strategy, forKey: .strategy) | ||
|  |         try container.encode(faUnitId, forKey: .faUnitId) | ||
|  |         try container.encode(JSONCodable(config), forKey: .config) | ||
|  |     } | ||
|  |      | ||
|  |     public init(from decoder: Decoder) throws { | ||
|  |         let container = try decoder.container(keyedBy: CodingKeys.self) | ||
|  |         strategy = try container.decode(Int.self, forKey: .strategy) | ||
|  |         faUnitId = try container.decode(String?.self, forKey: .faUnitId) ?? "default" | ||
|  |         config = try container.decode(JSONCodable.self, forKey: .config).value as! Dictionary | ||
|  |     } | ||
|  |      | ||
|  |     private enum CodingKeys: String, CodingKey { | ||
|  |         case strategy = "strategy", | ||
|  |              config = "config", | ||
|  |             faUnitId = "fa_unit_id" | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | private struct JSONCodable: Codable { | ||
|  |     let value: Any | ||
|  |      | ||
|  |     init(_ value: Any) { | ||
|  |         self.value = value | ||
|  |     } | ||
|  |      | ||
|  |     init(from decoder: Decoder) throws { | ||
|  |         let container = try decoder.singleValueContainer() | ||
|  |          | ||
|  |         if container.decodeNil() { | ||
|  |             self.value = NSNull() | ||
|  |         } else if let bool = try? container.decode(Bool.self) { | ||
|  |             self.value = bool | ||
|  |         } else if let int = try? container.decode(Int.self) { | ||
|  |             self.value = int | ||
|  |         } else if let uint = try? container.decode(UInt.self) { | ||
|  |             self.value = uint | ||
|  |         } else if let double = try? container.decode(Double.self) { | ||
|  |             self.value = double | ||
|  |         } else if let string = try? container.decode(String.self) { | ||
|  |             self.value = string | ||
|  |         } else if let array = try? container.decode([JSONCodable].self) { | ||
|  |             self.value = array.map { $0.value } | ||
|  |         } else if let dictionary = try? container.decode([String: JSONCodable].self) { | ||
|  |             self.value = dictionary.mapValues { $0.value } | ||
|  |         } else { | ||
|  |             throw DecodingError.dataCorruptedError( | ||
|  |                 in: container, | ||
|  |                 debugDescription: "AnyCodable cannot decode value" | ||
|  |             ) | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func encode(to encoder: Encoder) throws { | ||
|  |         var container = encoder.singleValueContainer() | ||
|  |          | ||
|  |         switch self.value { | ||
|  |         case is NSNull: | ||
|  |             try container.encodeNil() | ||
|  |         case let bool as Bool: | ||
|  |             try container.encode(bool) | ||
|  |         case let int as Int: | ||
|  |             try container.encode(int) | ||
|  |         case let uint as UInt: | ||
|  |             try container.encode(uint) | ||
|  |         case let double as Double: | ||
|  |             try container.encode(double) | ||
|  |         case let string as String: | ||
|  |             try container.encode(string) | ||
|  |         case let array as [Any]: | ||
|  |             try container.encode(array.map { JSONCodable($0) }) | ||
|  |         case let dictionary as [String: Any]: | ||
|  |             try container.encode(dictionary.mapValues { JSONCodable($0) }) | ||
|  |         default: | ||
|  |             let context = EncodingError.Context( | ||
|  |                 codingPath: container.codingPath, | ||
|  |                 debugDescription: "AnyCodable cannot encode value \(self.value)" | ||
|  |             ) | ||
|  |             throw EncodingError.invalidValue(self.value, context) | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | extension StrategyConfig | ||
|  | { | ||
|  |     init<Key: Hashable>(_ dict: [Key: Any]) throws | ||
|  |     { | ||
|  |         do { | ||
|  |             let data = try JSONSerialization.data(withJSONObject: dict, options: []) | ||
|  |             self = try JSONDecoder().decode(Self.self, from: data) | ||
|  |         } catch { | ||
|  |             Logger.e(tag: "StrategyConfig", message: "strategy config deserialize to \(Self.self) fail, data is \(dict)") | ||
|  |             throw error; | ||
|  |         } | ||
|  |     } | ||
|  | } |