// // MP_AdMobManager.swift // relax.offline.mp3.music // // Created by Mr.Zhou on 2024/6/14. // import UIKit import AVFoundation import GoogleMobileAds import AppLovinAdapter import AppLovinSDK import LiftoffMonetizeAdapter import VungleAdsSDK import PangleAdapter import PAGAdSDK import IronSourceAdapter import IronSource import MintegralAdapter import MTGSDK import ChartboostSDK import ChartboostAdapter ///AdMob广告管理器 class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenContentDelegate, GADNativeAdLoaderDelegate, GADNativeAdDelegate, GADVideoControllerDelegate { static let shared = MP_AdMobManager() ///广告总开关 private var openAdStatus:Bool = MP_ADSimpleManager.shared.openAdStatus ///内部使用广告开光 private var internalAdStatus:Bool = MP_ADSimpleManager.shared.internalAdStatus private let sharedInstance = GADMobileAds.sharedInstance() ///广告过期时间(50分钟) private let expirationTime:TimeInterval = 3000 //检测广告是否过期 private func wasAdexpirationTime(_ date:Date?) -> Bool { guard let loadTime = date else { return false } // Check if ad was loaded more than four hours ago. return Date().timeIntervalSince(loadTime) < expirationTime } //MARK: - 插页广告总设置 ///插页广告总开关 private var interstitialSwitch:Bool = false{ didSet{ DispatchQueue.main.async { [weak self] in MPSideA_MediaCenterManager.shared.isAdLate = self?.interstitialSwitch } } } ///插页广告显示时间 var interstitialDate:Date? ///插页广告间隔秒数(默认40秒) private var interstitialDuration:TimeInterval{ get{ if let times = UserDefaults.standard.object(forKey: "InterstitialDuration") as? TimeInterval { return times }else { return 40 } } } ///中介间隔秒数 private var intermediaryDuration:TimeInterval{ get{ if let times = UserDefaults.standard.object(forKey: "IntermediaryDuration") as? TimeInterval { return times }else { return 40 } } } ///开屏中介记录时间值 private var intermediaryOpenShowTime:Date? ///插页中介记录时间值 private var intermediaryInterstitialShowTime:Date? //中介间隔是否通过 private var isPassIntermediary:Bool = true ///设置插页总开关 func setInterstitialSwitch(_ status:Bool) { interstitialSwitch = status } ///获得插页开关的状态 func getInterstitialSwitch() -> Bool { return interstitialSwitch } ///设置插页广告间隔秒数 func setInterstitialDuration(_ duration:TimeInterval?) { if let times = duration { UserDefaults.standard.set(times, forKey: "InterstitialDuration") } } ///设置中介间隔秒数 func setIntermediaryDuration(_ duration:TimeInterval?) { if let times = duration { UserDefaults.standard.set(times, forKey: "IntermediaryDuration") } } ///是否达到插页间隔时长(达到即可继续展示插页广告) private func isShowInterstitialADAvailable(_ date:Date) -> Bool { return Date().timeIntervalSince(date) > interstitialDuration } private override init() { super.init() NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkReachableAction(_:)), notificationName: .net_switch_reachable) GADMobileAds.sharedInstance().audioVideoManager.delegate = self // GADMobileAds.sharedInstance().audioVideoManager. reloadAdMobIDs() //对开屏广告完成处理闭包 completeOpenAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的开屏广告实例 appOpenAd = nil appInterstitialAd = nil isShowingOpenAd = false loadOpenAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新开屏广告中介间隔时间 intermediaryOpenShowTime = Date() //重新加载后续的开屏广告 DispatchQueue.main.asyncAfter(deadline: .now() + 4) { [weak self] in self?.loadOpenAd(.HOST) { status in if status == true { print("新的开屏广告加载成功") }else { print("开屏广告加载失败了") } } } } //搜索插页广告完成处理闭包 completeSearchInterstitialAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的搜索插页广告实例 searchInterstitialAd = nil isShowingSearchInterstitialAd = false loadSearchInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新插页广告中介间隔时长 intermediaryInterstitialShowTime = Date() //重新加载后续的搜索插页广告 DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadSearchInterstitialAd { status in if status { print("成功加载搜索插页广告") }else { print("搜索插页广告加载失败") } } } } //播放插页广告完成处理闭包 completePlayInterstitialAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的播放插页广告实例 playInterstitialAd = nil isShowingPlayInterstitialAd = false loadPlayInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新插页广告中介间隔时长 intermediaryInterstitialShowTime = Date() //重新加载后续的播放插页广告 DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadPlayInterstitialAd { status in if status { print("成功加载播放插页广告") }else { print("播放插页广告加载失败") } } } } //切歌插页 completeSwitchInterstitialAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的切歌插页广告实例 switchInterstitialAd = nil isShowingSwitchInterstitialAd = false loadSwitchInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新插页广告中介间隔时长 intermediaryInterstitialShowTime = Date() //重新加载后续的切歌插页广告 DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadSwitchInterstitialAd { status in if status { print("成功加载切歌插页广告") }else { print("切歌插页广告加载失败") } } } } //下载插页 completeLoadInterstitialAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的切歌插页广告实例 loadInterstitialAd = nil isShowingLoadInterstitialAd = false loadLoadInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新插页广告中介间隔时长 intermediaryInterstitialShowTime = Date() //重新加载后续的下载插页广告 DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadLoadInterstitialAd { status in if status { print("成功加载下载插页广告") }else { print("下载插页广告加载失败") } } } } //曲库插页广告完成处理闭包 completeLibraryInterstitialAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的曲库插页广告实例 libraryInterstitialAd = nil isShowingLibraryInterstitialAd = false loadLibraryInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新插页广告中介间隔时长 intermediaryInterstitialShowTime = Date() //重新加载后续的曲库插页广告 DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadLibraryInterstitialAd { status in if status { print("成功加载曲库插页广告") }else { print("曲库插页广告加载失败") } } } } //全局插页广告完成处理闭包 completeGlobalInterstitialAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的全局插页广告实例 globalInterstitialAd = nil isShowingGlobalInterstitialAd = false loadGlobalInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //更新插页广告中介间隔时长 intermediaryInterstitialShowTime = Date() //重新加载后续的全局插页广告 DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadGlobalInterstitialAd { status in if status { print("成功加载全局插页广告") }else { print("全局插页广告加载失败") } } } } } ///更新ID func reloadAdMobIDs() { //更新所有广告ID if let data = UserDefaults.standard.object(forKey: "OpenICEID") as? Data, let array = jsonforCoreAdModel(data) { print("成功提取ID") OpenICEID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "OpenHOSTID") as? Data, let array = jsonforCoreAdModel(data) { OpenHOSTID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "SearchINSERTID") as? Data, let array = jsonforCoreAdModel(data) { SearchINSERTID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "SearchNATIVEID") as? Data, let array = jsonforCoreAdModel(data) { SearchNATIVEID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "PlayerINSERTID") as? Data, let array = jsonforCoreAdModel(data) { PlayerINSERTID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "SwitchINSERTID") as? Data, let array = jsonforCoreAdModel(data) { SwitchINSERTID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "LoadINSERTID") as? Data, let array = jsonforCoreAdModel(data) { LoadINSERTID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "LibraryINSERTID") as? Data, let array = jsonforCoreAdModel(data) { LibraryINSERTID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "LibraryNATIVEID") as? Data, let array = jsonforCoreAdModel(data) { LibraryNATIVEID = array.sorted(by: {$0.level > $1.level}) } if let data = UserDefaults.standard.object(forKey: "GlobalINSERTID") as? Data, let array = jsonforCoreAdModel(data) { GlobalINSERTID = array.sorted(by: {$0.level > $1.level}) } } ///加载更多广告 func loadMoreAdMobs() { loadPlayInterstitialAd{status in if status { print("成功加载播放插页广告") }else { print("播放插页广告加载失败") } } loadSearchInterstitialAd { status in if status { print("成功加载搜索插页广告") }else { print("搜索插页广告加载失败") } } loadLibraryInterstitialAd { status in if status { print("成功加载曲库插页广告") }else { print("曲库插页广告加载失败") } } } //网络可用时触发 @objc private func netWorkReachableAction(_ sender:Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else {return} loadMoreAdMobs() } } deinit{ NotificationCenter.default.removeObserver(self) displaySearchTimer?.invalidate() displaySearchTimer = nil displayLibraryTimer?.invalidate() displayLibraryTimer = nil } ///开始缓存广告 func start() { sharedInstance.start { status in print("App启动,开始加载广告") let adapterStatuses = status.adapterStatusesByClassName for adapter in adapterStatuses { let adapterStatus = adapter.value print("Adapter Name: \(adapter.key), Description: \(adapterStatus.description), Latency: \(adapterStatus.latency)") } } } ///检索与插页广告之间的中介间隔时长是否达标 private func retrieveIntermediaryInterstitial() -> Bool { //判断插页中介记录时间值是否存在 guard let date = intermediaryInterstitialShowTime else {return true} return Date().timeIntervalSince(date) > intermediaryDuration } ///检索与开屏广告之间的中介间隔时长是否达标 private func retrieveIntermediaryOpen() -> Bool { //判断插页中介记录时间值是否存在 guard let date = intermediaryOpenShowTime else {return true} return Date().timeIntervalSince(date) > intermediaryDuration } //MARK: - 开屏 //开屏冷启动广告ID private var OpenICEID:[MPPositive_AdItemModel] = [] //开屏热启动广告ID private var OpenHOSTID:[MPPositive_AdItemModel] = [] //应用开屏广告实例 var appOpenAd:GADAppOpenAd? //应用插页广告实例 var appInterstitialAd:GADInterstitialAd? //是否正在加载广告 private var isLoadingOpenAd:Bool = false //是否正在展示广告 var isShowingOpenAd:Bool = false //开屏广告加载时间 private var loadOpenAdTime:Date? //开屏广告时间间隔(默认10秒) private var openAppDuration:TimeInterval{ get{ if let times = UserDefaults.standard.object(forKey: "OpenAppDuration") as? TimeInterval { return times }else { return 10 } } } //设置开屏广告时间间隔 func setOpenAppDuration(_ duration:TimeInterval) { UserDefaults.standard.set(duration, forKey: "OpenAppDuration") } //获取开屏广告时间间隔 func getOpenAppDuration() -> TimeInterval { return self.openAppDuration } //开屏广告加载完成处理闭包 var completeOpenAdBlock:(() -> Void)? ///异步加载开屏广告 func loadOpenAd(_ type:OpenType, level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else {return} // 检测当前是否有广告或者有广告正在加载 if isLoadingOpenAd || isOpenAdAvailable() { // 有广告或有广告在加载 completion(false) return } //检索是否超过了对应的id组的阶级数量 var item:MPPositive_AdItemModel switch type { case .ICE: guard OpenICEID.isEmpty == false else { //冷启动无数据 MP_AnalyticsManager.shared.cold_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (OpenICEID.count) else { print("冷启动广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.cold_ads_loadFailureAction("No Ads Fill") completion(false) return } item = OpenICEID[level] case .HOST: guard OpenHOSTID.isEmpty == false else { //热启动无数据 MP_AnalyticsManager.shared.hot_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (OpenHOSTID.count) else { print("热启动广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.hot_ads_loadFailureAction("No Ads Fill") completion(false) DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in self?.loadOpenAd(.HOST, completion: { status in if status { print("重新加载热启动广告成功") }else { print("重新加载热启动广告失败") } }) } return } item = OpenHOSTID[level] } isLoadingOpenAd = true let request = GADRequest() MP_ADSimpleManager.shared.isAdSounded() //判断需要生成什么广告 if item.type == .Open { //生成开屏广告 // 使用 GADAppOpenAd 的 load 方法和一个completion handler来加载广告 GADAppOpenAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载开屏广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") switch type { case .ICE: MP_AnalyticsManager.shared.cold_ads_loadFailureAction(error.localizedDescription) case .HOST: MP_AnalyticsManager.shared.hot_ads_loadFailureAction(error.localizedDescription) } self.isLoadingOpenAd = false loadOpenAd(type, level: level+1, completion: completion) } else { self.appOpenAd = ad self.isLoadingOpenAd = false //实现代理 self.appOpenAd?.fullScreenContentDelegate = self //更新加载时间 self.loadOpenAdTime = Date() completion(true) } } } }else if item.type == .Insert { //生成插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request ) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载开屏广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") switch type { case .ICE: MP_AnalyticsManager.shared.cold_ads_loadFailureAction(error.localizedDescription) case .HOST: MP_AnalyticsManager.shared.hot_ads_loadFailureAction(error.localizedDescription) } self.isLoadingOpenAd = false loadOpenAd(type, level: level+1, completion: completion) } else { self.appInterstitialAd = ad self.isLoadingOpenAd = false //实现代理 self.appInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadOpenAdTime = Date() completion(true) } } } }else { completion(false) } } ///开屏广告展示 func showOpenAdIfAvailable(_ type:OpenType, completion:((_ T:GADFullScreenPresentingAd, _ isOpen:Bool) -> Void)?) { guard openAdStatus, internalAdStatus else {return} // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingOpenAd, retrieveIntermediaryInterstitial() else { return } // 如果应用开屏广告尚不可用但应该显示,则加载新广告。 if !isOpenAdAvailable() { loadOpenAd(type) { [weak self] success in guard let self = self else { return } if success { self.showOpenAdIfAvailable(type, completion: completion) } } if type == .HOST { //同步展示全屏广告 showGlobalInterstitialAdIfAvailable { ad in if let ad = ad { if let block = completion { block(ad, false) } } } } return } if type == .ICE { MP_AnalyticsManager.shared.cold_ads_chanceAction() }else { MP_AnalyticsManager.shared.hot_ads_chanceAction() } //当开屏广告确定有值后展示 if let ad = (appOpenAd) { //传递加载完成事件 if let block = completion { block(ad, true) }else { isShowingOpenAd = true interstitialSwitch = true DispatchQueue.main.async { [weak self] in guard let self = self else {return} do{ try ad.canPresent(fromRootViewController: nil) ad.present(fromRootViewController: nil) }catch{ print("开屏广告展示失败,失败原因:\(error)") if completeOpenAdBlock != nil { completeOpenAdBlock!() } } } } }else if let ad = (appInterstitialAd) { //传递加载完成事件 if let block = completion { block(ad, false) }else { isShowingOpenAd = true interstitialSwitch = true DispatchQueue.main.async { [weak self] in guard let self = self else {return} do{ try ad.canPresent(fromRootViewController: nil) ad.present(fromRootViewController: nil) }catch{ print("开屏广告展示失败,失败原因:\(error)") if completeOpenAdBlock != nil { completeOpenAdBlock!() } } } } }else { print("开屏广告展示失败") if type == .ICE { MP_AnalyticsManager.shared.cold_ads_showFailureAction("Ad loading failed") }else { MP_AnalyticsManager.shared.hot_ads_showFailureAction("Ad loading failed") } } } ///查询是否有开屏广告 func isOpenAdAvailable() -> Bool { return (appOpenAd != nil || appInterstitialAd != nil) && wasAdexpirationTime(loadOpenAdTime) } //MARK: - 搜索 //搜索插页广告ID private var SearchINSERTID:[MPPositive_AdItemModel] = [] //搜索原生广告ID private var SearchNATIVEID:[MPPositive_AdItemModel] = [] ///搜索插页广告 private var searchInterstitialAd:GADInterstitialAd? ///是否正在加载搜索插页广告 private var isLoadingSearchInterstitialAd:Bool = false ///是否正在展示搜索插页广告 var isShowingSearchInterstitialAd:Bool = false ///搜索插页加载时间 private var loadSearchInterstitialAdTime:Date? ///搜索广告处理闭包 var completeSearchInterstitialAdBlock:(() -> Void)? ///搜索原生广告加载器 var searchAdLoader:GADAdLoader? ///搜索原生广告 var searchNativeAd:GADNativeAd? ///搜索原生广告视图 var searchNativeAdView:GADNativeAdView? ///搜索原生存储时长 var refreshSearchTimes:TimeInterval = 3600 ///搜索原生显示刷新计时器 var displaySearchTimer:Timer? ///搜索原生加载时间 var expirationSearchDate:Date? ///搜索控制器 var searchViewController:UIViewController? ///搜索原生回调闭包 var onSearchNativeAdBlock:(() -> Void)? ///配置搜索原生广告加载器 func configureSreachNativeAd(rootController vc:UIViewController) { searchViewController = vc } ///搜索原生广告加载 func loadSearchNativeAd() { guard openAdStatus, internalAdStatus else {return} guard let vc = searchViewController else {return} //请求数量限制器 let multipleAdOptions = GADMultipleAdsAdLoaderOptions() //加载一条,每次即使结束后重新刷新数据 multipleAdOptions.numberOfAds = 1 //图片加载限制器 let imageAdOptions = GADNativeAdImageAdLoaderOptions() imageAdOptions.shouldRequestMultipleImages = false //视频加载限制器 let videoAdOptions = GADVideoOptions() videoAdOptions.startMuted = true if let first = SearchNATIVEID.first, first.type == .Native { MP_AnalyticsManager.shared.result_ads_chanceAction() searchAdLoader = GADAdLoader(adUnitID: first.identifier, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions, imageAdOptions, videoAdOptions]) searchAdLoader?.delegate = self let request = GADRequest() searchAdLoader?.load(request) } } ///将加载的搜索原生广告添加到页面中 func layoutSearchNativeAd(in containerView: UIView) { guard openAdStatus, internalAdStatus else {return} MP_ADSimpleManager.shared.isAdMuted() containerView.subviews.forEach { item in item.removeFromSuperview() } searchNativeAdView = nil //初始化广告模版对象 guard let templateView = (Bundle.main.loadNibNamed("GADTSmallTemplateView", owner: nil, options: nil)?.first as? GADTTemplateView), let nativeAd = searchNativeAd, refreshSearchDate(expirationSearchDate) else { //重新加载 loadSearchNativeAd() return } searchNativeAdView = templateView nativeAd.delegate = self containerView.addSubview(templateView) templateView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() make.left.equalToSuperview().offset(16*width) make.right.equalToSuperview().offset(-16*width) } //创建一个choiveView let customRect = CGRect(x: containerView.frame.width-(16*width)-25, y: 0, width: 25, height: 25) let customAdChoicesView = GADAdChoicesView(frame: customRect) templateView.addSubview(customAdChoicesView) templateView.adChoicesView = customAdChoicesView containerView.snp.updateConstraints { make in make.height.equalTo(125) } templateView.nativeAd = nativeAd nativeAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.result_ads_showAction(nativeAd.responseInfo, adValue: adValue) } // 设置展示计时器,60 秒后刷新加载新广告 displaySearchTimer?.invalidate() displaySearchTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: false) { [weak self] _ in self?.loadSearchNativeAd() } } ///搜索原生存储时长 private func refreshSearchDate(_ date:Date?) -> Bool { guard let date = date else {return false} return Date().timeIntervalSince(date) < refreshSearchTimes } //异步加载搜索插页广告 func loadSearchInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else {return} // 检测当前是否有广告或者有广告正在加载 if isLoadingSearchInterstitialAd || isSearchInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } guard SearchINSERTID.isEmpty == false else { MP_AnalyticsManager.shared.search_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (SearchINSERTID.count) else { print("搜索插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.search_ads_loadFailureAction("No Ads Fill") DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadSearchInterstitialAd { status in if status { print("重新加载搜索插页广告") }else { print("加载搜索插页广告失败") } } } return } isLoadingSearchInterstitialAd = true let item = SearchINSERTID[level] let request = GADRequest() MP_ADSimpleManager.shared.isAdSounded() //加载搜索插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载搜索插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") MP_AnalyticsManager.shared.search_ads_loadFailureAction(error.localizedDescription) self.isLoadingSearchInterstitialAd = false loadSearchInterstitialAd(level+1, completion: completion) } else { self.searchInterstitialAd = ad self.isLoadingSearchInterstitialAd = false //实现代理 self.searchInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadSearchInterstitialAdTime = Date() completion(true) } } } } ///搜索插页广告展示 func showSearchInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { guard openAdStatus, internalAdStatus else {return} // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingSearchInterstitialAd, retrieveIntermediaryOpen() else { return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") return } } // 如果搜索广告尚不可用但应该显示,则加载新广告。 if !isSearchInterstitialAdAvailable() { loadSearchInterstitialAd { [weak self] success in guard let self = self else { return } if success { self.showSearchInterstitialAdIfAvailable(completion: completion) } } //展示全屏广告 showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.search_ads_chanceAction() //当搜索插页广告确定有值后展示 if let ad = searchInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingSearchInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else { MP_AnalyticsManager.shared.search_ads_showFailureAction("Ad loading failed") } } //查询是否有搜索插页广告 func isSearchInterstitialAdAvailable() -> Bool { return searchInterstitialAd != nil && wasAdexpirationTime(loadSearchInterstitialAdTime) } //MARK: - 播放 //播放插页广告ID private var PlayerINSERTID:[MPPositive_AdItemModel] = [] ///播放插页广告 var playInterstitialAd:GADInterstitialAd? ///是否正在加载播放插页广告 private var isLoadingPlayInterstitialAd:Bool = false ///是否正在展示播放插页广告 var isShowingPlayInterstitialAd:Bool = false ///播放插页加载时间 private var loadPlayInterstitialAdTime:Date? ///播放广告处理闭包 var completePlayInterstitialAdBlock:(() -> Void)? //异步加载播放插页广告 func loadPlayInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else { completion(false) return } // 检测当前是否有广告或者有广告正在加载 if isLoadingPlayInterstitialAd || isPlayInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } guard PlayerINSERTID.isEmpty == false else { MP_AnalyticsManager.shared.play_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (PlayerINSERTID.count) else { print("播放插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.play_ads_loadFailureAction("No Ads Fill") DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadPlayInterstitialAd { status in if status { print("重新加载播放插页广告") }else { print("加载播放插页广告失败") } } } return } isLoadingPlayInterstitialAd = true let item = PlayerINSERTID[level] let request = GADRequest() MP_ADSimpleManager.shared.isAdSounded() //加载播放插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载播放插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") MP_AnalyticsManager.shared.play_ads_loadFailureAction(error.localizedDescription) self.isLoadingPlayInterstitialAd = false loadPlayInterstitialAd(level+1, completion: completion) } else { self.playInterstitialAd = ad self.isLoadingPlayInterstitialAd = false //实现代理 self.playInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadPlayInterstitialAdTime = Date() completion(true) } } } } ///播放插页广告展示 func showPlayInterstitialAdIfAvailable(completion:((GADInterstitialAd?) -> Void)?) { guard openAdStatus, internalAdStatus else { completion?(nil) return } guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { completion?(nil) return } // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingPlayInterstitialAd, retrieveIntermediaryOpen() else { completion?(nil) return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") completion?(nil) return } } // 如果播放插页广告尚不可用但应该显示,则加载新广告。 if !isPlayInterstitialAdAvailable() { loadPlayInterstitialAd{ [weak self] success in guard let self = self else { return } if success { print("播放广告已加载") } } completion?(nil) return } MP_AnalyticsManager.shared.play_ads_chanceAction() //当播放插页广告确定有值后展示 if let ad = playInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingPlayInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else { MP_AnalyticsManager.shared.play_ads_showFailureAction("Ad loading failed") completion?(nil) } } //查询是否有播放插页广告 func isPlayInterstitialAdAvailable() -> Bool { return playInterstitialAd != nil && wasAdexpirationTime(loadPlayInterstitialAdTime) } //MARK: - 切歌 //切歌插页广告ID private var SwitchINSERTID:[MPPositive_AdItemModel] = [] ///切歌插页广告 var switchInterstitialAd:GADInterstitialAd? ///是否正在加载切歌插页广告 private var isLoadingSwitchInterstitialAd:Bool = false ///是否正在展示切歌插页广告 var isShowingSwitchInterstitialAd:Bool = false ///切歌插页加载时间 private var loadSwitchInterstitialAdTime:Date? ///切歌广告处理闭包 var completeSwitchInterstitialAdBlock:(() -> Void)? //异步加载切歌插页广告 func loadSwitchInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else { completion(false) return } // 检测当前是否有广告或者有广告正在加载 if isLoadingSwitchInterstitialAd || isSwitchInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } guard SwitchINSERTID.isEmpty == false else { MP_AnalyticsManager.shared.cut_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (SwitchINSERTID.count) else { print("切歌插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.cut_ads_loadFailureAction("No Ads Fill") DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadSwitchInterstitialAd { status in if status { print("重新加载切歌插页广告") }else { print("加载切歌插页广告失败") } } } return } isLoadingSwitchInterstitialAd = true let item = SwitchINSERTID[level] let request = GADRequest() //加载播放插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载切歌插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") MP_AnalyticsManager.shared.cut_ads_loadFailureAction(error.localizedDescription) self.isLoadingSwitchInterstitialAd = false loadSwitchInterstitialAd(level+1, completion: completion) } else { self.switchInterstitialAd = ad self.isLoadingSwitchInterstitialAd = false //实现代理 self.switchInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadSwitchInterstitialAdTime = Date() completion(true) } } } } ///切歌插页广告展示 func showSwitchInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { guard openAdStatus, internalAdStatus else { return } // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingSwitchInterstitialAd, retrieveIntermediaryOpen() else { return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") return } } // 如果切歌插页广告尚不可用但应该显示,则加载新广告。 if !isSwitchInterstitialAdAvailable() { loadSwitchInterstitialAd{ [weak self] success in guard let self = self else { return } if success { self.showSwitchInterstitialAdIfAvailable(completion: completion) } } //展示全屏广告 showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.cut_ads_chanceAction() //当切歌插页广告确定有值后展示 if let ad = switchInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingSwitchInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else { MP_AnalyticsManager.shared.cut_ads_showFailureAction("Ad loading failed") } } //查询是否有切歌插页广告 func isSwitchInterstitialAdAvailable() -> Bool { return switchInterstitialAd != nil && wasAdexpirationTime(loadSwitchInterstitialAdTime) } //MARK: - 下载 //下载插页广告ID private var LoadINSERTID:[MPPositive_AdItemModel] = [] ///下载插页广告 var loadInterstitialAd:GADInterstitialAd? ///是否正在加载下载插页广告 private var isLoadingLoadInterstitialAd:Bool = false ///是否正在展示下载插页广告 var isShowingLoadInterstitialAd:Bool = false ///下载插页加载时间 private var loadLoadInterstitialAdTime:Date? ///下载广告处理闭包 var completeLoadInterstitialAdBlock:(() -> Void)? //异步加载下载插页广告 func loadLoadInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else { completion(false) return } // 检测当前是否有广告或者有广告正在加载 if isLoadingLoadInterstitialAd || isLoadInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } guard LoadINSERTID.isEmpty == false else { MP_AnalyticsManager.shared.dl_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (LoadINSERTID.count) else { print("下载插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.dl_ads_loadFailureAction("No Ads Fill") DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadLoadInterstitialAd { status in if status { print("重新加载下载插页广告") }else { print("加载下载插页广告失败") } } } return } isLoadingLoadInterstitialAd = true let item = LoadINSERTID[level] let request = GADRequest() //加载下载插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载下载插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") MP_AnalyticsManager.shared.dl_ads_loadFailureAction(error.localizedDescription) self.isLoadingLoadInterstitialAd = false loadLoadInterstitialAd(level+1, completion: completion) } else { self.loadInterstitialAd = ad self.isLoadingLoadInterstitialAd = false //实现代理 self.loadInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadLoadInterstitialAdTime = Date() completion(true) } } } } ///下载插页广告展示 func showLoadInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { guard openAdStatus, internalAdStatus else { return } // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingLoadInterstitialAd, retrieveIntermediaryOpen() else { return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") return } } // 如果下载插页广告尚不可用但应该显示,则加载新广告。 if !isLoadInterstitialAdAvailable() { loadLoadInterstitialAd{ [weak self] success in guard let self = self else { return } if success { self.showLoadInterstitialAdIfAvailable(completion: completion) } } //展示全屏广告 showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.dl_ads_chanceAction() //当下载插页广告确定有值后展示 if let ad = loadInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingLoadInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else { MP_AnalyticsManager.shared.dl_ads_showFailureAction("Ad loading failed") } } //查询是否有下载插页广告 func isLoadInterstitialAdAvailable() -> Bool { return loadInterstitialAd != nil && wasAdexpirationTime(loadLoadInterstitialAdTime) } //MARK: - 曲库 //曲库插页ID private var LibraryINSERTID:[MPPositive_AdItemModel] = [] //曲库原生ID private var LibraryNATIVEID:[MPPositive_AdItemModel] = [] ///曲库插页广告 private var libraryInterstitialAd:GADInterstitialAd? ///是否正在加载曲库插页广告 private var isLoadingLibraryInterstitialAd:Bool = false ///是否正在展示曲库插页广告 var isShowingLibraryInterstitialAd:Bool = false ///曲库插页加载时间 private var loadLibraryInterstitialAdTime:Date? ///曲库广告处理闭包 var completeLibraryInterstitialAdBlock:(() -> Void)? ///曲库原生广告加载器 var libraryAdLoader:GADAdLoader? ///曲库原生广告 var libraryNativeAds:[GADNativeAd]? ///曲库原生广告视图一 var libraryNativeAdFirstView:GADNativeAdView? ///原生广告视图二 var libraryNativeAdSecondView:GADNativeAdView? ///曲库原生存储时长 var refreshLibraryTimes:TimeInterval = 3600 ///曲库原生显示刷新计时器 var displayLibraryTimer:Timer? ///曲库原生加载时间 var expirationLibraryDate:Date? ///曲库控制器 var libraryViewController:UIViewController? ///曲库原生回调闭包 var onLibraryNativeAdBlock:(() -> Void)? ///配置曲库原生广告加载器 func configureLibraryNativeAd(rootController vc:UIViewController) { guard openAdStatus, internalAdStatus else { return } if libraryViewController == nil { libraryViewController = vc } } ///曲库原生广告加载 func loadLibraryNativeAd() { guard openAdStatus, internalAdStatus else {return} guard let vc = libraryViewController, libraryNativeAds == nil else {return} //请求数量限制器 let multipleAdOptions = GADMultipleAdsAdLoaderOptions() //加载一条,每次即使结束后重新刷新数据 multipleAdOptions.numberOfAds = 2 //图片加载限制器 let imageAdOptions = GADNativeAdImageAdLoaderOptions() imageAdOptions.shouldRequestMultipleImages = false //视频加载限制器 let videoAdOptions = GADVideoOptions() videoAdOptions.startMuted = true if let first = LibraryNATIVEID.first, first.type == .Native { libraryAdLoader = GADAdLoader(adUnitID: first.identifier, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions,imageAdOptions,videoAdOptions]) libraryAdLoader?.delegate = self let request = GADRequest() //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 libraryAdLoader?.load(request) libraryNativeAds = [] } } ///将加载的曲库原生广告添加到页面中 func layoutLibraryNativeAd(in containerView: UIView, index:Int, completion:(() -> Void)? = nil) { guard openAdStatus, internalAdStatus else {return} MP_ADSimpleManager.shared.isAdMuted() containerView.subviews.forEach { item in item.removeFromSuperview() } if index == 0 { MP_AnalyticsManager.shared.lbr_ads_chanceAction() //曲库第一页 libraryNativeAdFirstView = nil //初始化广告模版对象 guard let templateView = (Bundle.main.loadNibNamed("GADTSmallTemplateView", owner: nil, options: nil)?.first as? GADTTemplateView), let nativeAds = libraryNativeAds, nativeAds.count == 2, let nativeAd = nativeAds.first, refreshLibraryDate(expirationLibraryDate) else { //重新加载 loadLibraryNativeAd() return } libraryNativeAdFirstView = templateView nativeAd.delegate = self containerView.addSubview(templateView) templateView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() make.left.equalToSuperview().offset(16*width) make.right.equalToSuperview().offset(-16*width) } //创建一个choiveView let customRect = CGRect(x: containerView.frame.width-(16*width)-25, y: 0, width: 25, height: 25) let customAdChoicesView = GADAdChoicesView(frame: customRect) templateView.addSubview(customAdChoicesView) templateView.adChoicesView = customAdChoicesView templateView.nativeAd = nativeAd nativeAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.lbr_ads_showAction(nativeAd.responseInfo, adValue: adValue) } }else { MP_AnalyticsManager.shared.list_ads_chanceAction() //曲库第二页 libraryNativeAdSecondView = nil //初始化广告模版对象 guard let templateView = (Bundle.main.loadNibNamed("GADTSmallTemplateView", owner: nil, options: nil)?.first as? GADTTemplateView), let nativeAds = libraryNativeAds, nativeAds.count == 2, let nativeAd = nativeAds.last, refreshLibraryDate(expirationLibraryDate) else { //重新加载 loadLibraryNativeAd() return } libraryNativeAdSecondView = templateView nativeAd.delegate = self containerView.addSubview(templateView) templateView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() make.left.equalToSuperview().offset(16*width) make.right.equalToSuperview().offset(-16*width) } //创建一个choiveView let customRect = CGRect(x: containerView.frame.width-(16*width)-25, y: 0, width: 25, height: 25) let customAdChoicesView = GADAdChoicesView(frame: customRect) templateView.addSubview(customAdChoicesView) templateView.adChoicesView = customAdChoicesView templateView.nativeAd = nativeAd nativeAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.list_ads_showAction(nativeAd.responseInfo, adValue: adValue) } } DispatchQueue.main.async { [weak self] in containerView.snp.updateConstraints { make in make.height.equalTo(125) } completion?() } // 设置展示计时器,60 秒后刷新加载新广告 displayLibraryTimer?.invalidate() displayLibraryTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: false) { [weak self] _ in self?.loadLibraryNativeAd() } } ///曲库原生存储时长 private func refreshLibraryDate(_ date:Date?) -> Bool { guard let date = date else {return false} return Date().timeIntervalSince(date) < refreshLibraryTimes } //异步加载曲库插页广告 func loadLibraryInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else { completion(false) return } // 检测当前是否有广告或者有广告正在加载 if isLoadingLibraryInterstitialAd || isLibraryInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } guard LibraryINSERTID.isEmpty == false else { MP_AnalyticsManager.shared.listclk_ads_showFailureAction("No IDs") //重新获取数据 reloadAdMobIDs() completion(false) return } guard level < (LibraryINSERTID.count) else { print("曲库插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.listclk_ads_loadFailureAction("No Ads Fill") DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.loadLibraryInterstitialAd { status in if status { print("重新加载曲库插页广告") }else { print("加载曲库插页广告失败") } } } return } isLoadingLibraryInterstitialAd = true let item = LibraryINSERTID[level] let request = GADRequest() MP_ADSimpleManager.shared.isAdSounded() //加载曲库插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载曲库插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") MP_AnalyticsManager.shared.listclk_ads_loadFailureAction(error.localizedDescription) self.isLoadingLibraryInterstitialAd = false loadLibraryInterstitialAd(level+1, completion: completion) } else { self.libraryInterstitialAd = ad self.isLoadingLibraryInterstitialAd = false //实现代理 self.libraryInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadLibraryInterstitialAdTime = Date() completion(true) } } } } ///曲库插页广告展示 func showLibraryInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { guard openAdStatus, internalAdStatus else { return } // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingLibraryInterstitialAd, retrieveIntermediaryOpen() else { return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") return } } // 如果曲库广告尚不可用但应该显示,则加载新广告。 if !isLibraryInterstitialAdAvailable() { loadLibraryInterstitialAd { [weak self] success in guard let self = self else { return } if success { self.showLibraryInterstitialAdIfAvailable(completion: completion) } } //展示全屏广告 showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.listclk_ads_chanceAction() //当曲库插页广告确定有值后展示 if let ad = libraryInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingLibraryInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else { MP_AnalyticsManager.shared.listclk_ads_showFailureAction("Ad loading failed") } } //查询是否有曲库插页广告 func isLibraryInterstitialAdAvailable() -> Bool { return libraryInterstitialAd != nil && wasAdexpirationTime(loadLibraryInterstitialAdTime) } //MARK: - 全局 //全局备用插页ID private var GlobalINSERTID:[MPPositive_AdItemModel] = [] ///全局插页广告 private var globalInterstitialAd:GADInterstitialAd? ///是否正在加载全局插页广告 private var isLoadingGlobalInterstitialAd:Bool = false ///是否正在展示全局插页广告 var isShowingGlobalInterstitialAd:Bool = false ///全局插页加载时间 private var loadGlobalInterstitialAdTime:Date? ///全局广告处理闭包 var completeGlobalInterstitialAdBlock:(() -> Void)? //异步加载全局插页广告 func loadGlobalInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { guard openAdStatus, internalAdStatus else { return } // 检测当前是否有广告或者有广告正在加载 if isLoadingGlobalInterstitialAd || isGlobalInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } guard level < (GlobalINSERTID.count) else { print("全局插页广告组已经全部加载失败,停止继续加载") completion(false) return } isLoadingGlobalInterstitialAd = true let item = GlobalINSERTID[level] let request = GADRequest() //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 // let mintegralExtra = GADMAdapterMintegralExtras() // mintegralExtra.muteVideoAudio = true // let appLovinExtra = GADMAdapterAppLovinExtras() // appLovinExtra.muteAudio = true // request.register(appLovinExtra) // request.register(mintegralExtra) //加载全局插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载全局插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载") self.isLoadingGlobalInterstitialAd = false loadGlobalInterstitialAd(level+1, completion: completion) } else { self.globalInterstitialAd = ad self.isLoadingGlobalInterstitialAd = false //实现代理 self.globalInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadGlobalInterstitialAdTime = Date() completion(true) } } } } ///全局插页广告展示 func showGlobalInterstitialAdIfAvailable(completion:((GADInterstitialAd?) -> Void)?) { guard openAdStatus, internalAdStatus else { return } // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingGlobalInterstitialAd, retrieveIntermediaryOpen() else { return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") return } } // 如果全局广告尚不可用但应该显示,则加载新广告。 if !isGlobalInterstitialAdAvailable() { loadGlobalInterstitialAd { [weak self] success in guard let self = self else { return } if success { self.showGlobalInterstitialAdIfAvailable(completion: completion) }else { completion?(nil) } } return } //当全局插页广告确定有值后展示 if let ad = globalInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingGlobalInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } } } //查询是否有全局插页广告 func isGlobalInterstitialAdAvailable() -> Bool { return globalInterstitialAd != nil && wasAdexpirationTime(loadGlobalInterstitialAdTime) } //MARK: - 广告音频代理 GADAudioVideoManagerDelegate //广告将会播放视频 func audioVideoManagerWillPlayVideo(_ audioVideoManager: GADAudioVideoManager) { // print("广告将会播放视频") } //广告将会暂停播放所有视频 func audioVideoManagerDidPauseAllVideo(_ audioVideoManager: GADAudioVideoManager) { // print("广告暂停播放视频") } //广告将要播放音频 func audioVideoManagerWillPlayAudio(_ audioVideoManager: GADAudioVideoManager) { accessAppdelegate.setAudioActive() } //广告停止播放音频 func audioVideoManagerDidStopPlayingAudio(_ audioVideoManager: GADAudioVideoManager) { DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { accessAppdelegate.setAudioActive() } } //MARK: - 覆盖型广告代理 GADFullScreenContentDelegate //覆盖型广告将要将要展示 func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) { if ad === appOpenAd || ad === appInterstitialAd {//开屏广告 print("当前展示的广告是开屏广告,广告ID--\(appOpenAd != nil ? (appOpenAd?.adUnitID ?? ""):(appInterstitialAd?.adUnitID ?? ""))") //当前是热启动还是冷启动 if OpenICEID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) { //冷启动,检索是插页还是开屏 if let openAd = appOpenAd { if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { //上传广告收益 openAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) } }else { MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } }else if let openAd = appInterstitialAd { if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { //上传广告收益 openAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) } }else { MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } } }else if OpenHOSTID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) { //热启动,检索是插页还是开屏 if let openAd = appOpenAd { if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { //上传广告收益 openAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) } }else { MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } }else if let openAd = appInterstitialAd { if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { //上传广告收益 openAd.paidEventHandler = { adValue in MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) } }else { MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } } } }else if ad === searchInterstitialAd {//搜索插页广告 print("当前展示的广告是搜索插页广告,广告ID--\(searchInterstitialAd?.adUnitID ?? "")") if MP_AnalyticsManager.shared.infoFromAdMobSource(searchInterstitialAd?.responseInfo) { searchInterstitialAd?.paidEventHandler = { adValue in if let response = self.searchInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.search_ads_showSuccessAction(response, adValue: adValue) } } }else { if let response = self.searchInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.search_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === playInterstitialAd {//播放插页广告 print("当前展示的广告是播放插页广告,广告ID--\(playInterstitialAd?.adUnitID ?? "")") if MP_AnalyticsManager.shared.infoFromAdMobSource(playInterstitialAd?.responseInfo) { playInterstitialAd?.paidEventHandler = { adValue in if let response = self.playInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) } } }else { if let response = self.playInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === switchInterstitialAd {//切歌插页广告 print("当前展示的广告是切歌插页广告,广告ID--\(switchInterstitialAd?.adUnitID ?? "")") if MP_AnalyticsManager.shared.infoFromAdMobSource(switchInterstitialAd?.responseInfo) { switchInterstitialAd?.paidEventHandler = { adValue in if let response = self.switchInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.cut_ads_showSuccessAction(response, adValue: adValue) } } }else { if let response = self.switchInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.cut_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === loadInterstitialAd {//下载插页广告 print("当前展示的广告是下载插页广告,广告ID--\(loadInterstitialAd?.adUnitID ?? "")") if MP_AnalyticsManager.shared.infoFromAdMobSource(switchInterstitialAd?.responseInfo) { loadInterstitialAd?.paidEventHandler = { adValue in if let response = self.loadInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.dl_ads_showSuccessAction(response, adValue: adValue) } } }else { if let response = self.loadInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.dl_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === libraryInterstitialAd {//曲库插页广告 print("当前展示的广告是曲库插页广告,广告ID--\(libraryInterstitialAd?.adUnitID ?? "")") if MP_AnalyticsManager.shared.infoFromAdMobSource(switchInterstitialAd?.responseInfo) { libraryInterstitialAd?.paidEventHandler = { adValue in if let response = self.libraryInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.listclk_ads_showSuccessAction(response, adValue: adValue) } } }else { if let response = self.libraryInterstitialAd?.responseInfo { MP_AnalyticsManager.shared.listclk_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === globalInterstitialAd {//全局插页广告 print("当前展示的广告是全局插页广告,广告ID--\(globalInterstitialAd?.adUnitID ?? "")") } } //覆盖型广告已经消失 func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) { //更新插页广告展示时间 interstitialDate = Date() if ad === appOpenAd || ad === appInterstitialAd {//开屏广告 print("当前消失的广告是开屏广告,广告ID--\(appOpenAd != nil ? (appOpenAd?.adUnitID ?? ""):(appInterstitialAd?.adUnitID ?? ""))") //执行开屏广告完成事件包 if completeOpenAdBlock != nil { completeOpenAdBlock!() } }else if ad === searchInterstitialAd {//搜索插页广告 print("当前消失的广告是搜索插页广告,广告ID--\(searchInterstitialAd?.adUnitID ?? "")") //执行搜索插页广告完成事件包 if completeSearchInterstitialAdBlock != nil { completeSearchInterstitialAdBlock!() } }else if ad === playInterstitialAd {//播放插页广告 print("当前消失的广告是播放插页广告,广告ID--\(playInterstitialAd?.adUnitID ?? "")") //执行播放插页广告完成事件包 if completePlayInterstitialAdBlock != nil { completePlayInterstitialAdBlock!() } }else if ad === switchInterstitialAd {//播放插页广告 print("当前消失的广告是切歌插页广告,广告ID--\(switchInterstitialAd?.adUnitID ?? "")") //执行播放插页广告完成事件包 if completeSwitchInterstitialAdBlock != nil { completeSwitchInterstitialAdBlock!() } }else if ad === loadInterstitialAd {//下载插页广告 print("当前消失的广告是下载插页广告,广告ID--\(loadInterstitialAd?.adUnitID ?? "")") //执行播放插页广告完成事件包 if completeLoadInterstitialAdBlock != nil { completeLoadInterstitialAdBlock!() } }else if ad === libraryInterstitialAd {//曲库插页广告 print("当前消失的广告是曲库插页广告,广告ID--\(libraryInterstitialAd?.adUnitID ?? "")") //执行搜索插页广告完成事件包 if completeLibraryInterstitialAdBlock != nil { completeLibraryInterstitialAdBlock!() } }else if ad === globalInterstitialAd {///全局插页广告 print("当前消失的广告是全局插页广告,广告ID--\(globalInterstitialAd?.adUnitID ?? "")") //执行搜索插页广告完成事件包 if completeGlobalInterstitialAdBlock != nil { completeGlobalInterstitialAdBlock!() } } DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { accessAppdelegate.setAudioActive() } } //覆盖型广告加载出错 func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { //更新插页广告展示时间 interstitialDate = Date() if ad === appOpenAd || ad === appInterstitialAd {//应用开屏广告 print("开屏广告展示时出错,广告ID--\(appOpenAd != nil ? (appOpenAd?.adUnitID ?? ""):(appInterstitialAd?.adUnitID ?? "")),具体错误原因:\(error.localizedDescription)") //判断是冷启动还是热启动 if OpenICEID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) { MP_AnalyticsManager.shared.cold_ads_showFailureAction(error.localizedDescription) }else if OpenHOSTID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) { MP_AnalyticsManager.shared.hot_ads_showFailureAction(error.localizedDescription) } if completeOpenAdBlock != nil { completeOpenAdBlock!() } }else if ad === searchInterstitialAd {//搜索插页广告 print("搜索插页广告展示时出错,广告ID--\(searchInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") MP_AnalyticsManager.shared.search_ads_showFailureAction(error.localizedDescription) if completeSearchInterstitialAdBlock != nil { completeSearchInterstitialAdBlock!() } }else if ad === playInterstitialAd {//播放插页广告 print("播放插页广告展示时出错,广告ID--\(playInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") MP_AnalyticsManager.shared.play_ads_showFailureAction(error.localizedDescription) //执行播放插页广告完成事件包 if completePlayInterstitialAdBlock != nil { completePlayInterstitialAdBlock!() } }else if ad === switchInterstitialAd {//切歌插页广告 print("切歌插页广告展示时出错,广告ID--\(switchInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") MP_AnalyticsManager.shared.cut_ads_showFailureAction(error.localizedDescription) //执行播放插页广告完成事件包 if completeSwitchInterstitialAdBlock != nil { completeSwitchInterstitialAdBlock!() } }else if ad === loadInterstitialAd {//下载插页广告 print("下载插页广告展示时出错,广告ID--\(loadInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") MP_AnalyticsManager.shared.dl_ads_showFailureAction(error.localizedDescription) //执行下载插页广告完成事件包 if completeLoadInterstitialAdBlock != nil { completeLoadInterstitialAdBlock!() } }else if ad === libraryInterstitialAd {//搜索插页广告 print("曲库插页广告展示时出错,广告ID--\(libraryInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") MP_AnalyticsManager.shared.listclk_ads_showFailureAction(error.localizedDescription) if completeLibraryInterstitialAdBlock != nil { completeLibraryInterstitialAdBlock!() } }else if ad === globalInterstitialAd {//全局插页广告 print("全局插页广告展示时出错,广告ID--\(globalInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") if completeGlobalInterstitialAdBlock != nil { completeGlobalInterstitialAdBlock!() } } DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { accessAppdelegate.setAudioActive() } } //MARK: - GADNativeAdLoaderDelegate // 原生广告已加载,可以展示。 func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) { if nativeAd.mediaContent.hasVideoContent { // //判断这个原生广告是什么类型 // nativeAd.mediaContent.videoController.setMute(true) // nativeAd.mediaContent.videoController.delegate = self } if adLoader == searchAdLoader {//加载的是搜索原生广告 print("搜索原生已经加载完毕") self.searchNativeAd = nativeAd self.expirationSearchDate = Date() if let block = self.onSearchNativeAdBlock { block() } }else if adLoader == libraryAdLoader {//加载的是曲库原生广告 print("曲库原生已经加载完毕") guard libraryNativeAds != nil else { return } if (libraryNativeAds?.count ?? 0) < 2 { //添加广告 libraryNativeAds?.append(nativeAd) }else { //已经有一批广告了,销毁掉 libraryNativeAds = [] libraryNativeAds?.append(nativeAd) } //判断是否加载结束 if (libraryNativeAds?.count ?? 0) == 2 { self.expirationLibraryDate = Date() if let block = self.onLibraryNativeAdBlock { block() } } } } // 原生广告加载错误 func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: any Error) { if adLoader == searchAdLoader {//加载的是搜索原生广告 print("加载搜索原生广告发生错误,错误详情:\(error.localizedDescription)") DispatchQueue.main.asyncAfter(deadline: .now() + 300) { [weak self] in guard let self = self else {return} loadSearchNativeAd() } }else if adLoader == libraryAdLoader {//加载的是曲库原生广告 print("加载曲库原生广告发生错误,错误详情:\(error.localizedDescription)") DispatchQueue.main.asyncAfter(deadline: .now() + 300) { [weak self] in guard let self = self else {return} loadLibraryNativeAd() } } } // 原生广告已展示。 func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) { print("原生广告刷新") } // 原生广告被点击了。 func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) { print("原生广告被点击") } // 原生广告将呈现全屏视图。 func nativeAdWillPresentScreen(_ nativeAd: GADNativeAd) { print("原生广告将弹出一个新视图") } // 原生广告将会关闭全屏视图。 func nativeAdWillDismissScreen(_ nativeAd: GADNativeAd) { print("原生广告视图将要关闭") } // 原生广告关闭了全屏视图。 func nativeAdDidDismissScreen(_ nativeAd: GADNativeAd) { print("原生广告视图已经关闭") } // 原生广告将导致应用处于非活动状态并且打开新的应用。 func nativeAdWillLeaveApplication(_ nativeAd: GADNativeAd) { } //MARK: - GADVideoControllerDelegate // 开始播放原生视频广告 func videoControllerDidPlayVideo(_ videoController: GADVideoController) { //强制切回控制中心权限 } // 暂停原生视频广告 func videoControllerDidPauseVideo(_ videoController: GADVideoController) { //强制切回控制中心权限 } // 停止播放视频广告 func videoControllerDidEndVideoPlayback(_ videoController: GADVideoController) { //强制切回控制中心权限 } }