362 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Swift
		
	
	
		
		
			
		
	
	
			362 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Swift
		
	
	
|  | // AdsEngineManager.swift | ||
|  | // Manages all ad engines | ||
|  | // Corresponds to AdsEngineManager.kt in Android implementation | ||
|  | 
 | ||
|  | import Foundation | ||
|  | import UIKit | ||
|  | 
 | ||
|  | class AdsEngineManager { | ||
|  |      | ||
|  |     private let viewController: UIViewController | ||
|  |      | ||
|  |     private var interstitialAdEngines: [Int: InterstitialAdEngine] = [:] | ||
|  |     private var rewardedAdEngines: [Int: RewardedAdEngine] = [:] | ||
|  |     private var bannerAdEngines: [Int: BannerAdEngine] = [:] | ||
|  |     private var mrecAdEngines: [Int: MRecAdEngine] = [:] | ||
|  |      | ||
|  |     private var supportedAdsSdk: [AdPlatform: GuruAdsSdk] = [:] | ||
|  |      | ||
|  |     init(viewController: UIViewController) { | ||
|  |         self.viewController = viewController | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - Logging | ||
|  |      | ||
|  |     private func logInfo(_ message: String) { | ||
|  |         Logger.i(tag: "StrategyManager", message: message) | ||
|  |     } | ||
|  |      | ||
|  |     private func logError(_ message: String, error: Error? = nil) { | ||
|  |         Logger.e(tag: "StrategyManager", message: message) | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - SDK Management | ||
|  |      | ||
|  |     internal func addAdsSdk(_ adsSdk: GuruAdsSdk) { | ||
|  |         supportedAdsSdk[adsSdk.adPlatform] = adsSdk | ||
|  |     } | ||
|  |      | ||
|  |     private func getAdsSdk(adPlatform: AdPlatform) -> GuruAdsSdk? { | ||
|  |         return supportedAdsSdk[adPlatform] | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - Interstitial Engine Methods | ||
|  |      | ||
|  |     private func createDefaultInterstitialAdEngine( | ||
|  |         id: Int, | ||
|  |         config: DefaultInterstitialConfig | ||
|  |     ) -> DefaultInterstitialAdEngine? { | ||
|  |         if let adSdk = getAdsSdk(adPlatform: AdPlatform.fromName(config.adPlatform))?.obtainInterstitialAd( | ||
|  |             adConfig: AdConfig( | ||
|  |                 engineId: id, | ||
|  |                 adUnitId: config.adUnitId, | ||
|  |                 adAmazonSlotId: config.adAmazonSlotId | ||
|  |             ) | ||
|  |         ) { | ||
|  |            return DefaultInterstitialAdEngine(viewController: viewController, id: id, ad: adSdk) | ||
|  |         } else { | ||
|  |             return nil; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     private func createMabInterstitialEngine( | ||
|  |         id: Int, | ||
|  |         faUnitId: String, | ||
|  |         config: MabInterstitialConfig | ||
|  |     ) -> MabInterstitialEngine { | ||
|  |         return MabInterstitialEngine(viewController: viewController, id: id, faUnitId: faUnitId, mabConfig: config) { | ||
|  |             [weak self] adPlatform, adConfig in | ||
|  |             self?.getAdsSdk(adPlatform: adPlatform)?.obtainInterstitialAd(adConfig: adConfig) | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func getInterstitialAdEngine(id: Int) -> InterstitialAdEngine? { | ||
|  |         return interstitialAdEngines[id] | ||
|  |     } | ||
|  |      | ||
|  |     func createInterstitialAdEngine(adEngineConfig: AdEngineConfig) -> InterstitialAdEngine? { | ||
|  |         // Potential hashcode collision | ||
|  |         let id = adEngineConfig.hashCode() | ||
|  |         logInfo("createInterstitialAdEngine: \(id)") | ||
|  |      | ||
|  |          | ||
|  |         let engine:InterstitialAdEngine? = getInterstitialAdEngine(id: id) ?? { | ||
|  |             logInfo("config parsed!, with strategy \(InterstitialStrategy.default.rawValue)") | ||
|  |             switch adEngineConfig.strategy { | ||
|  |             case InterstitialStrategy.default.rawValue: | ||
|  |                 guard let config = try? DefaultInterstitialConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultInterstitialAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |             case InterstitialStrategy.mab.rawValue: | ||
|  |                 guard let config = try? MabInterstitialConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createMabInterstitialEngine(id: id, faUnitId: adEngineConfig.faUnitId, config: config) | ||
|  |             default: | ||
|  |                 // todo forward compatible | ||
|  |                 guard let config = try? DefaultInterstitialConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultInterstitialAdEngine( | ||
|  |                     id: id, | ||
|  |                     config:config | ||
|  |                 ) | ||
|  |             } | ||
|  |         }() | ||
|  |          | ||
|  |         if let engine = engine { | ||
|  |             interstitialAdEngines[id] = engine | ||
|  |         } | ||
|  |          | ||
|  |         return engine | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - Rewarded Engine Methods | ||
|  |      | ||
|  |     private func createDefaultRewardedAdEngine( | ||
|  |         id: Int, | ||
|  |         config: DefaultRewardedConfig | ||
|  |     ) -> DefaultRewardedAdEngine? { | ||
|  |         if let adSdk = getAdsSdk(adPlatform: AdPlatform.fromName(config.adPlatform))?.obtainRewardedAd( | ||
|  |             adConfig: AdConfig( | ||
|  |                 engineId: id, | ||
|  |                 adUnitId: config.adUnitId, | ||
|  |                 adAmazonSlotId: config.adAmazonSlotId | ||
|  |             ) | ||
|  |         ) { | ||
|  |            return DefaultRewardedAdEngine(viewController: viewController, id: id, ad: adSdk) | ||
|  |         } else { | ||
|  |             return nil; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     private func createMabRewardedEngine( | ||
|  |         id: Int, | ||
|  |         faUnitId: String, | ||
|  |         config: MabRewardedConfig | ||
|  |     ) -> MabRewardedEngine { | ||
|  |         return MabRewardedEngine(viewController: viewController, id: id, faUnitId: faUnitId, mabConfig: config) { | ||
|  |             [weak self] adPlatform, adConfig in | ||
|  |             self?.getAdsSdk(adPlatform: adPlatform)?.obtainRewardedAd(adConfig: adConfig) | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func getRewardedAdEngine(id: Int) -> RewardedAdEngine? { | ||
|  |         return rewardedAdEngines[id] | ||
|  |     } | ||
|  |      | ||
|  |     func createRewardedAdEngine(adEngineConfig: AdEngineConfig) -> RewardedAdEngine? { | ||
|  |         let id = adEngineConfig.hashCode() | ||
|  |         logInfo("createRewardedAdEngine: \(id)") | ||
|  |          | ||
|  |         let engine = getRewardedAdEngine(id: id) ?? { | ||
|  |             switch adEngineConfig.strategy { | ||
|  |             case RewardedStrategy.default.rawValue: | ||
|  |                 guard let config = try? DefaultRewardedConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultRewardedAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |             case RewardedStrategy.mab.rawValue: | ||
|  |                 guard let config = try? MabRewardedConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createMabRewardedEngine(id: id, faUnitId: adEngineConfig.faUnitId, config: config) | ||
|  |                  | ||
|  |             default: | ||
|  |                 guard let config = try? DefaultRewardedConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultRewardedAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |             } | ||
|  |         }() | ||
|  |          | ||
|  |         if let engine = engine { | ||
|  |             rewardedAdEngines[id] = engine | ||
|  |         } | ||
|  |          | ||
|  |         return engine | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - Banner Engine Methods | ||
|  |      | ||
|  |     private func createDefaultBannerAdEngine( | ||
|  |         id: Int, | ||
|  |         config: DefaultBannerConfig | ||
|  |     ) -> DefaultBannerAdEngine? { | ||
|  |         if let adSdk = getAdsSdk(adPlatform: AdPlatform.fromName(config.adPlatform))?.obtainBannerAd( | ||
|  |             adConfig: AdConfig( | ||
|  |                 engineId: id, | ||
|  |                 adUnitId: config.adUnitId, | ||
|  |                 adAmazonSlotId: config.adAmazonSlotId | ||
|  |             ) | ||
|  |         ) { | ||
|  |            return DefaultBannerAdEngine(viewController: viewController, id: id, ad: adSdk) | ||
|  |         } else { | ||
|  |             return nil; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func getBannerAdEngine(id: Int) -> BannerAdEngine? { | ||
|  |         return bannerAdEngines[id] | ||
|  |     } | ||
|  |      | ||
|  |     func createBannerAdEngine(adEngineConfig: AdEngineConfig) -> BannerAdEngine? { | ||
|  |         let id = adEngineConfig.hashCode() | ||
|  |         logInfo("createBannerAdEngine: \(id)") | ||
|  |          | ||
|  |         let engine = getBannerAdEngine(id: id) ?? { | ||
|  |             switch adEngineConfig.strategy { | ||
|  |             case BannerStrategy.default.rawValue: | ||
|  |                 guard let config = try? DefaultBannerConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultBannerAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |                  | ||
|  |             default: | ||
|  |                 guard let config = try? DefaultBannerConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultBannerAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |             } | ||
|  |         }() | ||
|  |          | ||
|  |         if let engine = engine { | ||
|  |             bannerAdEngines[id] = engine | ||
|  |         } | ||
|  |          | ||
|  |         return engine | ||
|  |     } | ||
|  |      | ||
|  |     // MARK: - MRec Engine Methods | ||
|  |      | ||
|  |     private func createDefaultMRecAdEngine( | ||
|  |         id: Int, | ||
|  |         config: DefaultMRecConfig | ||
|  |     ) -> DefaultMRecAdEngine? { | ||
|  |         if let adSdk = getAdsSdk(adPlatform: AdPlatform.fromName(config.adPlatform))?.obtainMRecAd( | ||
|  |             adConfig: AdConfig( | ||
|  |                 engineId: id, | ||
|  |                 adUnitId: config.adUnitId, | ||
|  |                 adAmazonSlotId: config.adAmazonSlotId | ||
|  |             ) | ||
|  |         ) { | ||
|  |            return DefaultMRecAdEngine(viewController: viewController, id: id, ad: adSdk) | ||
|  |         } else { | ||
|  |             return nil; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     func getMRecAdEngine(id: Int) -> MRecAdEngine? { | ||
|  |         return mrecAdEngines[id] | ||
|  |     } | ||
|  |      | ||
|  |     func createMRecAdEngine(adEngineConfig: AdEngineConfig) -> MRecAdEngine? { | ||
|  |         let id = adEngineConfig.hashCode() | ||
|  |         logInfo("createMRecAdEngine: \(id)") | ||
|  |          | ||
|  |         let engine = getMRecAdEngine(id: id) ?? { | ||
|  |             switch adEngineConfig.strategy { | ||
|  |             case BannerStrategy.default.rawValue: | ||
|  |                 guard let config = try? DefaultMRecConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultMRecAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |                  | ||
|  |             default: | ||
|  |                 guard let config = try? DefaultMRecConfig(adEngineConfig.config) else { | ||
|  |                     return nil; | ||
|  |                 } | ||
|  |                 return createDefaultMRecAdEngine( | ||
|  |                     id: id, | ||
|  |                     config: config | ||
|  |                 ) | ||
|  |             } | ||
|  |         }() | ||
|  |          | ||
|  |         if let engine = engine { | ||
|  |             mrecAdEngines[id] = engine | ||
|  |         } | ||
|  |          | ||
|  |         return engine | ||
|  |     } | ||
|  |      | ||
|  |     func dispatchOrientationUpdate(orientation: ScreenOrientation) { | ||
|  |         let body: (Any) throws -> Void = { it in | ||
|  |             (it as? OrientationAware)?.onOrientationUpdate(orientation: orientation) | ||
|  |         } | ||
|  |         try? interstitialAdEngines.values.forEach(body) | ||
|  |         try? bannerAdEngines.values.forEach(body) | ||
|  |         try? rewardedAdEngines.values.forEach(body) | ||
|  |         try? mrecAdEngines.values.forEach(body) | ||
|  |     } | ||
|  |      | ||
|  |     // for testing only! | ||
|  |     func clearCachedEngines() { | ||
|  |         interstitialAdEngines.removeAll() | ||
|  |         bannerAdEngines.removeAll() | ||
|  |         rewardedAdEngines.removeAll() | ||
|  |         mrecAdEngines.removeAll() | ||
|  |     } | ||
|  |      | ||
|  | } | ||
|  | 
 | ||
|  | // MARK: - Hashable Extension for AdEngineConfig | ||
|  | 
 | ||
|  | extension AdEngineConfig: Hashable { | ||
|  |     func hashCode() -> Int { | ||
|  |         return hashValue | ||
|  |     } | ||
|  |     public static func == (lhs: AdEngineConfig, rhs: AdEngineConfig) -> Bool { | ||
|  |         return lhs.strategy == rhs.strategy | ||
|  |         && (lhs.config as NSDictionary).isEqual(to: rhs.config) | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     public func hash(into hasher: inout Hasher) { | ||
|  |         hasher.combine(strategy) | ||
|  |         for (key, value) in config { | ||
|  |             hasher.combine(key) | ||
|  |             if let hashableValue = value as? (any Hashable) { | ||
|  |                 hasher.combine(hashableValue) | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | // MARK: - Hashable Extensions | ||
|  | 
 | ||
|  | extension Int { | ||
|  |     func hashCode() -> Int { | ||
|  |         return self | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | extension String { | ||
|  |     func hashCode() -> Int { | ||
|  |         var h: Int = 0 | ||
|  |         for c in self.unicodeScalars { | ||
|  |             h = 31 &* h &+ Int(c.value) | ||
|  |         } | ||
|  |         return h | ||
|  |     } | ||
|  | } |