diff --git a/ThimraTV.xcodeproj/project.pbxproj b/ThimraTV.xcodeproj/project.pbxproj index 05184a8..93ef0ea 100644 --- a/ThimraTV.xcodeproj/project.pbxproj +++ b/ThimraTV.xcodeproj/project.pbxproj @@ -282,6 +282,7 @@ 1BF513112E1FA138009750EA /* SPStatAdModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513102E1FA138009750EA /* SPStatAdModel.swift */; }; 1BF513142E1FB8C1009750EA /* SPAppOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513132E1FB8C1009750EA /* SPAppOpenAdManager.swift */; }; 1BF513162E20ADB4009750EA /* SPAppOpenAdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */; }; + 1BF513192E20DC85009750EA /* SPBannerAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513182E20DC85009750EA /* SPBannerAd.swift */; }; C3D1CE788CA03A1878493356 /* Pods_ThimraTV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B64805795B479324EB764157 /* Pods_ThimraTV.framework */; }; /* End PBXBuildFile section */ @@ -595,6 +596,7 @@ 1BF513102E1FA138009750EA /* SPStatAdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPStatAdModel.swift; sourceTree = ""; }; 1BF513132E1FB8C1009750EA /* SPAppOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAppOpenAdManager.swift; sourceTree = ""; }; 1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAppOpenAdViewController.swift; sourceTree = ""; }; + 1BF513182E20DC85009750EA /* SPBannerAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPBannerAd.swift; sourceTree = ""; }; 1DBC40592DA4EDFC0093FCB0 /* ThimraTV.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ThimraTV.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1F666DE0B12C863F26BE5027 /* Pods-MoviaBox.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoviaBox.debug.xcconfig"; path = "Target Support Files/Pods-MoviaBox/Pods-MoviaBox.debug.xcconfig"; sourceTree = ""; }; A1174E10BCF2C606F7818792 /* Pods-ThimraTV.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ThimraTV.release.xcconfig"; path = "Target Support Files/Pods-ThimraTV/Pods-ThimraTV.release.xcconfig"; sourceTree = ""; }; @@ -1485,6 +1487,7 @@ 1BDE20112E1E158400C2C2B5 /* AdManager */ = { isa = PBXGroup; children = ( + 1BF513172E20DC63009750EA /* BannerAd */, 1BF513122E1FB897009750EA /* AppOpenAd */, 1BF5130F2E1F5EE4009750EA /* RewardedAd */, 1BDE20122E1E159B00C2C2B5 /* SPAdManager.swift */, @@ -1512,6 +1515,14 @@ path = AppOpenAd; sourceTree = ""; }; + 1BF513172E20DC63009750EA /* BannerAd */ = { + isa = PBXGroup; + children = ( + 1BF513182E20DC85009750EA /* SPBannerAd.swift */, + ); + path = BannerAd; + sourceTree = ""; + }; 1DBC40502DA4EDFC0093FCB0 = { isa = PBXGroup; children = ( @@ -1831,6 +1842,7 @@ 1BF5130C2E1F4660009750EA /* SPRewardedAdManager+AppLovin.swift in Sources */, 1BB91D712E04FD6A00A2C715 /* SPHomeHotView.swift in Sources */, 1BB91D722E04FD6A00A2C715 /* SPHomeNineSquareContentCell.swift in Sources */, + 1BF513192E20DC85009750EA /* SPBannerAd.swift in Sources */, 1BB91D732E04FD6A00A2C715 /* SPHomePlayHistoricalView.swift in Sources */, 1BDE20172E1E164600C2C2B5 /* SPAdAPI.swift in Sources */, 1BB91D742E04FD6A00A2C715 /* SPHomePlayHistoryCell.swift in Sources */, diff --git a/ThimraTV/Class/Player/Controller/SPPlayerDetailViewController.swift b/ThimraTV/Class/Player/Controller/SPPlayerDetailViewController.swift index f0c6fd9..0e0815e 100644 --- a/ThimraTV/Class/Player/Controller/SPPlayerDetailViewController.swift +++ b/ThimraTV/Class/Player/Controller/SPPlayerDetailViewController.swift @@ -164,12 +164,14 @@ class SPPlayerDetailViewController: SPPlayerListViewController { guard let self = self else { return } self._handleBack() - let manager = SPRewardedAdManager.manager - manager.delegate = nil - manager.statScene = .detail - manager.videoInfo = self.viewModel.currentPlayer?.videoInfo - if manager.isAdAvailable() { - manager.loadAndShowRewardedAd() + if SPLoginManager.manager.userInfo?.user_level == .ad { + let manager = SPRewardedAdManager.manager + manager.delegate = nil + manager.statScene = .detail + manager.videoInfo = self.viewModel.currentPlayer?.videoInfo + if manager.isAdAvailable() { + manager.loadAndShowRewardedAd() + } } } diff --git a/ThimraTV/Class/Player/View/SPPlayerDetailRecommandView.swift b/ThimraTV/Class/Player/View/SPPlayerDetailRecommandView.swift index 14c1692..14dae58 100644 --- a/ThimraTV/Class/Player/View/SPPlayerDetailRecommandView.swift +++ b/ThimraTV/Class/Player/View/SPPlayerDetailRecommandView.swift @@ -28,6 +28,11 @@ class SPPlayerDetailRecommandView: HWPanModalContentView { } } + private lazy var bannerAd: SPBannerAd = { + let ad = SPBannerAd() + return ad + }() + //MARK: UI属性 private lazy var bgImageView: UIImageView = { let imageView = UIImageView(image: UIImage(named: "recommand_bg_image_01")) @@ -102,7 +107,11 @@ class SPPlayerDetailRecommandView: HWPanModalContentView { //MARK: HWPanModalPresentable override func longFormHeight() -> PanModalHeight { - return PanModalHeightMake(.content, 540 + kSPTabbarSafeBottomMargin) + if SPLoginManager.manager.userInfo?.user_level == .ad { + return PanModalHeightMake(.content, 540 + bannerAd.size.height + kSPTabbarSafeBottomMargin) + } else { + return PanModalHeightMake(.content, 540 + kSPTabbarSafeBottomMargin) + } } override func showDragIndicator() -> Bool { @@ -195,6 +204,17 @@ extension SPPlayerDetailRecommandView { make.top.equalTo(bannerView.snp.bottom).offset(81) make.height.equalTo(46) } + + if SPLoginManager.manager.userInfo?.user_level == .ad { + addSubview(bannerAd.view) + + bannerAd.view.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-kSPTabbarSafeBottomMargin) + } + } + + } } diff --git a/ThimraTV/Libs/AdManager/AppOpenAd/SPAppOpenAdManager.swift b/ThimraTV/Libs/AdManager/AppOpenAd/SPAppOpenAdManager.swift index 96643c1..57e7a9b 100644 --- a/ThimraTV/Libs/AdManager/AppOpenAd/SPAppOpenAdManager.swift +++ b/ThimraTV/Libs/AdManager/AppOpenAd/SPAppOpenAdManager.swift @@ -36,6 +36,15 @@ class SPAppOpenAdManager: NSObject { static let manager = SPAppOpenAdManager() + deinit { + NotificationCenter.default.removeObserver(self) + } + + override init() { + super.init() + NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) + } + private func loadAd() { // Do not load ad if there is an unused ad or one is already loading. if isLoadingAd || isAdAvailable() { diff --git a/ThimraTV/Libs/AdManager/BannerAd/SPBannerAd.swift b/ThimraTV/Libs/AdManager/BannerAd/SPBannerAd.swift new file mode 100644 index 0000000..cce665b --- /dev/null +++ b/ThimraTV/Libs/AdManager/BannerAd/SPBannerAd.swift @@ -0,0 +1,111 @@ +// +// SPBannerAd.swift +// ThimraTV +// +// Created by 长沙佳儿 on 2025/7/11. +// + +import UIKit +import GoogleMobileAds + + +@objc protocol SPBannerAdDelegate: NSObjectProtocol { + ///广告加载失败 + @objc optional func bannerAd(bannerAd: SPBannerAd, didLoadFail error: Error) + ///广告加载成功 + @objc optional func bannerAdDidLoadFinish(bannerAd: SPBannerAd) + ///广告被展示 + @objc optional func bannerAdDidShow(bannerAd: SPBannerAd) + ///广告被关闭 + @objc optional func bannerAdDidDismiss(bannerAd: SPBannerAd) +} + +class SPBannerAd: NSObject { + +#if DEBUG + let adUnitID = "ca-app-pub-3940256099942544/2435281174" +#endif + + let size = CGSize.init(width: kSPScreenWidth, height: 59) + + weak var delegate: SPBannerAdDelegate? + + private(set) lazy var view: BannerView = { + let view = BannerView() + view.adUnitID = self.adUnitID + view.adSize = inlineAdaptiveBanner(width: size.width, maxHeight:size.height) +// view.adSize = adSizeFor(cgSize: size) + view.delegate = self + return view + }() + + + deinit { + NotificationCenter.default.removeObserver(self) + } + + override init() { + super.init() + NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) + + view.load(Request()) + } + +} + +//MARK: -------------- BannerViewDelegate -------------- +extension SPBannerAd: BannerViewDelegate { + func bannerViewDidReceiveAd(_ bannerView: BannerView) { + self.delegate?.bannerAdDidLoadFinish?(bannerAd: self) + } + + func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) { + self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) + self.delegate?.bannerAd?(bannerAd: self, didLoadFail: error) + } + + func bannerViewDidRecordClick(_ bannerView: BannerView) { + print(#function) + self.requestStatAd(type: "click", errorMsg: nil) + } + + func bannerViewDidRecordImpression(_ bannerView: BannerView) { + print(#function) + } + + func bannerViewWillPresentScreen(_ bannerView: BannerView) { + self.requestStatAd(type: "start", errorMsg: nil) + self.delegate?.bannerAdDidShow?(bannerAd: self) + } + + func bannerViewWillDismissScreen(_ bannerView: BannerView) { + print(#function) + } + + func bannerViewDidDismissScreen(_ bannerView: BannerView) { + self.requestStatAd(type: "close", errorMsg: nil) + self.delegate?.bannerAdDidDismiss?(bannerAd: self) + } +} + +//MARK: -------------- 统计 -------------- +extension SPBannerAd { + + private func requestStatAd(type: String, errorMsg: String?) { + let model = SPStatAdModel() + model.type = type + model.ads_id = adUnitID + model.ad_platform_key = .google + model.error_msg = errorMsg + model.scene = .splash + + SPStatAPI.requestStatAd(model: model) + } + + + @objc private func didEnterBackgroundNotification() { + + self.requestStatAd(type: "Interrupt", errorMsg: nil) + } +} + diff --git a/ThimraTV/Libs/AdManager/SPStatAdModel.swift b/ThimraTV/Libs/AdManager/SPStatAdModel.swift index a889fb6..30a9232 100644 --- a/ThimraTV/Libs/AdManager/SPStatAdModel.swift +++ b/ThimraTV/Libs/AdManager/SPStatAdModel.swift @@ -15,6 +15,7 @@ class SPStatAdModel: SPModel, SmartCodable { case me = "me" case reward = "reward" case splash = "splash" + case banner = "banner" } var type: String? //start click error click show_failed load_failed Interrupt(退到后台) close