ThimraTV/ThimraTV/Libs/AdManager/RewardedAd/SPRewardedAdManager.swift
2025-07-16 17:06:13 +08:00

322 lines
9.5 KiB
Swift

//
// SPRewardedAdManager.swift
// ThimraTV
//
// Created by on 2025/7/10.
//
import UIKit
@objc protocol SPRewardedAdManagerDelegate: NSObjectProtocol {
///
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, userDidEarnReward adInfo: SPAdInfo)
///广
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, didLoadFail error: Error)
///广
@objc optional func rewardedAdManagerDidLoadFinish(manager: SPRewardedAdManager)
///广
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, didDisplayFail error: Error)
///广
@objc optional func rewardedAdManagerDidShow(manager: SPRewardedAdManager)
///广
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, didDismiss adInfo: SPAdInfo)
}
class SPRewardedAdManager: NSObject {
static let manager = SPRewardedAdManager()
weak var delegate: SPRewardedAdManagerDelegate?
private(set) var isLoadingRewardedAd = false
///
private var retryAttempt = 0.0
///
private var retryCount = 0
///
private let retryMaxCount = 1
///广
private(set) var isEnable = true
private(set) var adInfo: SPAdInfo?
private(set) var isShowLoading = false
private(set) var isShowToast = false
private var adsDate: Date?
///
var statScene: SPStatAdModel.AdScene?
var videoInfo: SPVideoInfoModel?
deinit {
NotificationCenter.default.removeObserver(self)
}
override init() {
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
func isAdAvailable() -> Bool {
guard let adInfo = adInfo else { return false }
if adInfo.platform_key == .google {
return admob_isReady()
} else if adInfo.platform_key == .applovin {
return appLovin_isReady()
}
return false
}
///广
func loadAndShowRewardedAd(isShowLoading: Bool = false, isShowToast: Bool = true) {
guard isEnable else {
let text = "movia_no_ads_tip".localized
if isShowToast {
self.showToast(text: text)
}
self.isShowToast = false
self.isShowLoading = false
let error = NSError(domain: text.localized, code: -1)
loadFailHandler(isStat: false, error: error)
return
}
self.isShowLoading = isShowLoading
self.isShowToast = isShowToast
if self.isShowLoading {
SPHUD.show()
}
guard !isLoadingRewardedAd else { return }
if !isAdAvailable() {
self.isLoadingRewardedAd = true
}
self.requestAdInfo { [weak self] adInfo in
guard let self = self else { return }
if adInfo.platform_key == .google {
self.admob_loadAndShowRewardedAd(adInfo: adInfo)
} else if adInfo.platform_key == .applovin {
self.appLovin_loadAndShowRewardedAd(adInfo: adInfo)
} else {
self.isLoadingRewardedAd = false
self.adInfo = nil
}
}
}
///广
func preloadRewardedAd() {
guard isEnable else { return }
guard !isLoadingRewardedAd else { return }
isShowLoading = false
isShowToast = false
self.isLoadingRewardedAd = true
self.requestAdInfo { [weak self] adInfo in
guard let self = self else { return }
if adInfo.platform_key == .google {
self.admob_loadRewardedAd(adInfo: adInfo)
} else if adInfo.platform_key == .applovin {
self.appLovin_loadRewardedAd(adInfo: adInfo)
} else {
self.isLoadingRewardedAd = false
self.adInfo = nil
}
}
}
///广
private func retryLoadAd() {
guard isEnable else { return }
guard retryCount < retryMaxCount else {
retryCount = 0
retryAttempt = 0
return
}
retryCount += 1
retryAttempt += 1
let delaySec = pow(2.0, min(6.0, retryAttempt))
DispatchQueue.main.asyncAfter(deadline: .now() + delaySec) { [weak self] in
self?.preloadRewardedAd()
}
}
private func clean() {
self.statScene = nil
self.videoInfo = nil
}
}
//MARK: -------------- 广() --------------
extension SPRewardedAdManager {
///
func userDidEarnRewardHandler() {
guard let adInfo = adInfo else { return }
self.delegate?.rewardedAdManager?(manager: self, userDidEarnReward: adInfo)
self.requestStatAd(type: "reward", errorMsg: nil)
}
///广
func loadFailHandler(isStat: Bool = true, error: Error) {
if isShowLoading {
SPHUD.dismiss()
}
if isShowToast {
self.showToast()
}
self.isLoadingRewardedAd = false
self.delegate?.rewardedAdManager?(manager: self, didLoadFail: error)
if isStat {
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
}
self.clean()
if self.adInfo?.platform_key != .google {//广
self.isLoadingRewardedAd = true
let adInfo = SPAdInfo()
adInfo.platform_key = .google
adInfo.ads_id = SPAdManager.manager.admob_rewardedAdUnitID
self.adInfo = adInfo
self.admob_loadRewardedAd(adInfo: adInfo)
} else {
self.isEnable = false
self.retryLoadAd()
}
}
///广
func loadFinishHandler() {
self.retryAttempt = 0
self.retryCount = 0
self.isLoadingRewardedAd = false
self.delegate?.rewardedAdManagerDidLoadFinish?(manager: self)
}
///广
func displayFailHandler(error: Error) {
if isShowLoading {
SPHUD.dismiss()
}
if isShowToast {
self.showToast()
}
self.delegate?.rewardedAdManager?(manager: self, didDisplayFail: error)
self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
self.clean()
}
///广
func didShowHandler() {
self.adsDate = Date()
if isShowLoading {
SPHUD.dismiss()
}
self.delegate?.rewardedAdManagerDidShow?(manager: self)
self.requestStatAd(type: "start", errorMsg: nil)
}
///广
func didDismissHandler() {
let adInfo = self.adInfo
var seconds = 0
if let adsDate = self.adsDate {
seconds = Int(Date().timeIntervalSince(adsDate))
}
self.requestStatAd(type: "close", seconds: seconds, errorMsg: nil) { [weak self] in
guard let self = self else { return }
if let adInfo = adInfo {
self.delegate?.rewardedAdManager?(manager: self, didDismiss: adInfo)
}
}
self.clean()
self.preloadRewardedAd()
}
///广
func didClickHandler() {
var seconds = 0
if let adsDate = self.adsDate {
seconds = Int(Date().timeIntervalSince(adsDate))
}
self.requestStatAd(type: "click", seconds: seconds, errorMsg: nil)
}
}
extension SPRewardedAdManager {
private func requestStatAd(type: String, seconds: Int = 0, errorMsg: String?, completer: (() -> Void)? = nil) {
guard let adInfo = adInfo else { return }
let model = SPStatAdModel()
model.type = type
model.ads_id = adInfo.ads_id
model.view_seconds = seconds
model.ad_platform_key = adInfo.platform_key
model.error_msg = errorMsg
model.scene = self.statScene
model.short_play_id = self.videoInfo?.short_play_id
model.short_play_video_id = self.videoInfo?.short_play_video_id
SPStatAPI.requestStatAd(model: model, completer: completer)
}
@objc private func didEnterBackgroundNotification() {
if self.statScene == nil { return }
self.requestStatAd(type: "Interrupt", seconds: 0, errorMsg: nil)
}
func showToast(text: String? = "movia_no_ads_tip".localized) {
SPToast.show(text: text)
}
private func requestAdInfo(completer: ((_ adInfo: SPAdInfo) -> Void)?) {
if let adInfo = self.adInfo {
completer?(adInfo)
return
}
SPAdAPI.requestShowAdInfo { [weak self] adInfo in
guard let self = self else { return }
if let adInfo = adInfo {
self.adInfo = adInfo
} else {
self.adInfo = SPAdInfo()
self.adInfo?.platform_key = .google
self.adInfo?.ads_id = SPAdManager.manager.admob_rewardedAdUnitID
}
completer?(self.adInfo!)
}
}
}