// // MP_AdMobManager.swift // relax.offline.mp3.music // // Created by Mr.Zhou on 2024/6/14. // import UIKit import AVFoundation import GoogleMobileAds ///广告管理器 class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoaderDelegate, GADNativeAdDelegate { static let shared = MP_AdMobManager() 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 MP_PlayerManager.shared.isAdLate = self?.interstitialSwitch MPSideA_MediaCenterManager.shared.isAdLate = self?.interstitialSwitch } } } ///插页广告显示时间 private var interstitialDate:Date? ///插页广告间隔秒数(默认30秒) private var interstitialDuration:TimeInterval = 30 ///设置插页总开关 func setInterstitialSwitch(_ status:Bool) { interstitialSwitch = status } ///获得插页开关的状态 func getInterstitialSwitch() -> Bool { return interstitialSwitch } ///设置插页广告间隔秒数 func setInterstitialDuration(_ duration:TimeInterval?) { self.interstitialDuration = duration ?? 30 } ///是否达到插页间隔时长(达到即可继续展示插页广告) private func isShowInterstitialADAvailable(_ date:Date) -> Bool { return Date().timeIntervalSince(date) > interstitialDuration } private override init() { super.init() //对开屏广告完成处理闭包 completeOpenAdBlock = { [weak self] in guard let self = self, interstitialSwitch == true else {return} //销毁现在的开屏广告实例 appOpenAd = nil isShowingOpenAd = false loadOpenAdTime = nil //关闭插页广告开关 interstitialSwitch = false //重新加载后续的开屏广告 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 //重新加载后续的搜索插页广告 loadSearchInterstitialAd { status in if status { print("成功加载搜索插页广告") }else { print("搜索插页广告加载失败") } } } //播放插页广告完成处理闭包 completePlayInterstitialAdBlock = { [weak self] type in guard let self = self, interstitialSwitch == true else {return} //销毁现在的播放插页广告实例 playInterstitialAd = nil isShowingPlayInterstitialAd = false loadPlayInterstitialAdTime = nil //关闭插页广告开关 interstitialSwitch = false //重新加载后续的播放插页广告 loadPlayInterstitialAd(type) { 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 //重新加载后续的曲库插页广告 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 //重新加载后续的全局插页广告 loadGlobalInterstitialAd { status in if status { print("成功加载全局插页广告") }else { print("全局插页广告加载失败") } } } } deinit{ displaySearchTimer?.invalidate() displaySearchTimer = nil displayLibraryTimer?.invalidate() displayLibraryTimer = nil } ///开始缓存广告 func start() { sharedInstance.start { status in print("App启动,开始加载广告") } } //MARK: - 开屏 //开屏冷启动广告ID private let OpenICEID:String = "ca-app-pub-1371732277241593/1926543650" //开屏热启动广告ID private let OpenHOSTID:String = "ca-app-pub-1371732277241593/3299335073" //开屏广告类型 enum OpenType:Int { //冷启动 case ICE = 0 //热启动 case HOST = 1 var title:String{ switch self { case .ICE: return "是冷启动开屏广告" case .HOST: return "是热启动开屏广告" } } } //开屏广告实例 private var appOpenAd:GADAppOpenAd? //是否正在加载广告 private var isLoadingOpenAd:Bool = false //是否正在展示广告 var isShowingOpenAd:Bool = false //开屏广告加载时间 private var loadOpenAdTime:Date? //开屏广告时间间隔(默认5秒) private var openAppDuration:TimeInterval = 10 //设置开屏广告时间间隔 func setOpenAppDuration(_ duration:TimeInterval) { self.openAppDuration = duration } //获取开屏广告时间间隔 func getOpenAppDuration() -> TimeInterval { return self.openAppDuration } //开屏广告加载完成处理闭包 var completeOpenAdBlock:(() -> Void)? ///异步加载开屏广告 func loadOpenAd(_ type:OpenType,completion: @escaping (Bool) -> Void) { // 检测当前是否有广告或者有广告正在加载 if isLoadingOpenAd || isOpenAdAvailable() { // 有广告或有广告在加载 completion(false) return } isLoadingOpenAd = true var UUID:String switch type { case .ICE: UUID = OpenICEID case .HOST: UUID = OpenHOSTID } // 使用 GADAppOpenAd 的 load 方法和一个completion handler来加载广告 GADAppOpenAd.load(withAdUnitID: UUID, request: GADRequest()) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载开屏广告失败,失败原因: \(error.localizedDescription)") self.isLoadingOpenAd = false completion(false) } else { self.appOpenAd = ad self.isLoadingOpenAd = false //实现代理 self.appOpenAd?.fullScreenContentDelegate = self //更新加载时间 self.loadOpenAdTime = Date() completion(true) } } } } ///开屏广告展示 func showOpenAdIfAvailable(_ type:OpenType, completion:((GADAppOpenAd) -> Void)?) { // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingOpenAd else { return } // 如果应用开屏广告尚不可用但应该显示,则加载新广告。 if !isOpenAdAvailable() { loadOpenAd(type) { [weak self] success in guard let self = self else { return } if success { self.showOpenAdIfAvailable(type, completion: completion) } } return } //当开屏广告确定有值后展示 if let ad = appOpenAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingOpenAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } } } ///查询是否有开屏广告 func isOpenAdAvailable() -> Bool { return appOpenAd != nil && wasAdexpirationTime(loadOpenAdTime) } //MARK: - 搜索 //搜索插页广告ID private let SearchINSERTID:String = "ca-app-pub-1371732277241593/8622500865" //搜索原生广告ID private let SearchNATIVEID:String = "ca-app-pub-1371732277241593/5674216970" ///搜索插页广告 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 let vc = searchViewController else {return} let multipleAdOptions = GADMultipleAdsAdLoaderOptions() //加载一条,每次即使结束后重新刷新数据 multipleAdOptions.numberOfAds = 1 searchAdLoader = GADAdLoader(adUnitID: SearchNATIVEID, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions]) searchAdLoader?.delegate = self searchAdLoader?.load(GADRequest()) } ///将加载的搜索原生广告添加到页面中 func layoutSearchNativeAd(in containerView: UIView) { 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.addHorizontalConstraintsToSuperviewWidth() templateView.addVerticalCenterConstraintToSuperview() templateView.snp.updateConstraints { make in make.height.equalTo(150*width) } //创建一个choiveView let customRect = CGRect(x: screen_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(150*width) } templateView.nativeAd = nativeAd MP_AnalyticsManager.shared.result_ads_chanceAction() MP_AnalyticsManager.shared.result_ads_showAction() // 设置展示计时器,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(completion: @escaping (Bool) -> Void) { // 检测当前是否有广告或者有广告正在加载 if isLoadingSearchInterstitialAd || isSearchInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } isLoadingSearchInterstitialAd = true //加载搜索插页广告 GADInterstitialAd.load(withAdUnitID: SearchINSERTID, request: GADRequest()) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载搜索插页广告失败,失败原因: \(error.localizedDescription)") self.isLoadingSearchInterstitialAd = false //开始加载全局插页 loadGlobalInterstitialAd { status in completion(status) } } else { self.searchInterstitialAd = ad self.isLoadingSearchInterstitialAd = false //实现代理 self.searchInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadSearchInterstitialAdTime = Date() completion(true) } } } } ///搜索插页广告展示 func showSearchInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingSearchInterstitialAd 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) } } return } //当搜索插页广告确定有值后展示 if let ad = searchInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingSearchInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else if let ad = globalInterstitialAd { //加载全局插页广告 //传递加载完成事件 if let block = completion { block(ad) }else { isShowingGlobalInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } } } //查询是否有搜索插页广告 func isSearchInterstitialAdAvailable() -> Bool { return searchInterstitialAd != nil && wasAdexpirationTime(loadSearchInterstitialAdTime) } //MARK: - 播放 //播放插页广告ID private let PlayerINSERTID:String = "ca-app-pub-1371732277241593/6339952454" //切歌插页广告ID private let SwitchINSERTID:String = "ca-app-pub-1371732277241593/8439981117" //下载插页广告ID private let LoadINSERTID:String = "ca-app-pub-1371732277241593/3107763383" //播放组插页广告类型 enum PlayerType: Int{ //播放时 case Play //切歌时 case Switch //下载时 case Load } ///播放插页广告 var playInterstitialAd:GADInterstitialAd? ///是否正在加载播放插页广告 private var isLoadingPlayInterstitialAd:Bool = false ///是否正在展示播放插页广告 var isShowingPlayInterstitialAd:Bool = false ///播放插页加载时间 private var loadPlayInterstitialAdTime:Date? ///播放广告处理闭包 var completePlayInterstitialAdBlock:((PlayerType) -> Void)? //异步加载播放插页广告 func loadPlayInterstitialAd(_ type:PlayerType, completion: @escaping (Bool) -> Void) { // 检测当前是否有广告或者有广告正在加载 if isLoadingPlayInterstitialAd || isPlayInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } isLoadingPlayInterstitialAd = true var UUID:String switch type { case .Play: UUID = PlayerINSERTID case .Switch: UUID = SwitchINSERTID case .Load: UUID = LoadINSERTID } //加载播放插页广告 GADInterstitialAd.load(withAdUnitID: UUID, request: GADRequest()) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载播放插页广告失败,失败原因: \(error.localizedDescription)") self.isLoadingPlayInterstitialAd = false loadGlobalInterstitialAd { status in completion(status) } } else { self.playInterstitialAd = ad self.isLoadingPlayInterstitialAd = false //实现代理 self.playInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadPlayInterstitialAdTime = Date() completion(true) } } } } ///播放插页广告展示 func showPlayInterstitialAdIfAvailable(_ type:PlayerType,completion:((GADInterstitialAd) -> Void)?) { // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingPlayInterstitialAd else { return } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") return } } // 如果播放插页广告尚不可用但应该显示,则加载新广告。 if !isPlayInterstitialAdAvailable() { loadPlayInterstitialAd(type) { [weak self] success in guard let self = self else { return } if success { self.showPlayInterstitialAdIfAvailable(type, completion: completion) } } return } //当播放插页广告确定有值后展示 if let ad = playInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingPlayInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else if let ad = globalInterstitialAd { //加载全局插页广告 //传递加载完成事件 if let block = completion { block(ad) }else { isShowingGlobalInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } } } //查询是否有播放插页广告 func isPlayInterstitialAdAvailable() -> Bool { return playInterstitialAd != nil && wasAdexpirationTime(loadPlayInterstitialAdTime) } //MARK: - 曲库 //曲库插页ID private let LibraryINSERTID:String = "ca-app-pub-1371732277241593/5298812459" //曲库原生ID private let LibraryNATIVEID:String = "ca-app-pub-1371732277241593/4683255855" ///曲库插页广告 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) { if libraryViewController == nil { libraryViewController = vc } } ///搜索原生广告加载 func loadLibraryNativeAd() { guard let vc = libraryViewController, libraryNativeAds == nil else {return} let multipleAdOptions = GADMultipleAdsAdLoaderOptions() //加载一条,每次即使结束后重新刷新数据 multipleAdOptions.numberOfAds = 2 libraryAdLoader = GADAdLoader(adUnitID: LibraryNATIVEID, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions]) libraryAdLoader?.delegate = self libraryAdLoader?.load(GADRequest()) libraryNativeAds = [] } ///将加载的搜索原生广告添加到页面中 func layoutLibraryNativeAd(in containerView: UIView, index:Int) { containerView.subviews.forEach { item in item.removeFromSuperview() } if index == 0 { //曲库第一页 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.addHorizontalConstraintsToSuperviewWidth() templateView.addVerticalCenterConstraintToSuperview() templateView.snp.updateConstraints { make in make.height.equalTo(150*width) } //创建一个choiveView let customRect = CGRect(x: screen_Width-25, y: 0, width: 25, height: 25) let customAdChoicesView = GADAdChoicesView(frame: customRect) templateView.addSubview(customAdChoicesView) templateView.adChoicesView = customAdChoicesView templateView.nativeAd = nativeAd MP_AnalyticsManager.shared.lbr_ads_chanceAction() MP_AnalyticsManager.shared.lbr_ads_showAction() }else { //曲库第二页 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.addHorizontalConstraintsToSuperviewWidth() templateView.addVerticalCenterConstraintToSuperview() templateView.snp.updateConstraints { make in make.height.equalTo(150*width) } //创建一个choiveView let customRect = CGRect(x: screen_Width-25, y: 0, width: 25, height: 25) let customAdChoicesView = GADAdChoicesView(frame: customRect) templateView.addSubview(customAdChoicesView) templateView.adChoicesView = customAdChoicesView templateView.nativeAd = nativeAd MP_AnalyticsManager.shared.list_ads_chanceAction() MP_AnalyticsManager.shared.list_ads_showAction() } DispatchQueue.main.async { [weak self] in containerView.snp.updateConstraints { make in make.height.equalTo(150*width) } } // 设置展示计时器,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(completion: @escaping (Bool) -> Void) { // 检测当前是否有广告或者有广告正在加载 if isLoadingLibraryInterstitialAd || isLibraryInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } isLoadingLibraryInterstitialAd = true //加载曲库插页广告 GADInterstitialAd.load(withAdUnitID: LibraryINSERTID, request: GADRequest()) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载曲库插页广告失败,失败原因: \(error.localizedDescription)") self.isLoadingLibraryInterstitialAd = false loadGlobalInterstitialAd { status in completion(status) } } else { self.libraryInterstitialAd = ad self.isLoadingLibraryInterstitialAd = false //实现代理 self.libraryInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadLibraryInterstitialAdTime = Date() completion(true) } } } } ///曲库插页广告展示 func showLibraryInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingLibraryInterstitialAd 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) } } return } //当曲库插页广告确定有值后展示 if let ad = libraryInterstitialAd { //传递加载完成事件 if let block = completion { block(ad) }else { isShowingLibraryInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } }else if let ad = globalInterstitialAd { //加载全局插页广告 //传递加载完成事件 if let block = completion { block(ad) }else { isShowingGlobalInterstitialAd = true interstitialSwitch = true ad.present(fromRootViewController: nil) } } } //查询是否有曲库插页广告 func isLibraryInterstitialAdAvailable() -> Bool { return libraryInterstitialAd != nil && wasAdexpirationTime(loadLibraryInterstitialAdTime) } //MARK: - 全局 //全局备用插页ID private let GlobalINSERTID:String = "ca-app-pub-1371732277241593/3713789116" ///全局插页广告 private var globalInterstitialAd:GADInterstitialAd? ///是否正在加载全局插页广告 private var isLoadingGlobalInterstitialAd:Bool = false ///是否正在展示全局插页广告 var isShowingGlobalInterstitialAd:Bool = false ///全局插页加载时间 private var loadGlobalInterstitialAdTime:Date? ///全局广告处理闭包 var completeGlobalInterstitialAdBlock:(() -> Void)? //异步加载全局插页广告 func loadGlobalInterstitialAd(completion: @escaping (Bool) -> Void) { // 检测当前是否有广告或者有广告正在加载 if isLoadingGlobalInterstitialAd || isGlobalInterstitialAdAvailable() { // 有广告或有广告在加载 completion(false) return } isLoadingGlobalInterstitialAd = true //加载全局插页广告 GADInterstitialAd.load(withAdUnitID: GlobalINSERTID, request: GADRequest()) { ad, error in DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let error = error { print("加载全局插页广告失败,失败原因: \(error.localizedDescription)") self.isLoadingGlobalInterstitialAd = false completion(false) } else { self.globalInterstitialAd = ad self.isLoadingGlobalInterstitialAd = false //实现代理 self.globalInterstitialAd?.fullScreenContentDelegate = self //更新加载时间 self.loadGlobalInterstitialAdTime = Date() completion(true) } } } } ///全局插页广告展示 func showGlobalInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 guard !interstitialSwitch, !isShowingGlobalInterstitialAd 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) } } 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: - 覆盖型广告代理 GADFullScreenContentDelegate //覆盖型广告将要将要展示 func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) { if ad === appOpenAd {//开屏广告 print("当前展示的广告是开屏广告,广告ID--\(appOpenAd?.adUnitID ?? "")") //判断是冷启动还是热启动 if appOpenAd?.adUnitID == OpenICEID { MP_AnalyticsManager.shared.cold_ads_showAction() MP_AnalyticsManager.shared.cold_ads_chanceAction() }else if appOpenAd?.adUnitID == OpenHOSTID { MP_AnalyticsManager.shared.hot_ads_showAction() MP_AnalyticsManager.shared.hot_ads_chanceAction() } }else if ad === searchInterstitialAd {//搜索插页广告 print("当前展示的广告是搜索插页广告,广告ID--\(searchInterstitialAd?.adUnitID ?? "")") MP_AnalyticsManager.shared.search_ads_chanceAction() MP_AnalyticsManager.shared.search_ads_showAction() }else if ad === playInterstitialAd {//播放插页广告 print("当前展示的广告是播放插页广告,广告ID--\(playInterstitialAd?.adUnitID ?? "")") let UUID = playInterstitialAd?.adUnitID ?? "" if UUID == PlayerINSERTID { MP_AnalyticsManager.shared.play_ads_chanceAction() MP_AnalyticsManager.shared.play_ads_showAction() }else if UUID == SwitchINSERTID { MP_AnalyticsManager.shared.cut_ads_chanceAction() MP_AnalyticsManager.shared.cut_ads_showAction() }else if UUID == LoadINSERTID { MP_AnalyticsManager.shared.dl_ads_chanceAction() MP_AnalyticsManager.shared.dl_ads_showAction() } }else if ad === libraryInterstitialAd {//曲库插页广告 print("当前展示的广告是曲库插页广告,广告ID--\(libraryInterstitialAd?.adUnitID ?? "")") MP_AnalyticsManager.shared.listclk_ads_chanceAction() MP_AnalyticsManager.shared.listclk_ads_showAction() }else if ad === globalInterstitialAd {//全局插页广告 print("当前展示的广告是全局插页广告,广告ID--\(globalInterstitialAd?.adUnitID ?? "")") } } //覆盖型广告已经消失 func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) { //更新插页广告展示时间 interstitialDate = Date() if ad === appOpenAd {//开屏广告 print("当前消失的广告是开屏广告,广告ID--\(appOpenAd?.adUnitID ?? "")") //执行开屏广告完成事件包 if completeOpenAdBlock != nil { completeOpenAdBlock!() } }else if ad === searchInterstitialAd {//搜索插页广告 print("当前消失的广告是搜索插页广告,广告ID--\(searchInterstitialAd?.adUnitID ?? "")") //执行搜索插页广告完成事件包 if completeSearchInterstitialAdBlock != nil { completeSearchInterstitialAdBlock!() } }else if ad === playInterstitialAd {//播放插页广告 let UUID = playInterstitialAd?.adUnitID ?? "" print("当前消失的广告是播放插页广告,广告ID--\(UUID)") var type:PlayerType = .Play if UUID == PlayerINSERTID { type = .Play }else if UUID == SwitchINSERTID { type = .Switch }else if UUID == LoadINSERTID { type = .Load } //执行播放插页广告完成事件包 if completePlayInterstitialAdBlock != nil { completePlayInterstitialAdBlock!(type) } }else if ad === libraryInterstitialAd {//曲库插页广告 print("当前消失的广告是曲库插页广告,广告ID--\(libraryInterstitialAd?.adUnitID ?? "")") //执行搜索插页广告完成事件包 if completeLibraryInterstitialAdBlock != nil { completeLibraryInterstitialAdBlock!() } }else if ad === globalInterstitialAd {///全局插页广告 print("当前消失的广告是全局插页广告,广告ID--\(globalInterstitialAd?.adUnitID ?? "")") //执行搜索插页广告完成事件包 if completeGlobalInterstitialAdBlock != nil { completeGlobalInterstitialAdBlock!() } } accessAppdelegate.setAudioSupport() } //覆盖型广告加载出错 func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { //更新插页广告展示时间 interstitialDate = Date() if ad === appOpenAd {//开屏广告 print("开屏广告展示时出错,广告ID--\(appOpenAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") if completeOpenAdBlock != nil { completeOpenAdBlock!() } }else if ad === searchInterstitialAd {//搜索插页广告 print("搜索插页广告展示时出错,广告ID--\(searchInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") if completeSearchInterstitialAdBlock != nil { completeSearchInterstitialAdBlock!() } }else if ad === playInterstitialAd {//播放插页广告 let UUID = playInterstitialAd?.adUnitID ?? "" print("播放插页广告展示时出错,广告ID--\(UUID),具体错误原因:\(error.localizedDescription)") var type:PlayerType = .Play if UUID == PlayerINSERTID { type = .Play }else if UUID == SwitchINSERTID { type = .Switch }else if UUID == LoadINSERTID { type = .Load } //执行播放插页广告完成事件包 if completePlayInterstitialAdBlock != nil { completePlayInterstitialAdBlock!(type) } }else if ad === libraryInterstitialAd {//搜索插页广告 print("曲库插页广告展示时出错,广告ID--\(libraryInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") if completeLibraryInterstitialAdBlock != nil { completeLibraryInterstitialAdBlock!() } }else if ad === globalInterstitialAd {//全局插页广告 print("全局插页广告展示时出错,广告ID--\(globalInterstitialAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)") if completeGlobalInterstitialAdBlock != nil { completeGlobalInterstitialAdBlock!() } } accessAppdelegate.setAudioSupport() } //MARK: - GADNativeAdLoaderDelegate // 原生广告已展示。 func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) { } // 原生广告被点击了。 func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) { } // 原生广告将呈现全屏视图。 func nativeAdWillPresentScreen(_ nativeAd: GADNativeAd) { } // 原生广告将会关闭全屏视图。 func nativeAdWillDismissScreen(_ nativeAd: GADNativeAd) { } // 原生广告关闭了全屏视图。 func nativeAdDidDismissScreen(_ nativeAd: GADNativeAd) { } // 原生广告将导致应用处于非活动状态并且打开新的应用。 func nativeAdWillLeaveApplication(_ nativeAd: GADNativeAd) { } // 原生广告已加载,可以展示。 func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) { 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() } } } }