// GuruMaxMRecAd.swift // Implementation for MAX MREC ads // Corresponds to GuruMaxMRecAd.kt in Android implementation import Foundation import UIKit import AppLovinSDK public class GuruMaxMRecAd: GuruMRecAd, MAAdViewAdDelegate, MAAdRevenueDelegate { private let viewController: UIViewController private let adConfig: AdConfig private var mrecAd: MAAdView? private var contentView: UIView? private var currentUid2Token: String = "" private var horizontalOffset: CGFloat = 0.0 private var verticalOffset: CGFloat = 0.0 private var orientation: ScreenOrientation = .portrait private var contentId: Int { return self.adConfig.engineId } public init(viewController: UIViewController, adConfig: AdConfig) { self.viewController = viewController self.adConfig = adConfig super.init(engineId: adConfig.engineId, adUnitId: adConfig.adUnitId, adPlatform: AdPlatform.max) } public override func logDebug(_ message: String) { Logger.d(tag: "MaxMRecAd[\(adConfig.adUnitId)]", message: message) } public override func logInfo(_ message: String) { Logger.i(tag: "MaxMRecAd[\(adConfig.adUnitId)]", message: message) } public override func logWarn(_ message: String) { Logger.w(tag: "MaxMRecAd[\(adConfig.adUnitId)]", message: message) } public override func load() -> Bool { mrecAd = MAAdView(adUnitIdentifier: adConfig.adUnitId, adFormat: MAAdFormat.mrec) guard let mrecAd = mrecAd else { return false } mrecAd.delegate = self mrecAd.revenueDelegate = self mrecAd.setExtraParameterForKey("allow_pause_auto_refresh_immediately", value: "true") if let uid2Token = AdsHelper.getUid2Token() { mrecAd.setExtraParameterForKey("uid2_token", value: uid2Token) currentUid2Token = uid2Token } mrecAd.stopAutoRefresh() if let amazonSlotId = adConfig.adAmazonSlotId, !amazonSlotId.isEmpty { // In a real implementation, you would load Amazon ads here logDebug("Would load Amazon MREC ad with slot ID: \(amazonSlotId)") // Simulate direct load for now mrecAd.loadAd() } else { mrecAd.loadAd() } return true } public override func show(request: MRecShowRequest? = nil) -> Bool { let placement = request?.placement let newHorizontalOffset = request?.horizontalOffset let newVerticalOffset = request?.verticalOffset var shouldReattach = false // Check if position or offset has changed if let offset = newVerticalOffset, offset != Float(verticalOffset) { verticalOffset = CGFloat(offset) shouldReattach = true } if let offset = newHorizontalOffset, offset != Float(horizontalOffset) { horizontalOffset = CGFloat(offset) shouldReattach = true } // If we already have a view and parameters changed, remove it if let contentView = contentView, shouldReattach { logInfo("Parameters changed! Re-attaching view!") contentView.removeFromSuperview() self.contentView = nil } // Create new content view if needed if contentView == nil { let container = UIView() container.tag = contentId viewController.view.addSubview(container) container.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ container.leadingAnchor.constraint(equalTo: viewController.view.leadingAnchor), container.trailingAnchor.constraint(equalTo: viewController.view.trailingAnchor), container.topAnchor.constraint(equalTo: viewController.view.topAnchor), container.bottomAnchor.constraint(equalTo: viewController.view.bottomAnchor) ]) contentView = container guard let mrecAd = mrecAd else { return false } // Standard MREC size is 300x250 let mrecWidth: CGFloat = 300 let mrecHeight: CGFloat = 250 mrecAd.translatesAutoresizingMaskIntoConstraints = false container.addSubview(mrecAd) NSLayoutConstraint.activate([ mrecAd.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: horizontalOffset), mrecAd.topAnchor.constraint(equalTo: container.topAnchor, constant: verticalOffset), mrecAd.widthAnchor.constraint(equalToConstant: mrecWidth), mrecAd.heightAnchor.constraint(equalToConstant: mrecHeight) ]) mrecAd.isHidden = false mrecAd.startAutoRefresh() } else { mrecAd?.startAutoRefresh() mrecAd?.isHidden = false } // Update UID2 token if needed if let uid2Token = AdsHelper.getUid2Token(), !uid2Token.isEmpty, uid2Token != currentUid2Token { mrecAd?.setExtraParameterForKey("uid2_token", value: uid2Token) currentUid2Token = uid2Token logInfo("MRec refresh uid2_token \(currentUid2Token)") } return true } public override func hide() -> Bool { guard let _ = viewController.view.viewWithTag(contentId) else { return true } if let mrecAd = mrecAd, !mrecAd.isHidden { mrecAd.setExtraParameterForKey("allow_pause_auto_refresh_immediately", value: "true") mrecAd.stopAutoRefresh() mrecAd.isHidden = true } return true } override public func destroy() -> Bool{ mrecAd?.delegate = nil mrecAd?.revenueDelegate = nil mrecAd?.removeFromSuperview() mrecAd = nil contentView?.removeFromSuperview() contentView = nil return true } override public func updateOrientation(orientation: ScreenOrientation) -> Bool { if let _ = viewController.view.viewWithTag(contentId), self.orientation != orientation { let isVisible = !(mrecAd?.isHidden ?? true) mrecAd?.setExtraParameterForKey("allow_pause_auto_refresh_immediately", value: "true") mrecAd?.stopAutoRefresh() mrecAd?.isHidden = true contentView?.removeFromSuperview() contentView = nil if isVisible { return show() } } self.orientation = orientation return true } // MARK: - MAAdViewAdDelegate methods public func didLoad(_ ad: MAAd) { listener?.onAdLoaded(ad: MaxFusionAd(engineId: engineId, adType: AdType.MRec, ad: ad)) } public func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { let loadFailedInfo = LoadFailedInfo( engineId: engineId, adPlatform: AdPlatform.max, adType: AdType.MRec, adUnitId: adUnitIdentifier, error: MaxFusionError(error) ) listener?.onAdLoadFailed(loadFailedInfo: loadFailedInfo) } public func didDisplay(_ ad: MAAd) { listener?.onAdDisplayed(ad: MaxFusionAd(engineId: engineId, adType: AdType.MRec, ad: ad)) } public func didHide(_ ad: MAAd) { listener?.onAdHidden(ad: MaxFusionAd(engineId: engineId, adType: AdType.MRec, ad: ad)) } public func didClick(_ ad: MAAd) { listener?.onAdClicked(ad: MaxFusionAd(engineId: engineId, adType: AdType.MRec, ad: ad)) } public func didFail(toDisplay ad: MAAd, withError error: MAError) { listener?.onAdDisplayFailed( ad: MaxFusionAd(engineId: engineId, adType: AdType.MRec, ad: ad), error: MaxFusionError(error) ) } public func didExpand(_ ad: MAAd) { // In a real implementation, you would call adBannerExpanded } public func didCollapse(_ ad: MAAd) { // In a real implementation, you would call adBannerCollapsed } // MARK: - MAAdRevenueDelegate methods public func didPayRevenue(for ad: MAAd) { listener?.onAdRevenuePaid(ad: MaxFusionAd(engineId: engineId, adType: AdType.MRec, ad: ad)) } }