启屏广告

This commit is contained in:
zeng 2025-07-11 11:27:45 +08:00
parent 0232c818d8
commit 7736f5ed02
13 changed files with 192 additions and 37 deletions

View File

@ -281,6 +281,7 @@
1BF5130E2E1F5D9B009750EA /* SPRewardedAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF5130D2E1F5D8F009750EA /* SPRewardedAdManager.swift */; };
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 */; };
C3D1CE788CA03A1878493356 /* Pods_ThimraTV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B64805795B479324EB764157 /* Pods_ThimraTV.framework */; };
/* End PBXBuildFile section */
@ -593,6 +594,7 @@
1BF5130D2E1F5D8F009750EA /* SPRewardedAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPRewardedAdManager.swift; sourceTree = "<group>"; };
1BF513102E1FA138009750EA /* SPStatAdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPStatAdModel.swift; sourceTree = "<group>"; };
1BF513132E1FB8C1009750EA /* SPAppOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAppOpenAdManager.swift; sourceTree = "<group>"; };
1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAppOpenAdViewController.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
@ -833,6 +835,7 @@
isa = PBXGroup;
children = (
1BB91C142E04FD6A00A2C715 /* SPGuideViewController.swift */,
1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
@ -1984,6 +1987,7 @@
1BB91E062E04FD6A00A2C715 /* UIViewController+WMPageController.m in Sources */,
1BB91E072E04FD6A00A2C715 /* WMPageController.m in Sources */,
1BB91E082E04FD6A00A2C715 /* ZKCycleScrollView.swift in Sources */,
1BF513162E20ADB4009750EA /* SPAppOpenAdViewController.swift in Sources */,
1BB91E092E04FD6A00A2C715 /* ZKCycleScrollViewFlowLayout.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -54,6 +54,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if SPNetworkReachabilityManager.manager.isReachable == true {
// SPLoginManager.manager.requestVisitorLogin(completer: nil)
SPLoginManager.manager.updateUserInfo(completer: nil)
SPRewardedAdManager.manager.preloadRewardedAd()
}
}

View File

@ -110,22 +110,28 @@ extension SceneDelegate {
}
private func setRootVC() {
///
let hasOpenApp = UserDefaults.standard.object(forKey: kSPHasBeenOpenedAPPDefaultsKey) as? Bool
///
let guideVc = SPGuideViewController()
if hasOpenApp != true && guideVc.lanuchVC != nil {
SPAPPTool.isAppOpen = false
guideVc.openAppBlock = {
self.handleOpenApp()
guideVc.openAppBlock = { [weak self] in
self?.handleOpenApp()
}
window?.rootViewController = guideVc
window?.makeKeyAndVisible()
} else if !SPAPPTool.isAppOpen, hasOpenApp == true, SPNetworkReachabilityManager.manager.isReachable == true { //广
let openAdVC = SPAppOpenAdViewController()
openAdVC.didEndBlock = { [weak self] in
self?.handleOpenApp()
}
window?.rootViewController = openAdVC
window?.makeKeyAndVisible()
} else {
SPAPPTool.isAppOpen = true
setTabBarController()
handleOpenApp()
}
}
@ -139,6 +145,7 @@ extension SceneDelegate {
///app
@objc private func handleOpenApp() {
SPAPPTool.isAppOpen = true
setTabBarController()
retryHandleOpenAppMessage()

View File

@ -34,6 +34,8 @@ class SPTabBarController: UITabBarController {
SPAPPTool.requestIDFAAuthorization { idfa in
}
///广
SPRewardedAdManager.manager.preloadRewardedAd()
}

View File

@ -130,10 +130,12 @@ extension SPWebViewController: SPRewardedAdManagerDelegate {
func rewardedAdManager(manager: SPRewardedAdManager, didLoadFail error: any Error) {
self.needAutoRefresh = true
SPRewardedAdManager.manager.delegate = nil
}
func rewardedAdManager(manager: SPRewardedAdManager, didDisplayFail error: any Error) {
self.needAutoRefresh = true
SPRewardedAdManager.manager.delegate = nil
}
func rewardedAdManagerDidDismiss(manager: SPRewardedAdManager) {
@ -141,5 +143,6 @@ extension SPWebViewController: SPRewardedAdManagerDelegate {
let js = "uploadCheckSignIn()"
self.webView.evaluateJavaScript(js)
SPRewardedAdManager.manager.delegate = nil
}
}

View File

@ -0,0 +1,51 @@
//
// SPAppOpenAdViewController.swift
// ThimraTV
//
// Created by on 2025/7/11.
//
import UIKit
class SPAppOpenAdViewController: SPViewController {
var didEndBlock: (() -> Void)?
private(set) lazy var lanuchVC: UIViewController? = {
let vc = SPAPPTool.getLanuchViewController()
return vc
}()
override func viewDidLoad() {
super.viewDidLoad()
if let vc = lanuchVC {
addChild(vc)
view.addSubview(vc.view)
}
let manager = SPAppOpenAdManager.manager
manager.delegate = self
manager.showAdIfAvailable()
}
}
extension SPAppOpenAdViewController: SPAppOpenAdManagerDelegate {
///广
func appOpenAdManager(manager: SPAppOpenAdManager, didLoadFail error: Error) {
self.didEndBlock?()
}
///广
func appOpenAdManager(manager: SPAppOpenAdManager, didDisplayFail error: Error) {
self.didEndBlock?()
}
///广
func appOpenAdManagerDidDismiss(manager: SPAppOpenAdManager) {
self.didEndBlock?()
}
}

View File

@ -149,8 +149,9 @@ extension SPSettingsViewController {
SPMineItem(type: .clearCache, title: "movia_Clear_cache".localized, subtitle: SPAppCacheManager.cacheToString(cache: cache)),
SPMineItem(type: .aboutUs, title: "movia_profile_About_Us".localized),
]
arr.append(SPMineItem(type: .deleteAccount, title: "DeleteAccount".localized))
if SPLoginManager.manager.isLogin {
arr.append(SPMineItem(type: .deleteAccount, title: "DeleteAccount".localized))
arr.append(SPMineItem(type: .logout, title: "movia_signout".localized))
}

View File

@ -12,7 +12,7 @@ import AdSupport
class SPAPPTool: NSObject {
///app
static var isAppOpen = true
static var isAppOpen = false
static var appDelegate: AppDelegate?
static var sceneDelegate: SceneDelegate?

View File

@ -8,45 +8,78 @@
import UIKit
import GoogleMobileAds
@objc protocol SPAppOpenAdManagerDelegate: NSObjectProtocol {
///广
@objc optional func appOpenAdManager(manager: SPAppOpenAdManager, didLoadFail error: Error)
///广
@objc optional func appOpenAdManagerDidLoadFinish(manager: SPAppOpenAdManager)
///广
@objc optional func appOpenAdManager(manager: SPAppOpenAdManager, didDisplayFail error: Error)
///广
@objc optional func appOpenAdManagerDidShow(manager: SPAppOpenAdManager)
///广
@objc optional func appOpenAdManagerDidDismiss(manager: SPAppOpenAdManager)
}
class SPAppOpenAdManager: NSObject {
var appOpenAd: AppOpenAd?
var isLoadingAd = false
var isShowingAd = false
weak var delegate: SPAppOpenAdManagerDelegate?
static let shared = SPAppOpenAdManager()
#if DEBUG
let adUnitID = "ca-app-pub-3940256099942544/5575463023"
#endif
private func loadAd() async {
private var appOpenAd: AppOpenAd?
private(set) var isLoadingAd = false
private(set) var isShowingAd = false
private var isNeedShow = false
static let manager = SPAppOpenAdManager()
private func loadAd() {
// Do not load ad if there is an unused ad or one is already loading.
if isLoadingAd || isAdAvailable() {
return
}
isLoadingAd = true
do {
appOpenAd = try await AppOpenAd.load(with: "ca-app-pub-3940256099942544/5575463023", request: Request())
AppOpenAd.load(with: adUnitID, request: Request()) { [weak self] appOpenAd, error in
guard let self = self else { return }
self.isLoadingAd = false
appOpenAd?.fullScreenContentDelegate = self
} catch {
print("App open ad failed to load with error: \(error.localizedDescription)")
self.appOpenAd = appOpenAd
self.appOpenAd?.fullScreenContentDelegate = self
if appOpenAd != nil, self.isNeedShow {
self.showAdIfAvailable()
}
if let error = error {
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
self.delegate?.appOpenAdManager?(manager: self, didLoadFail: error)
} else {
self.delegate?.appOpenAdManagerDidLoadFinish?(manager: self)
}
}
isLoadingAd = false
}
func showAdIfAvailable() {
// If the app open ad is already showing, do not show the ad again.
guard !isShowingAd else { return }
self.isNeedShow = true
// If the app open ad is not available yet but is supposed to show, load
// a new ad.
if !isAdAvailable() {
Task {
await loadAd()
}
self.loadAd()
return
}
if let ad = appOpenAd {
self.isNeedShow = false
isShowingAd = true
ad.present(from: nil)
}
@ -60,24 +93,57 @@ class SPAppOpenAdManager: NSObject {
extension SPAppOpenAdManager: FullScreenContentDelegate {
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
self.requestStatAd(type: "start", errorMsg: nil)
print("App open ad will be presented.")
self.delegate?.appOpenAdManagerDidShow?(manager: self)
}
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
self.requestStatAd(type: "close", errorMsg: nil)
appOpenAd = nil
isShowingAd = false
// Reload an ad.
Task {
await loadAd()
}
// self.loadAd()
self.delegate?.appOpenAdManagerDidDismiss?(manager: self)
}
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
self.requestStatAd(type: "show_failed", errorMsg: nil)
appOpenAd = nil
isShowingAd = false
// Reload an ad.
Task {
await loadAd()
}
// self.loadAd()
self.delegate?.appOpenAdManager?(manager: self, didDisplayFail: error)
}
func adDidRecordClick(_ ad: any FullScreenPresentingAd) {
self.requestStatAd(type: "click", errorMsg: nil)
}
}
//MARK: -------------- --------------
extension SPAppOpenAdManager {
private func requestStatAd(type: String, errorMsg: String?) {
guard appOpenAd != nil else { return }
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)
}
}

View File

@ -65,7 +65,13 @@ extension SPRewardedAdManager {
func admob_loadRewardedAd(adInfo: SPAdInfo) {
guard !self.admob_isLoadingRewardedAd else { return }
#if DEBUG
adInfo.ads_id = "ca-app-pub-3940256099942544/1712485313"
#endif
let adUnitID = adInfo.ads_id ?? ""
let request = Request()
self.admob_isLoadingRewardedAd = true

View File

@ -59,6 +59,14 @@ class SPRewardedAdManager: NSObject {
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_rewardedAd != nil ? true : false
}
return false
}
///广
func loadAndShowRewardedAd(isShowLoading: Bool = true, isShowToast: Bool = true) {
guard isEnable else {
@ -105,13 +113,14 @@ class SPRewardedAdManager: NSObject {
}
}
}
}
///广
func preloadRewardedAd() {
guard isEnable else { return }
guard !isLoadingRewardedAd else { return }
guard self.adInfo == nil else { return }
isShowLoading = false
isShowToast = false
@ -151,6 +160,12 @@ class SPRewardedAdManager: NSObject {
}
}
private func clean() {
self.adInfo = nil
self.statScene = nil
self.videoInfo = nil
}
}
@ -179,9 +194,8 @@ extension SPRewardedAdManager {
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
}
self.statScene = nil
self.videoInfo = nil
self.isEnable = false
self.clean()
self.retryLoadAd()
}
@ -205,8 +219,7 @@ extension SPRewardedAdManager {
self.delegate?.rewardedAdManager?(manager: self, didDisplayFail: error)
self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
self.statScene = nil
self.videoInfo = nil
self.clean()
}
///广
@ -233,8 +246,7 @@ extension SPRewardedAdManager {
self.delegate?.rewardedAdManagerDidDismiss?(manager: self)
}
self.statScene = nil
self.videoInfo = nil
self.clean()
preloadRewardedAd()
}

View File

@ -33,8 +33,8 @@ class SPAdManager: NSObject {
// // Start loading ads
// }
#endif
//广
SPRewardedAdManager.manager.preloadRewardedAd()
// SPRewardedAdManager.manager.preloadRewardedAd()
}

View File

@ -14,6 +14,7 @@ class SPStatAdModel: SPModel, SmartCodable {
case detail = "detail"
case me = "me"
case reward = "reward"
case splash = "splash"
}
var type: String? //start click error click show_failed load_failed Interrupt(退) close