From 7932c20c65ac56a7737cd5b4451ceed5a2701786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E7=A7=A6=E4=B9=9D?= Date: Sat, 24 Jan 2026 09:05:25 +0800 Subject: [PATCH 1/3] 1 --- Fableon.xcodeproj/project.pbxproj | 58 +++++ Fableon/App/AppDelegate+FAConfig.swift | 1 + Fableon/App/SceneDelegate.swift | 2 + .../Object/Libs/AdManager/FAAdManager.swift | 62 +++++ .../Libs/AdManager/Open/FAOpenAdManager.swift | 221 ++++++++++++++++++ .../AdManager/Open/FATradPlusOpenAd.swift | 104 +++++++++ Fableon/Source/Info.plist | 206 ++++++++++++++++ Podfile | 45 +++- Podfile.lock | 175 +++++++++++++- 9 files changed, 865 insertions(+), 9 deletions(-) create mode 100644 Fableon/Object/Libs/AdManager/FAAdManager.swift create mode 100644 Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift create mode 100644 Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift diff --git a/Fableon.xcodeproj/project.pbxproj b/Fableon.xcodeproj/project.pbxproj index a8babdc..754806a 100644 --- a/Fableon.xcodeproj/project.pbxproj +++ b/Fableon.xcodeproj/project.pbxproj @@ -41,6 +41,9 @@ 031FDEEC2EB35DF600F4CAC7 /* FACoinsPackAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEEB2EB35DF600F4CAC7 /* FACoinsPackAlert.swift */; }; 031FDEEE2EB3682000F4CAC7 /* FAVipRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEED2EB3682000F4CAC7 /* FAVipRetainAlert.swift */; }; 035589332F161E6E00FAEF4A /* FAPayRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589322F161E6E00FAEF4A /* FAPayRetainAlert.swift */; }; + 035589362F2305D800FAEF4A /* FAAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589352F2305D800FAEF4A /* FAAdManager.swift */; }; + 0355893A2F234B3E00FAEF4A /* FAOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589392F234B3E00FAEF4A /* FAOpenAdManager.swift */; }; + 0355893C2F234C8300FAEF4A /* FATradPlusOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355893B2F234C8300FAEF4A /* FATradPlusOpenAd.swift */; }; 039CE6042EAA2621007B5EED /* AppDelegate+FAAdjust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */; }; 039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */; }; 039CE60B2EAA31CB007B5EED /* FAStatAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */; }; @@ -416,6 +419,9 @@ 031FDEEB2EB35DF600F4CAC7 /* FACoinsPackAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackAlert.swift; sourceTree = ""; }; 031FDEED2EB3682000F4CAC7 /* FAVipRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAVipRetainAlert.swift; sourceTree = ""; }; 035589322F161E6E00FAEF4A /* FAPayRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPayRetainAlert.swift; sourceTree = ""; }; + 035589352F2305D800FAEF4A /* FAAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAdManager.swift; sourceTree = ""; }; + 035589392F234B3E00FAEF4A /* FAOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOpenAdManager.swift; sourceTree = ""; }; + 0355893B2F234C8300FAEF4A /* FATradPlusOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusOpenAd.swift; sourceTree = ""; }; 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAAdjust.swift"; sourceTree = ""; }; 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAdjustStateManager.swift; sourceTree = ""; }; 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStatAPI.swift; sourceTree = ""; }; @@ -777,6 +783,32 @@ path = Alert; sourceTree = ""; }; + 035589342F2304B800FAEF4A /* AdManager */ = { + isa = PBXGroup; + children = ( + 035589382F2319EB00FAEF4A /* Open */, + 035589372F2319DD00FAEF4A /* Rewarded */, + 035589352F2305D800FAEF4A /* FAAdManager.swift */, + ); + path = AdManager; + sourceTree = ""; + }; + 035589372F2319DD00FAEF4A /* Rewarded */ = { + isa = PBXGroup; + children = ( + ); + path = Rewarded; + sourceTree = ""; + }; + 035589382F2319EB00FAEF4A /* Open */ = { + isa = PBXGroup; + children = ( + 035589392F234B3E00FAEF4A /* FAOpenAdManager.swift */, + 0355893B2F234C8300FAEF4A /* FATradPlusOpenAd.swift */, + ); + path = Open; + sourceTree = ""; + }; 039CE6072EAA2F37007B5EED /* AdjustStateManager */ = { isa = PBXGroup; children = ( @@ -1302,6 +1334,7 @@ 03E23A962EAA1A65004A8CEC /* Libs */ = { isa = PBXGroup; children = ( + 035589342F2304B800FAEF4A /* AdManager */, 03E9A78E2EC1AFEA000D1067 /* ActivityManager */, 031FDEE22EB3487700F4CAC7 /* Alert */, 039CE6122EAB0DE1007B5EED /* FAIap */, @@ -1959,6 +1992,7 @@ F3T938414J234X46539JR019 /* Resources */, 4809W21R638Z15866LWB2041 /* [CP] Embed Pods Frameworks */, 03E9A7632EC19101000D1067 /* Embed Foundation Extensions */, + 7A6DD8DBCA1DA3FCAC271812 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -2099,6 +2133,27 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + 7A6DD8DBCA1DA3FCAC271812 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Fableon/Pods-Fableon-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9E12479709584PQ64999OJ92 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2164,6 +2219,7 @@ 031FDEB62EB0B77F00F4CAC7 /* FACoinPackConfirmItemView.swift in Sources */, F35S8138Z362EG3435ME1455 /* CSGleeView.swift in Sources */, 031FDEB42EB0AD7D00F4CAC7 /* FACoinPackConfirmView.swift in Sources */, + 035589362F2305D800FAEF4A /* FAAdManager.swift in Sources */, F31451S3X15B941342J922Q3 /* TConfigCell.swift in Sources */, F3670DZ2KI89TBO3L9L36P57 /* XLoginView.swift in Sources */, F3V24670CK2EGR4595CDQ261 /* AWUModalMageCell.swift in Sources */, @@ -2173,6 +2229,7 @@ 031FDEE12EB344AB00F4CAC7 /* FALogin+Facebook.swift in Sources */, F30E153206675C3SJ3974VL1 /* OJQUnechoSectionView.swift in Sources */, F381909BQ5JWXYI119A49469 /* DREychainCell.swift in Sources */, + 0355893A2F234B3E00FAEF4A /* FAOpenAdManager.swift in Sources */, F39R66F983517825QO331145 /* QCenterEfineView.swift in Sources */, F3II3AF834346F516W51V693 /* GAMainRecommendedView.swift in Sources */, 031FDEAE2EB093B100F4CAC7 /* FABuyRecordsModel.swift in Sources */, @@ -2388,6 +2445,7 @@ 03E239972EAA1A29004A8CEC /* FANetworkManager.swift in Sources */, 03E239982EAA1A29004A8CEC /* UIScrollView+FARefresh.swift in Sources */, 03E239992EAA1A29004A8CEC /* FANavigationController.swift in Sources */, + 0355893C2F234C8300FAEF4A /* FATradPlusOpenAd.swift in Sources */, 03E2399A2EAA1A29004A8CEC /* FAViewController.swift in Sources */, 03E2399B2EAA1A29004A8CEC /* FAWebMessageModel.swift in Sources */, 03E2399C2EAA1A29004A8CEC /* FAGradientButton.swift in Sources */, diff --git a/Fableon/App/AppDelegate+FAConfig.swift b/Fableon/App/AppDelegate+FAConfig.swift index bbcf3a2..e6132bb 100644 --- a/Fableon/App/AppDelegate+FAConfig.swift +++ b/Fableon/App/AppDelegate+FAConfig.swift @@ -36,6 +36,7 @@ extension AppDelegate { func fa_registThirdparty(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions) + FAAdManager.initSdk() } } diff --git a/Fableon/App/SceneDelegate.swift b/Fableon/App/SceneDelegate.swift index 70886c2..c546579 100644 --- a/Fableon/App/SceneDelegate.swift +++ b/Fableon/App/SceneDelegate.swift @@ -25,6 +25,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { FATool.windowScene = windowScene window = UIWindow(windowScene: windowScene) + window?.makeKeyAndVisible() startApp() onLineTimer = Timer.scheduledTimer(timeInterval: 60 * 10, target: YYTextWeakProxy(target: self), selector: #selector(handleOnLine), userInfo: nil, repeats: true) @@ -38,6 +39,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { requestFirebase() requestApns() + FAOpenAdManager.manager.showAdIfAvailable() } func sceneDidDisconnect(_ scene: UIScene) { diff --git a/Fableon/Object/Libs/AdManager/FAAdManager.swift b/Fableon/Object/Libs/AdManager/FAAdManager.swift new file mode 100644 index 0000000..508fe25 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/FAAdManager.swift @@ -0,0 +1,62 @@ +// +// FAAdManager.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/23. +// + +import UIKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + + +class FAAdManager: NSObject { + + static func initSdk() { +#if canImport(TradPlusAds) +#if DEBUG + TradPlus.setLogLevel(MSLogLevelAll) +#endif + TradPlus.initSDK("8C768B1A89BA057E47D752181A7BDA21") { error in + if let error = error { + debugLog(error) + } else { + debugLog("TradPlus 初始化成功") + } + } +#endif + + } + +} + + +enum FAAdPlatform { + case tradPlus + + ///激励广告单元Id + var rewardedUnitId: String { + switch self { + case .tradPlus: + return "E35A9B622C1125CB6EDFC288F22CDB22" + } + } + + ///开屏广告单元Id + var openUnitId: String { + switch self { + case .tradPlus: + return "67B5E393DF8D80325B0CC1055B5A2122" + } + } + + ///横幅广告单元Id + var bannerUnitId: String { + switch self { + case .tradPlus: + return "E92BEE12E188BCD15834075F5A32A922" + } + } + +} diff --git a/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift b/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift new file mode 100644 index 0000000..b3916a0 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift @@ -0,0 +1,221 @@ +// +// FAOpenAdManager.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/23. +// + +import UIKit + +@objc protocol FAOpenAdManagerDelegate: NSObjectProtocol { + /// 广告加载失败 + @objc optional func fa_openAdManager(manager: FAOpenAdManager, didLoadFail error: Error) + /// 广告加载成功 + @objc optional func fa_openAdManagerDidLoadFinish(manager: FAOpenAdManager) + /// 广告展示失败 + @objc optional func fa_openAdManager(manager: FAOpenAdManager, didDisplayFail error: Error) + /// 广告被展示 + @objc optional func fa_openAdManagerDidShow(manager: FAOpenAdManager) + /// 广告被关闭 + @objc optional func fa_openAdManagerDidDismiss(manager: FAOpenAdManager) + /// 其它错误 + @objc optional func fa_openAdManager(manager: FAOpenAdManager, didOtherFail error: Error) +} + +protocol FAOpenAdDelegate: NSObjectProtocol { + func fa_openAd(ad: FAOpenAd, didLoadFail error: Error) + func fa_openAdDidLoadFinish(ad: FAOpenAd) + func fa_openAd(ad: FAOpenAd, didDisplayFail error: Error) + func fa_openAdDidShow(ad: FAOpenAd) + func fa_openAdDidDismiss(ad: FAOpenAd) + func fa_openAdDidClick(ad: FAOpenAd) +} + +protocol FAOpenAd: NSObjectProtocol { + var delegate: FAOpenAdDelegate? { get set } + var adPlatform: FAAdPlatform { get } + var adUnitID: String { get } + var isReady: Bool { get } + + func loadAd() + func showAd() +} + +class FAOpenAdManager: NSObject { + + static let manager = FAOpenAdManager() + + weak var delegate: FAOpenAdManagerDelegate? + + private var appOpenAd: FAOpenAd? { + didSet { + oldValue?.delegate = nil + appOpenAd?.delegate = self + } + } + + private(set) var isLoadingAd = false + private(set) var isShowingAd = false + /// 标记是否在等待广告加载完成后自动展示 + private var isWaitingToShow = false + private var timeOutTimer: Timer? + + deinit { + NotificationCenter.default.removeObserver(self) + } + + private override init() { + super.init() + NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActiveNotification), name: UIApplication.didBecomeActiveNotification, object: nil) + } + + func loadAd() { + if isLoadingAd || isAdAvailable() { + return + } + isLoadingAd = true + + appOpenAd = FATradPlusOpenAd() + appOpenAd?.loadAd() + } + + func showAd() { + guard let ad = appOpenAd, isAdAvailable() else { + loadAd() + return + } + + isWaitingToShow = false + isShowingAd = true + ad.showAd() + } + + /// 外部调用的主要入口 + func showAdIfAvailable() { + // 如果正在展示广告,不再重复触发 + guard !isShowingAd else { return } + + // 1. 如果广告已就绪,直接展示 + if isAdAvailable() { + showAd() + return + } + + // 2. 如果没有就绪,标记等待并开始加载,同时开启超时保护 + isWaitingToShow = true + startTimeoutTimer() + loadAd() + } + + private func isAdAvailable() -> Bool { + return appOpenAd?.isReady ?? false + } + + // MARK: - Timer (防止加载时间过长,用户已进入首页后突然弹出广告) + private func startTimeoutTimer() { + clearTimer() +// timeOutTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] _ in +// Task { @MainActor in +// self?.handleTimeOut() +// } +// } + } + + @objc private func handleTimeOut() { + if isWaitingToShow { + isWaitingToShow = false + let error = NSError(domain: "time-out", code: -1) + delegate?.fa_openAdManager?(manager: self, didOtherFail: error) + } + clearTimer() + } + + private func clearTimer() { + timeOutTimer?.invalidate() + timeOutTimer = nil + } + + + +} + +// MARK: - BRAppOpenAdDelegate +extension FAOpenAdManager: FAOpenAdDelegate { + + func fa_openAd(ad: FAOpenAd, didLoadFail error: Error) { + isLoadingAd = false + isWaitingToShow = false + appOpenAd = nil + clearTimer() + requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) + delegate?.fa_openAdManager?(manager: self, didLoadFail: error) + delegate = nil + } + + func fa_openAdDidLoadFinish(ad: FAOpenAd) { + isLoadingAd = false + delegate?.fa_openAdManagerDidLoadFinish?(manager: self) + + // 如果之前处于等待展示状态,现在立即展示 + if isWaitingToShow { + clearTimer() + showAd() + } + } + + func fa_openAd(ad: FAOpenAd, didDisplayFail error: Error) { + isShowingAd = false + isWaitingToShow = false + appOpenAd = nil + clearTimer() + requestStatAd(type: "show_failed", errorMsg: error.localizedDescription) + delegate?.fa_openAdManager?(manager: self, didDisplayFail: error) + delegate = nil + } + + func fa_openAdDidShow(ad: FAOpenAd) { + requestStatAd(type: "start", errorMsg: nil) + delegate?.fa_openAdManagerDidShow?(manager: self) + } + + func fa_openAdDidDismiss(ad: FAOpenAd) { + isShowingAd = false + appOpenAd = nil + delegate?.fa_openAdManagerDidDismiss?(manager: self) + // 关闭后自动预加载下一条,提高下次展示成功率 + loadAd() + delegate = nil + } + + func fa_openAdDidClick(ad: FAOpenAd) { + requestStatAd(type: "click", errorMsg: nil) + } +} + +// MARK: - Statistics +extension FAOpenAdManager { + private func requestStatAd(type: String, errorMsg: String?) { + guard let appOpenAd = appOpenAd else { return } + + // let model = SPStatAdModel() + // model.type = type + // model.ads_id = appOpenAd.adUnitID + // model.ad_platform_key = SPAdPlatformKey(rawValue: appOpenAd.adPlatformKey) + // model.error_msg = errorMsg + // model.scene = .splash + // + // SPStatAPI.requestStatAd(model: model) + } + + + @objc private func didEnterBackgroundNotification() { + if !self.isShowingAd { return } + + self.requestStatAd(type: "Interrupt", errorMsg: nil) + } + + @objc private func didBecomeActiveNotification() { + showAdIfAvailable() + } +} diff --git a/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift b/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift new file mode 100644 index 0000000..0ad9fe6 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift @@ -0,0 +1,104 @@ +// +// BRTradPlusOpenAd.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/23. +// + +import UIKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + +class FATradPlusOpenAd: NSObject, FAOpenAd { + +#if canImport(TradPlusAds) + private var appOpenAd: TradPlusAdSplash? +#endif + + weak var delegate: FAOpenAdDelegate? + + var adPlatform: FAAdPlatform { + return .tradPlus + } + + var adUnitID: String { + return self.adPlatform.openUnitId + } + + var isReady: Bool { +#if canImport(TradPlusAds) + return self.appOpenAd?.isAdReady ?? false +#else + return false +#endif + } + + func loadAd() { + appOpenAd = nil + + guard let targetWindow = FATool.keyWindow else { + let error = NSError(domain: "com.beereel.ad", + code: -2, + userInfo: [NSLocalizedDescriptionKey: "TradPlus failed: No active window found"]) + self.delegate?.fa_openAd(ad: self, didLoadFail: error) + return + } +#if canImport(TradPlusAds) + // 3. 初始化并配置 + let splash = TradPlusAdSplash() + splash.setAdUnitID(adUnitID) + splash.delegate = self + self.appOpenAd = splash + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + splash.loadAd(with: targetWindow, bottomView: nil) + } +#endif + } + + func showAd() { + if isReady { +#if canImport(TradPlusAds) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in + guard let self = self else { return } + self.appOpenAd?.show() + } +#endif + } + } + +} + +#if canImport(TradPlusAds) +// MARK: - TradPlusADSplashDelegate +extension FATradPlusOpenAd: TradPlusADSplashDelegate { + + func tpSplashAdLoaded(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_openAdDidLoadFinish(ad: self) + } + + func tpSplashAdLoadFailWithError(_ error: Error, adInfo: [AnyHashable : Any]) { + self.appOpenAd = nil + self.delegate?.fa_openAd(ad: self, didLoadFail: error) + } + + func tpSplashAdImpression(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_openAdDidShow(ad: self) + } + + func tpSplashAdShow(_ adInfo: [AnyHashable : Any], didFailWithError error: Error) { + self.appOpenAd = nil + self.delegate?.fa_openAd(ad: self, didDisplayFail: error) + } + + func tpSplashAdClicked(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_openAdDidClick(ad: self) + } + + func tpSplashAdDismissed(_ adInfo: [AnyHashable : Any]) { + self.appOpenAd = nil + self.delegate?.fa_openAdDidDismiss(ad: self) + } +} +#endif diff --git a/Fableon/Source/Info.plist b/Fableon/Source/Info.plist index 0fa6392..8a73d4a 100755 --- a/Fableon/Source/Info.plist +++ b/Fableon/Source/Info.plist @@ -2,6 +2,8 @@ + GADApplicationIdentifier + ca-app-pub-3940256099942544~1458002511 CFBundleURLTypes @@ -21,6 +23,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + FacebookAppID 1309643747870828 FacebookClientToken @@ -53,5 +60,204 @@ UIDesignRequiresCompatibility + SKAdNetworkItems + + + SKAdNetworkIdentifier + cstr6suwn9.skadnetwork + + + SKAdNetworkIdentifier + 4fzdc2evr5.skadnetwork + + + SKAdNetworkIdentifier + 2fnua5tdw4.skadnetwork + + + SKAdNetworkIdentifier + ydx93a7ass.skadnetwork + + + SKAdNetworkIdentifier + p78axxw29g.skadnetwork + + + SKAdNetworkIdentifier + v72qych5uu.skadnetwork + + + SKAdNetworkIdentifier + ludvb6z3bs.skadnetwork + + + SKAdNetworkIdentifier + cp8zw746q7.skadnetwork + + + SKAdNetworkIdentifier + 3sh42y64q3.skadnetwork + + + SKAdNetworkIdentifier + c6k4g5qg8m.skadnetwork + + + SKAdNetworkIdentifier + s39g8k73mm.skadnetwork + + + SKAdNetworkIdentifier + 3qy4746246.skadnetwork + + + SKAdNetworkIdentifier + f38h382jlk.skadnetwork + + + SKAdNetworkIdentifier + hs6bdukanm.skadnetwork + + + SKAdNetworkIdentifier + mlmmfzh3r3.skadnetwork + + + SKAdNetworkIdentifier + v4nxqhlyqp.skadnetwork + + + SKAdNetworkIdentifier + wzmmz9fp6w.skadnetwork + + + SKAdNetworkIdentifier + su67r6k2v3.skadnetwork + + + SKAdNetworkIdentifier + yclnxrl5pm.skadnetwork + + + SKAdNetworkIdentifier + t38b2kh725.skadnetwork + + + SKAdNetworkIdentifier + 7ug5zh24hu.skadnetwork + + + SKAdNetworkIdentifier + gta9lk7p23.skadnetwork + + + SKAdNetworkIdentifier + vutu7akeur.skadnetwork + + + SKAdNetworkIdentifier + y5ghdn5j9k.skadnetwork + + + SKAdNetworkIdentifier + v9wttpbfk9.skadnetwork + + + SKAdNetworkIdentifier + n38lu8286q.skadnetwork + + + SKAdNetworkIdentifier + 47vhws6wlr.skadnetwork + + + SKAdNetworkIdentifier + kbd757ywx3.skadnetwork + + + SKAdNetworkIdentifier + 9t245vhmpl.skadnetwork + + + SKAdNetworkIdentifier + a2p9lx4jpn.skadnetwork + + + SKAdNetworkIdentifier + 22mmun2rn5.skadnetwork + + + SKAdNetworkIdentifier + 44jx6755aq.skadnetwork + + + SKAdNetworkIdentifier + k674qkevps.skadnetwork + + + SKAdNetworkIdentifier + 4468km3ulz.skadnetwork + + + SKAdNetworkIdentifier + 2u9pt9hc89.skadnetwork + + + SKAdNetworkIdentifier + 8s468mfl3y.skadnetwork + + + SKAdNetworkIdentifier + klf5c3l5u5.skadnetwork + + + SKAdNetworkIdentifier + ppxm28t8ap.skadnetwork + + + SKAdNetworkIdentifier + kbmxgpxpgc.skadnetwork + + + SKAdNetworkIdentifier + uw77j35x4d.skadnetwork + + + SKAdNetworkIdentifier + 578prtvx9j.skadnetwork + + + SKAdNetworkIdentifier + 4dzt52r2t5.skadnetwork + + + SKAdNetworkIdentifier + tl55sbb4fm.skadnetwork + + + SKAdNetworkIdentifier + c3frkrj4fj.skadnetwork + + + SKAdNetworkIdentifier + e5fvkxwrpn.skadnetwork + + + SKAdNetworkIdentifier + 8c4e2ghe7u.skadnetwork + + + SKAdNetworkIdentifier + 3rd42ekr43.skadnetwork + + + SKAdNetworkIdentifier + 97r2b46745.skadnetwork + + + SKAdNetworkIdentifier + 3qcr597p9d.skadnetwork + + diff --git a/Podfile b/Podfile index d7c6b9e..1daaf0e 100755 --- a/Podfile +++ b/Podfile @@ -1,16 +1,16 @@ -platform :ios, '13.0' +platform :ios, '15.0' source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git' post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" - config.build_settings['EXCLUDED_ARCHITECTURES'] = 'i386' - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' - end - end + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' + config.build_settings.delete('EXCLUDED_ARCHS[sdk=iphonesimulator*]') + config.build_settings.delete('EXCLUDED_ARCHITECTURES') + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end end target 'Fableon' do @@ -36,5 +36,34 @@ target 'Fableon' do pod 'JXPagingView/Paging' pod 'JXSegmentedView' pod 'Adjust' + +# 广告SDK AdMob Meta Pangle Liftoff Mintegral InMobi Verve Bigo TaurusX UnityAds AppLovin IronSource + pod 'TradPlusAdSDK', '14.9.0' + pod 'TradPlusAdSDK/FacebookAdapter', '14.9.0' + pod 'FBAudienceNetwork','6.20.1' + pod 'TradPlusAdSDK/AdMobAdapter', '14.9.0' + pod 'Google-Mobile-Ads-SDK','12.14.0' + pod 'TradPlusAdSDK/UnityAdapter', '14.9.0' + pod 'UnityAds','4.16.4' + pod 'TradPlusAdSDK/AppLovinAdapter', '14.9.0' + pod 'AppLovinSDK','13.5.0' + pod 'TradPlusAdSDK/VungleAdapter', '14.9.0' + pod 'VungleAds', '7.6.1' + pod 'TradPlusAdSDK/IronSourceAdapter', '14.9.0' + pod 'IronSourceSDK','9.2.0' + pod 'TradPlusAdSDK/InMobiAdapter', '14.9.0' + pod 'InMobiSDK' ,'11.1.0' + pod 'TradPlusAdSDK/MintegralAdapter', '14.9.0' + pod 'MintegralAdSDK' ,'7.7.9' + pod 'MintegralAdSDK/All','7.7.9' + pod 'TradPlusAdSDK/PangleAdapter', '14.9.0' + pod 'Ads-Global', '7.8.0.5' + pod 'TradPlusAdSDK/TPCrossAdapter', '14.9.0' + pod 'TradPlusAdSDK/VerveAdapter', '14.9.0' + pod 'HyBid','3.7.1' + pod 'TradPlusAdSDK/BigoAdapter', '14.9.0' + pod 'BigoADS','5.0.0' + pod 'TradPlusAdSDK/TaurusXAdapter', '14.9.0' + pod 'TaurusxAdsSDK','1.12.0' end diff --git a/Podfile.lock b/Podfile.lock index f382bfd..014c05d 100755 --- a/Podfile.lock +++ b/Podfile.lock @@ -4,13 +4,47 @@ PODS: - Adjust/Adjust (5.4.5): - AdjustSignature (= 3.47.0) - AdjustSignature (3.47.0) + - Ads-Global (7.8.0.5): + - Ads-Global/BUAdSDK (= 7.8.0.5) + - Ads-Global/BUAdSDK (7.8.0.5): + - Ads-Global/PangleSDK + - Ads-Global/TikTokBusinessSDK + - Ads-Global/PangleSDK (7.8.0.5) + - Ads-Global/TikTokBusinessSDK (7.8.0.5) - Alamofire (5.10.2) + - AppLovinSDK (13.5.0) + - ATOM-Standalone (3.8.0) + - BigoADS (5.0.0) - collection-view-layouts/Core (0.2.2) - collection-view-layouts/TagsLayout (0.2.2): - collection-view-layouts/Core + - FBAudienceNetwork (6.20.1) - FDFullscreenPopGesture (1.1) - FSPagerView (0.8.3) + - Google-Mobile-Ads-SDK (12.14.0): + - GoogleUserMessagingPlatform (>= 1.1) + - GoogleUserMessagingPlatform (3.1.0) - HWPanModal (0.9.9) + - HyBid (3.7.1): + - HyBid/ATOM (= 3.7.1) + - HyBid/Banner (= 3.7.1) + - HyBid/Core (= 3.7.1) + - HyBid/FullScreen (= 3.7.1) + - HyBid/Native (= 3.7.1) + - HyBid/RewardedVideo (= 3.7.1) + - HyBid/ATOM (3.7.1): + - ATOM-Standalone + - HyBid/Core + - HyBid/Banner (3.7.1): + - HyBid/Core + - HyBid/Core (3.7.1) + - HyBid/FullScreen (3.7.1): + - HyBid/Core + - HyBid/Native (3.7.1): + - HyBid/Core + - HyBid/RewardedVideo (3.7.1): + - HyBid/Core + - InMobiSDK (11.1.0) - IQKeyboardCore (1.0.8) - IQKeyboardManagerSwift (8.0.1): - IQKeyboardManagerSwift/Appearance (= 8.0.1) @@ -49,6 +83,13 @@ PODS: - IQKeyboardCore - IQTextView (1.0.5): - IQKeyboardToolbar/Placeholderable + - IronSourceAdQualitySDK (9.1.1) + - IronSourceSDK (9.2.0.0): + - IronSourceSDK/AdQuality (= 9.2.0.0) + - IronSourceSDK/Ads (= 9.2.0.0) + - IronSourceSDK/AdQuality (9.2.0.0): + - IronSourceAdQualitySDK (~> 9.1.1) + - IronSourceSDK/Ads (9.2.0.0) - JXPagingView/Paging (2.1.3) - JXPlayer (0.2.0): - SJMediaCacheServer (= 2.1.6) @@ -57,6 +98,54 @@ PODS: - Kingfisher (8.5.0) - LYEmptyView (1.3.1) - Masonry (1.1.0) + - MintegralAdSDK (7.7.9): + - MintegralAdSDK/BannerAd (= 7.7.9) + - MintegralAdSDK/BidBannerAd (= 7.7.9) + - MintegralAdSDK/BidInterstitialVideoAd (= 7.7.9) + - MintegralAdSDK/BidNativeAd (= 7.7.9) + - MintegralAdSDK/BidNewInterstitialAd (= 7.7.9) + - MintegralAdSDK/BidRewardVideoAd (= 7.7.9) + - MintegralAdSDK/InterstitialVideoAd (= 7.7.9) + - MintegralAdSDK/NativeAd (= 7.7.9) + - MintegralAdSDK/NewInterstitialAd (= 7.7.9) + - MintegralAdSDK/RewardVideoAd (= 7.7.9) + - MintegralAdSDK/All (7.7.9): + - MintegralAdSDK/BannerAd + - MintegralAdSDK/BidNativeAd + - MintegralAdSDK/InterstitialVideoAd + - MintegralAdSDK/NativeAd + - MintegralAdSDK/NativeAdvancedAd + - MintegralAdSDK/NewInterstitialAd + - MintegralAdSDK/RewardVideoAd + - MintegralAdSDK/SplashAd + - MintegralAdSDK/BannerAd (7.7.9): + - MintegralAdSDK/NativeAd + - MintegralAdSDK/BidBannerAd (7.7.9): + - MintegralAdSDK/BannerAd + - MintegralAdSDK/BidNativeAd + - MintegralAdSDK/BidInterstitialVideoAd (7.7.9): + - MintegralAdSDK/BidNativeAd + - MintegralAdSDK/InterstitialVideoAd + - MintegralAdSDK/BidNativeAd (7.7.9): + - MintegralAdSDK/NativeAd + - MintegralAdSDK/BidNewInterstitialAd (7.7.9): + - MintegralAdSDK/BidNativeAd + - MintegralAdSDK/NewInterstitialAd + - MintegralAdSDK/BidRewardVideoAd (7.7.9): + - MintegralAdSDK/BidNativeAd + - MintegralAdSDK/RewardVideoAd + - MintegralAdSDK/InterstitialVideoAd (7.7.9): + - MintegralAdSDK/NativeAd + - MintegralAdSDK/NativeAd (7.7.9) + - MintegralAdSDK/NativeAdvancedAd (7.7.9): + - MintegralAdSDK/NativeAd + - MintegralAdSDK/NewInterstitialAd (7.7.9): + - MintegralAdSDK/InterstitialVideoAd + - MintegralAdSDK/NativeAd + - MintegralAdSDK/RewardVideoAd (7.7.9): + - MintegralAdSDK/NativeAd + - MintegralAdSDK/SplashAd (7.7.9): + - MintegralAdSDK/NativeAd - MJRefresh (3.7.9) - SJBaseVideoPlayer (3.7.7.1): - Masonry @@ -129,7 +218,30 @@ PODS: - SVProgressHUD (2.3.1): - SVProgressHUD/Core (= 2.3.1) - SVProgressHUD/Core (2.3.1) + - TaurusxAdsSDK (1.12.0): + - TaurusxAdsSDK/TaurusxAds (= 1.12.0) + - TaurusxAdsSDK/TaurusxAds (1.12.0) - Toast (4.1.1) + - TPExchange (13.8.30) + - TradPlusAdSDK (14.9.0): + - TradPlusAdSDK/TradPlusAds (= 14.9.0) + - TradPlusAdSDK/AdMobAdapter (14.9.0) + - TradPlusAdSDK/AppLovinAdapter (14.9.0) + - TradPlusAdSDK/BigoAdapter (14.9.0) + - TradPlusAdSDK/FacebookAdapter (14.9.0) + - TradPlusAdSDK/InMobiAdapter (14.9.0) + - TradPlusAdSDK/IronSourceAdapter (14.9.0) + - TradPlusAdSDK/MintegralAdapter (14.9.0) + - TradPlusAdSDK/PangleAdapter (14.9.0) + - TradPlusAdSDK/TaurusXAdapter (14.9.0) + - TradPlusAdSDK/TPCrossAdapter (14.9.0) + - TradPlusAdSDK/TradPlusAds (14.9.0): + - TPExchange (= 13.8.30) + - TradPlusAdSDK/UnityAdapter (14.9.0) + - TradPlusAdSDK/VerveAdapter (14.9.0) + - TradPlusAdSDK/VungleAdapter (14.9.0) + - UnityAds (4.16.4) + - VungleAds (7.6.1) - YYCategories (1.0.4): - YYCategories/no-arc (= 1.0.4) - YYCategories/no-arc (1.0.4) @@ -141,22 +253,49 @@ PODS: DEPENDENCIES: - Adjust + - Ads-Global (= 7.8.0.5) - Alamofire + - AppLovinSDK (= 13.5.0) + - BigoADS (= 5.0.0) - collection-view-layouts/TagsLayout + - FBAudienceNetwork (= 6.20.1) - FDFullscreenPopGesture - FSPagerView + - Google-Mobile-Ads-SDK (= 12.14.0) - HWPanModal + - HyBid (= 3.7.1) + - InMobiSDK (= 11.1.0) - IQKeyboardManagerSwift + - IronSourceSDK (= 9.2.0) - JXPagingView/Paging - JXPlayer (from `https://github.com/zengjuexin/JXPlayer.git`, tag `0.2.0`) - JXSegmentedView - Kingfisher - LYEmptyView + - MintegralAdSDK (= 7.7.9) + - MintegralAdSDK/All (= 7.7.9) - MJRefresh - SmartCodable - SnapKit - SVProgressHUD + - TaurusxAdsSDK (= 1.12.0) - Toast + - TradPlusAdSDK (= 14.9.0) + - TradPlusAdSDK/AdMobAdapter (= 14.9.0) + - TradPlusAdSDK/AppLovinAdapter (= 14.9.0) + - TradPlusAdSDK/BigoAdapter (= 14.9.0) + - TradPlusAdSDK/FacebookAdapter (= 14.9.0) + - TradPlusAdSDK/InMobiAdapter (= 14.9.0) + - TradPlusAdSDK/IronSourceAdapter (= 14.9.0) + - TradPlusAdSDK/MintegralAdapter (= 14.9.0) + - TradPlusAdSDK/PangleAdapter (= 14.9.0) + - TradPlusAdSDK/TaurusXAdapter (= 14.9.0) + - TradPlusAdSDK/TPCrossAdapter (= 14.9.0) + - TradPlusAdSDK/UnityAdapter (= 14.9.0) + - TradPlusAdSDK/VerveAdapter (= 14.9.0) + - TradPlusAdSDK/VungleAdapter (= 14.9.0) + - UnityAds (= 4.16.4) + - VungleAds (= 7.6.1) - YYCategories - YYText - ZLPhotoBrowser @@ -165,11 +304,20 @@ SPEC REPOS: https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git: - Adjust - AdjustSignature + - Ads-Global - Alamofire + - AppLovinSDK + - ATOM-Standalone + - BigoADS - collection-view-layouts + - FBAudienceNetwork - FDFullscreenPopGesture - FSPagerView + - Google-Mobile-Ads-SDK + - GoogleUserMessagingPlatform - HWPanModal + - HyBid + - InMobiSDK - IQKeyboardCore - IQKeyboardManagerSwift - IQKeyboardNotification @@ -178,11 +326,14 @@ SPEC REPOS: - IQKeyboardToolbarManager - IQTextInputViewNotification - IQTextView + - IronSourceAdQualitySDK + - IronSourceSDK - JXPagingView - JXSegmentedView - Kingfisher - LYEmptyView - Masonry + - MintegralAdSDK - MJRefresh - SJBaseVideoPlayer - SJMediaCacheServer @@ -191,7 +342,12 @@ SPEC REPOS: - SmartCodable - SnapKit - SVProgressHUD + - TaurusxAdsSDK - Toast + - TPExchange + - TradPlusAdSDK + - UnityAds + - VungleAds - YYCategories - YYModel - YYText @@ -210,11 +366,20 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Adjust: 010c8b2b582add6ba200469c82c4d8c9e5ddb198 AdjustSignature: d634fc6b66295c38807f3b4e50978c1f72355950 + Ads-Global: f4958eaa8e92b32a05fab125fed7822be81cf878 Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 + AppLovinSDK: bf8974163120910e6b902e9610e7c5a2c0f577b6 + ATOM-Standalone: ad17f0d0e60b22f67ed99e5a336425d68d324f3e + BigoADS: 789ca51394adb1adb405e7e01ec8e43d3dc14f15 collection-view-layouts: 474ec4cce601a26247737227a97fa6a4eb30213f + FBAudienceNetwork: 08e86d63a05b3a5a59414af12e4af8d756943c80 FDFullscreenPopGesture: a8a620179e3d9c40e8e00256dcee1c1a27c6d0f0 FSPagerView: 670405b2f18e2a87fa37f20b00de783e562c25a8 + Google-Mobile-Ads-SDK: 4534fd2dfcd3f705c5485a6633c5188d03d4eed2 + GoogleUserMessagingPlatform: befe603da6501006420c206222acd449bba45a9c HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2 + HyBid: c75fa40e2d209aaed25b60f7bcd0e408d294c19e + InMobiSDK: 43b1d6560bd75c8c382bb54fa8e248f5ed979860 IQKeyboardCore: 8652977ec919cf5351aa2977fedd1a6546476fbc IQKeyboardManagerSwift: 835fc9c6e4732398113406d84900ad2e8f141218 IQKeyboardNotification: eb4910401f5a0e68f97e71c62f8a0c5b7e9d535c @@ -223,12 +388,15 @@ SPEC CHECKSUMS: IQKeyboardToolbarManager: c8a575e8b5fffe5873d0e75312244498a0759473 IQTextInputViewNotification: 3b9fb27a16e7ee8958cc9092cfb07a1a9e1fd559 IQTextView: ae13b4922f22e6f027f62c557d9f4f236b19d5c7 + IronSourceAdQualitySDK: 56314ade811a5226f76dfd377bc09aca0d6610c0 + IronSourceSDK: 66e1483cd62fb63162a965651f6f41c6b91664db JXPagingView: afdd2e9af09c90160dd232b970d603cc6e7ddd0e JXPlayer: 3064f658b71cba7f0db4098e618f11f5d8dce61a JXSegmentedView: cd73555ce2134d1656db2cb383ba9c2f36fb5078 Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c LYEmptyView: b6d418cfa38b78df0cf243f9a9c25ccbdc399922 Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 + MintegralAdSDK: 054814f99bb7e967b8974fe635d9005b225cbe42 MJRefresh: ff9e531227924c84ce459338414550a05d2aea78 SJBaseVideoPlayer: b3122de12225b27b71bd9a8a1f08f4dcf2f4e5ec SJMediaCacheServer: f6cd08ff32f5c6fc18ff06e676b42d6c17ce4cf1 @@ -237,12 +405,17 @@ SPEC CHECKSUMS: SmartCodable: 545dd052990fe7e80085463b79a1a5e462ee29ff SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22 + TaurusxAdsSDK: 6eed5ca3a64dcaeea3929bd483c7073fd7cf0628 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e + TPExchange: 41f39ebc014788b277bc78030f6ef2585a5c4460 + TradPlusAdSDK: 980b0feda31e25e1b8ec0f6481d43d7f2be1b39a + UnityAds: 91a5d786c1e79fcbf702c525af4700158aeb36c8 + VungleAds: ab78d62721933672a83efcf7d2de8ae0610494be YYCategories: 6bcd4314c6661a561410dce4a793379ebd306abd YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 YYText: 5c461d709e24d55a182d1441c41dc639a18a4849 ZLPhotoBrowser: d5928f08485c90a0b349a3a1e804e82c83ccf193 -PODFILE CHECKSUM: cd32c414c77ca06ddc270e513eb703e621fcdcff +PODFILE CHECKSUM: cbaf80f809461e9694f391ef939aeca544e90607 COCOAPODS: 1.16.2 From 040efe1cdaaf114b7e7e1ebe88ccfa14812767b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E7=A7=A6=E4=B9=9D?= Date: Sat, 24 Jan 2026 10:14:16 +0800 Subject: [PATCH 2/3] =?UTF-8?q?idfa=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Fableon.xcodeproj/project.pbxproj | 4 ++-- Fableon/App/SceneDelegate.swift | 10 +++++----- .../Object/Base/Controller/FATabBarController.swift | 1 - Fableon/Object/Libs/FATool/FATool.swift | 8 ++++++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Fableon.xcodeproj/project.pbxproj b/Fableon.xcodeproj/project.pbxproj index 754806a..503f384 100644 --- a/Fableon.xcodeproj/project.pbxproj +++ b/Fableon.xcodeproj/project.pbxproj @@ -2792,7 +2792,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Fableon/Fableon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 6XALB8RSYF; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; @@ -2835,7 +2835,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Fableon/Fableon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 6XALB8RSYF; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Fableon/Source/Info.plist; diff --git a/Fableon/App/SceneDelegate.swift b/Fableon/App/SceneDelegate.swift index c546579..cdd6702 100644 --- a/Fableon/App/SceneDelegate.swift +++ b/Fableon/App/SceneDelegate.swift @@ -47,6 +47,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } func sceneDidBecomeActive(_ scene: UIScene) { + FATool.requestIDFAAuthorization(nil) self.handleOnLine() FAStatAPI.requestEnterApp() self.setBadgeCount(0) @@ -76,13 +77,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { extension SceneDelegate { private func startApp() { - setRootVC() let languageManager = FALanguageManager.manager if languageManager.languageDataLanguageKey != languageManager.currentLanguageKey { let vc = FATool.getLanuchViewController() window?.rootViewController = vc - window?.makeKeyAndVisible() +// window?.makeKeyAndVisible() languageManager.updateLanguageData { [weak self] finish in guard let self = self else { return } @@ -107,7 +107,7 @@ extension SceneDelegate { self.retryHandleOpenAppMessage() } window?.rootViewController = vc - window?.makeKeyAndVisible() +// window?.makeKeyAndVisible() } else { self.setTabBarController() self.retryHandleOpenAppMessage() @@ -118,7 +118,7 @@ extension SceneDelegate { FAAdjustStateManager.manager.isOpenApp = true window?.rootViewController = FATabBarController() - window?.makeKeyAndVisible() +// window?.makeKeyAndVisible() } } @@ -133,7 +133,6 @@ extension SceneDelegate { if FANetworkMonitor.manager.isReachable == true { handleOnLine() -// FATool.requestIDFAAuthorization(nil) self.retryHandleOpenAppMessage() FAIapManager.manager.preloadingProducts() @@ -141,6 +140,7 @@ extension SceneDelegate { if localizedData.isEmpty { self.startApp() } +// FATool.requestIDFAAuthorization(nil) } } diff --git a/Fableon/Object/Base/Controller/FATabBarController.swift b/Fableon/Object/Base/Controller/FATabBarController.swift index 99eeec2..bdddcfe 100644 --- a/Fableon/Object/Base/Controller/FATabBarController.swift +++ b/Fableon/Object/Base/Controller/FATabBarController.swift @@ -48,7 +48,6 @@ class FATabBarController: UITabBarController { } } FATool.checkUpdates() - FATool.requestIDFAAuthorization(nil) } override var childForStatusBarStyle: UIViewController? { diff --git a/Fableon/Object/Libs/FATool/FATool.swift b/Fableon/Object/Libs/FATool/FATool.swift index 14413c5..f768bee 100644 --- a/Fableon/Object/Libs/FATool/FATool.swift +++ b/Fableon/Object/Libs/FATool/FATool.swift @@ -68,7 +68,7 @@ class FATool { } extension FATool { - + static var isNeedIdfaAuthorization = true static func requestIDFAAuthorization(_ completion: ((String?) -> Void)? = nil) { if FAAdjustStateManager.manager.idfaAuthorizationFinish { completion?(ASIdentifierManager.shared().advertisingIdentifier.uuidString) @@ -77,8 +77,12 @@ extension FATool { guard FANetworkMonitor.manager.isReachable == true, FAAdjustStateManager.manager.apnsAuthorizationFinish else { return } + guard isNeedIdfaAuthorization else { + return + } + isNeedIdfaAuthorization = false - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { ATTrackingManager.requestTrackingAuthorization { status in FAAdjustStateManager.manager.idfaAuthorizationFinish = true let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString From 308b4d5d3d20c41acb351e17bf8510d66702d631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E7=A7=A6=E4=B9=9D?= Date: Wed, 4 Feb 2026 17:25:54 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=B9=BF=E5=91=8A=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Fableon.xcodeproj/project.pbxproj | 60 +++++++ Fableon/App/SceneDelegate.swift | 6 + .../Base/Controller/FAViewController.swift | 4 + Fableon/Object/Base/Request/FAAPI/FAAPI.swift | 33 ++++ .../Player/V/FAPlayerDetailControlView.swift | 52 +++++- .../VC/FAPlayerDetailViewController.swift | 65 +++++-- .../Player/VM/FAShortDetailViewModel.swift | 75 +++++++- .../C/FARecommendViewController.swift | 5 + .../AdManager/Banner/FABannerAdManager.swift | 136 +++++++++++++++ .../AdManager/Banner/FATradPlusBannerAd.swift | 86 ++++++++++ .../Object/Libs/AdManager/FAAdManager.swift | 29 +++- .../AdManager/Native/FANativeAdManager.swift | 145 ++++++++++++++++ .../AdManager/Native/FATradPlusNativeAd.swift | 101 +++++++++++ .../Native/FATradPlusNativeAdView.swift | 160 ++++++++++++++++++ .../Libs/AdManager/Open/FAOpenAdManager.swift | 49 ++++-- .../AdManager/Open/FAOpenViewController.swift | 57 +++++++ .../AdManager/Open/FATradPlusOpenAd.swift | 4 + .../AdManager/Rewarded/FARewardedAdInfo.swift | 27 +++ .../Rewarded/FARewardedAdManager.swift | 157 +++++++++++++++++ .../Rewarded/FARewardedAdOverview.swift | 28 +++ .../Rewarded/FATradPlusInterstitialAd.swift | 91 ++++++++++ .../Rewarded/FATradPlusRewardedAd.swift | 90 ++++++++++ .../Object/Libs/Alert/FAPayRetainAlert.swift | 7 + .../color/#CC3333.colorset/Contents.json | 20 +++ 24 files changed, 1445 insertions(+), 42 deletions(-) create mode 100644 Fableon/Object/Libs/AdManager/Banner/FABannerAdManager.swift create mode 100644 Fableon/Object/Libs/AdManager/Banner/FATradPlusBannerAd.swift create mode 100644 Fableon/Object/Libs/AdManager/Native/FANativeAdManager.swift create mode 100644 Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAd.swift create mode 100644 Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAdView.swift create mode 100644 Fableon/Object/Libs/AdManager/Open/FAOpenViewController.swift create mode 100644 Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdInfo.swift create mode 100644 Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdManager.swift create mode 100644 Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdOverview.swift create mode 100644 Fableon/Object/Libs/AdManager/Rewarded/FATradPlusInterstitialAd.swift create mode 100644 Fableon/Object/Libs/AdManager/Rewarded/FATradPlusRewardedAd.swift create mode 100644 Fableon/Source/Assets.xcassets/color/#CC3333.colorset/Contents.json diff --git a/Fableon.xcodeproj/project.pbxproj b/Fableon.xcodeproj/project.pbxproj index 503f384..f1a3ec4 100644 --- a/Fableon.xcodeproj/project.pbxproj +++ b/Fableon.xcodeproj/project.pbxproj @@ -44,6 +44,17 @@ 035589362F2305D800FAEF4A /* FAAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589352F2305D800FAEF4A /* FAAdManager.swift */; }; 0355893A2F234B3E00FAEF4A /* FAOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589392F234B3E00FAEF4A /* FAOpenAdManager.swift */; }; 0355893C2F234C8300FAEF4A /* FATradPlusOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355893B2F234C8300FAEF4A /* FATradPlusOpenAd.swift */; }; + 0355893E2F2464C100FAEF4A /* FAOpenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355893D2F2464C100FAEF4A /* FAOpenViewController.swift */; }; + 035589402F24924300FAEF4A /* FARewardedAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355893F2F24924300FAEF4A /* FARewardedAdManager.swift */; }; + 035589422F24945600FAEF4A /* FATradPlusRewardedAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589412F24945600FAEF4A /* FATradPlusRewardedAd.swift */; }; + 035589452F249CF200FAEF4A /* FABannerAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589442F249CF200FAEF4A /* FABannerAdManager.swift */; }; + 035589472F249D9D00FAEF4A /* FATradPlusBannerAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589462F249D9D00FAEF4A /* FATradPlusBannerAd.swift */; }; + 035589492F273C5100FAEF4A /* FATradPlusInterstitialAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589482F273C5100FAEF4A /* FATradPlusInterstitialAd.swift */; }; + 0355894B2F274A9400FAEF4A /* FARewardedAdInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355894A2F274A9400FAEF4A /* FARewardedAdInfo.swift */; }; + 0355894D2F27530800FAEF4A /* FARewardedAdOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355894C2F27530800FAEF4A /* FARewardedAdOverview.swift */; }; + 035589502F2AEF3700FAEF4A /* FANativeAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0355894F2F2AEF3700FAEF4A /* FANativeAdManager.swift */; }; + 035589542F2AF1CB00FAEF4A /* FATradPlusNativeAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589532F2AF1CB00FAEF4A /* FATradPlusNativeAd.swift */; }; + 035589582F2B353200FAEF4A /* FATradPlusNativeAdView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035589572F2B353200FAEF4A /* FATradPlusNativeAdView.swift */; }; 039CE6042EAA2621007B5EED /* AppDelegate+FAAdjust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */; }; 039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */; }; 039CE60B2EAA31CB007B5EED /* FAStatAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */; }; @@ -422,6 +433,17 @@ 035589352F2305D800FAEF4A /* FAAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAdManager.swift; sourceTree = ""; }; 035589392F234B3E00FAEF4A /* FAOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOpenAdManager.swift; sourceTree = ""; }; 0355893B2F234C8300FAEF4A /* FATradPlusOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusOpenAd.swift; sourceTree = ""; }; + 0355893D2F2464C100FAEF4A /* FAOpenViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOpenViewController.swift; sourceTree = ""; }; + 0355893F2F24924300FAEF4A /* FARewardedAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARewardedAdManager.swift; sourceTree = ""; }; + 035589412F24945600FAEF4A /* FATradPlusRewardedAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusRewardedAd.swift; sourceTree = ""; }; + 035589442F249CF200FAEF4A /* FABannerAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FABannerAdManager.swift; sourceTree = ""; }; + 035589462F249D9D00FAEF4A /* FATradPlusBannerAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusBannerAd.swift; sourceTree = ""; }; + 035589482F273C5100FAEF4A /* FATradPlusInterstitialAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusInterstitialAd.swift; sourceTree = ""; }; + 0355894A2F274A9400FAEF4A /* FARewardedAdInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARewardedAdInfo.swift; sourceTree = ""; }; + 0355894C2F27530800FAEF4A /* FARewardedAdOverview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARewardedAdOverview.swift; sourceTree = ""; }; + 0355894F2F2AEF3700FAEF4A /* FANativeAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FANativeAdManager.swift; sourceTree = ""; }; + 035589532F2AF1CB00FAEF4A /* FATradPlusNativeAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusNativeAd.swift; sourceTree = ""; }; + 035589572F2B353200FAEF4A /* FATradPlusNativeAdView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FATradPlusNativeAdView.swift; sourceTree = ""; }; 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAAdjust.swift"; sourceTree = ""; }; 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAdjustStateManager.swift; sourceTree = ""; }; 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStatAPI.swift; sourceTree = ""; }; @@ -786,6 +808,8 @@ 035589342F2304B800FAEF4A /* AdManager */ = { isa = PBXGroup; children = ( + 0355894E2F2AEF0900FAEF4A /* Native */, + 035589432F249CC500FAEF4A /* Banner */, 035589382F2319EB00FAEF4A /* Open */, 035589372F2319DD00FAEF4A /* Rewarded */, 035589352F2305D800FAEF4A /* FAAdManager.swift */, @@ -796,6 +820,11 @@ 035589372F2319DD00FAEF4A /* Rewarded */ = { isa = PBXGroup; children = ( + 0355893F2F24924300FAEF4A /* FARewardedAdManager.swift */, + 035589412F24945600FAEF4A /* FATradPlusRewardedAd.swift */, + 035589482F273C5100FAEF4A /* FATradPlusInterstitialAd.swift */, + 0355894A2F274A9400FAEF4A /* FARewardedAdInfo.swift */, + 0355894C2F27530800FAEF4A /* FARewardedAdOverview.swift */, ); path = Rewarded; sourceTree = ""; @@ -803,12 +832,32 @@ 035589382F2319EB00FAEF4A /* Open */ = { isa = PBXGroup; children = ( + 0355893D2F2464C100FAEF4A /* FAOpenViewController.swift */, 035589392F234B3E00FAEF4A /* FAOpenAdManager.swift */, 0355893B2F234C8300FAEF4A /* FATradPlusOpenAd.swift */, ); path = Open; sourceTree = ""; }; + 035589432F249CC500FAEF4A /* Banner */ = { + isa = PBXGroup; + children = ( + 035589442F249CF200FAEF4A /* FABannerAdManager.swift */, + 035589462F249D9D00FAEF4A /* FATradPlusBannerAd.swift */, + ); + path = Banner; + sourceTree = ""; + }; + 0355894E2F2AEF0900FAEF4A /* Native */ = { + isa = PBXGroup; + children = ( + 0355894F2F2AEF3700FAEF4A /* FANativeAdManager.swift */, + 035589532F2AF1CB00FAEF4A /* FATradPlusNativeAd.swift */, + 035589572F2B353200FAEF4A /* FATradPlusNativeAdView.swift */, + ); + path = Native; + sourceTree = ""; + }; 039CE6072EAA2F37007B5EED /* AdjustStateManager */ = { isa = PBXGroup; children = ( @@ -2223,6 +2272,7 @@ F31451S3X15B941342J922Q3 /* TConfigCell.swift in Sources */, F3670DZ2KI89TBO3L9L36P57 /* XLoginView.swift in Sources */, F3V24670CK2EGR4595CDQ261 /* AWUModalMageCell.swift in Sources */, + 035589502F2AEF3700FAEF4A /* FANativeAdManager.swift in Sources */, F336143N569M8JG811WM9549 /* XHEedbackDetailView.swift in Sources */, F3F0952W592747Y1H6263E06 /* UCVBbfdebaffdFlowCell.swift in Sources */, F3SUP8DL68BIIEF1B8Z6U863 /* CFQConfigView.swift in Sources */, @@ -2252,7 +2302,10 @@ 03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */, 039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */, F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */, + 035589582F2B353200FAEF4A /* FATradPlusNativeAdView.swift in Sources */, F3140D182F162CFB003DA73F /* FAPayRetainAlertData.swift in Sources */, + 035589472F249D9D00FAEF4A /* FATradPlusBannerAd.swift in Sources */, + 035589402F24924300FAEF4A /* FARewardedAdManager.swift in Sources */, F3Q234J5M18F1Q5G2948P056 /* NPVBoutModalController.swift in Sources */, F38Y7NBX3M0RE4O142264411 /* EZEFlow.swift in Sources */, F363P024H4W1T8LN2546W883 /* YBanner.swift in Sources */, @@ -2262,6 +2315,7 @@ 031FDEC82EB1F89F00F4CAC7 /* FACoinsPackModel.swift in Sources */, F31N0S2575E3YC5AOG80WE90 /* TYElyon.swift in Sources */, F3JX29E3JQ40V23245TS8Z36 /* YRegisterController.swift in Sources */, + 035589422F24945600FAEF4A /* FATradPlusRewardedAd.swift in Sources */, F381171472542RD403O12925 /* QZOast.swift in Sources */, F33I62G51648130G0N6LN003 /* JOLayoutRyptorView.swift in Sources */, F39EH05VP4YX3F00P5162031 /* YFddebcdbeeffcebdfCenterView.swift in Sources */, @@ -2329,6 +2383,7 @@ 039CE6202EAB114B007B5EED /* FAPayDateModel.swift in Sources */, 03E23A4A2EAA1A4E004A8CEC /* FAConsumptionRecordsViewController.swift in Sources */, 031FDED02EB2167200F4CAC7 /* FACoinsPackBuyView.swift in Sources */, + 035589542F2AF1CB00FAEF4A /* FATradPlusNativeAd.swift in Sources */, 03E23A4B2EAA1A4E004A8CEC /* FAMeCoinsView.swift in Sources */, 03E23A4C2EAA1A4E004A8CEC /* FAHomeViewModel.swift in Sources */, 03E23A4D2EAA1A4E004A8CEC /* FAGenresViewController.swift in Sources */, @@ -2339,6 +2394,7 @@ 03E23A512EAA1A4E004A8CEC /* FAConsumptionRecordsCell.swift in Sources */, 03E23A522EAA1A4E004A8CEC /* FARankingListHeaderView.swift in Sources */, 03E23A532EAA1A4E004A8CEC /* FAVideoLockView.swift in Sources */, + 035589452F249CF200FAEF4A /* FABannerAdManager.swift in Sources */, 03E9A7482EB5D2CB000D1067 /* FALogoutAlert.swift in Sources */, 03E23A542EAA1A4E004A8CEC /* FAHomeViewController.swift in Sources */, 03E23A552EAA1A4E004A8CEC /* FAPopularListViewController.swift in Sources */, @@ -2357,6 +2413,7 @@ 03E23A5E2EAA1A4E004A8CEC /* FAHomeMustSeeContentView.swift in Sources */, 03E9A7902EC1B007000D1067 /* FAActivityManager.swift in Sources */, 03E23A5F2EAA1A4E004A8CEC /* FAEpSelectorCell.swift in Sources */, + 0355894B2F274A9400FAEF4A /* FARewardedAdInfo.swift in Sources */, 031FDEEC2EB35DF600F4CAC7 /* FACoinsPackAlert.swift in Sources */, 03E23A602EAA1A4E004A8CEC /* FASearchResultView.swift in Sources */, 03E23A612EAA1A4E004A8CEC /* FAHomeMustSeeContentCell.swift in Sources */, @@ -2395,6 +2452,7 @@ 03E23A7A2EAA1A4E004A8CEC /* FASearchRecordView.swift in Sources */, 03E23A7B2EAA1A4E004A8CEC /* FACollectViewController.swift in Sources */, 03E23A7C2EAA1A4E004A8CEC /* FAMeCell.swift in Sources */, + 0355894D2F27530800FAEF4A /* FARewardedAdOverview.swift in Sources */, 03E9A73A2EB45154000D1067 /* AppDelegate+FAApns.swift in Sources */, 03E23A7D2EAA1A4E004A8CEC /* FAWalletHeaderView.swift in Sources */, 03E23A7E2EAA1A4E004A8CEC /* FAPlayerProgressView.swift in Sources */, @@ -2426,6 +2484,7 @@ F3774560U03XA8151BTQ2Z61 /* HYLLayoutView.swift in Sources */, F3N85463XSRG9VFK665G9028 /* XKRefreshCell.swift in Sources */, 039CE6282EAB50A9007B5EED /* FAStoreCoinsView.swift in Sources */, + 035589492F273C5100FAEF4A /* FATradPlusInterstitialAd.swift in Sources */, 03E9A7402EB49BE6000D1067 /* FAUpdatesAlert.swift in Sources */, F35K41930D96476I83FHZ0D9 /* YLZFableonAlignmentCell.swift in Sources */, F3M8439X72Q55JY9G8U502D9 /* DXYFire.swift in Sources */, @@ -2493,6 +2552,7 @@ F395KWCS21F322A36E293006 /* IHAVeloriaButton.swift in Sources */, F31PD82C37A3078M87873G8T /* FFCheck.swift in Sources */, F36588YE88493S7167N94531 /* MProgressBoutCell.swift in Sources */, + 0355893E2F2464C100FAEF4A /* FAOpenViewController.swift in Sources */, F35TM2110T9T394C6D0214G9 /* EXYAlignmentHiveView.swift in Sources */, F32G5ID338260A2W78SS4618 /* TCFableonCell.swift in Sources */, F31E84U5Y6YW6430Z54X1K40 /* UCHVion.swift in Sources */, diff --git a/Fableon/App/SceneDelegate.swift b/Fableon/App/SceneDelegate.swift index cdd6702..342c081 100644 --- a/Fableon/App/SceneDelegate.swift +++ b/Fableon/App/SceneDelegate.swift @@ -39,7 +39,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { requestFirebase() requestApns() + //加载开屏广告 FAOpenAdManager.manager.showAdIfAvailable() + //加载激励广告 + FARewardedAdManager.manager.load() } func sceneDidDisconnect(_ scene: UIScene) { @@ -99,6 +102,8 @@ extension SceneDelegate { let hasOpenApp = UserDefaults.standard.object(forKey: kFAHasBeenOpenedAPPDefaultsKey) as? Bool if hasOpenApp != true { + //首次安装不展示广告 + FAOpenAdManager.manager.openAdVC.view.isHidden = true let vc = FAAppStartViewController() vc.openAppBlock = { [weak self] in guard let self = self else { return } @@ -118,6 +123,7 @@ extension SceneDelegate { FAAdjustStateManager.manager.isOpenApp = true window?.rootViewController = FATabBarController() + window?.addSubview(FAOpenAdManager.manager.openAdVC.view) // window?.makeKeyAndVisible() } } diff --git a/Fableon/Object/Base/Controller/FAViewController.swift b/Fableon/Object/Base/Controller/FAViewController.swift index f8c3b42..a73eea0 100644 --- a/Fableon/Object/Base/Controller/FAViewController.swift +++ b/Fableon/Object/Base/Controller/FAViewController.swift @@ -33,6 +33,10 @@ class FAViewController: UIViewController, JXSegmentedListContainerViewListDelega } } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + FAOpenAdManager.manager.vcAllowedShowAd = true + } func handleHeaderRefresh(_ completer: (() -> Void)?) { completer?() diff --git a/Fableon/Object/Base/Request/FAAPI/FAAPI.swift b/Fableon/Object/Base/Request/FAAPI/FAAPI.swift index 8cd1083..6e8104a 100644 --- a/Fableon/Object/Base/Request/FAAPI/FAAPI.swift +++ b/Fableon/Object/Base/Request/FAAPI/FAAPI.swift @@ -266,6 +266,39 @@ struct FAAPI { } } + ///获取激励广告数据 + static func requestRewardedAdOverview(completer: ((_ model: [FARewardedAdOverview]?) -> Void)?) { + + FANetworkManager.manager.request(FABaseURL + "/ad/watchAdOverview", + method: .get, + parameters: nil, + isLoding: false, + isToast: true) { (response: FANetworkManager.Response<[FARewardedAdOverview]>) in + completer?(response.data) + } + } + + ///广告解锁 + static func requestAdUnlockVideo(shortPlayId: String, videoId: String, completer: ((_ model: FAVideoUnlockResult?) -> Void)?) { + + let parameters = [ + "short_play_id" : shortPlayId, + "video_id" : videoId, + "ads_id" : "", + "ads_platform_key" : "", + "trans_id" : "", + "watch_num" : "1" + ] + + FANetworkManager.manager.request(FABaseURL + "/viewAdsUnlockVideo", + method: .post, + parameters: parameters, + isLoding: true, + isToast: true) { (response: FANetworkManager.Response) in + completer?(response.data) + } + } + static func requestVersionUpdateData(completer: ((_ model: FAVersionUpdateModel?) -> Void)?) { FANetworkManager.manager.request(FABaseURL + "/customer/versionControl", diff --git a/Fableon/Object/Class/Player/V/FAPlayerDetailControlView.swift b/Fableon/Object/Class/Player/V/FAPlayerDetailControlView.swift index 5b551db..b63c102 100644 --- a/Fableon/Object/Class/Player/V/FAPlayerDetailControlView.swift +++ b/Fableon/Object/Class/Player/V/FAPlayerDetailControlView.swift @@ -55,6 +55,12 @@ class FAPlayerDetailControlView: JXPlayerListControlView { override var isCurrent: Bool { didSet { playButton.setNeedsUpdateConfiguration() + if isCurrent { + self.bannerAdManager.loadAd() + } else { + self.bannerAdManager.cleanAd() + } + self.updateBannerAdLayout() } } @@ -102,6 +108,7 @@ class FAPlayerDetailControlView: JXPlayerListControlView { let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in self?.fa_viewModel?.userSwitchPlayAndPause() })) + button.isUserInteractionEnabled = false button.configurationUpdateHandler = { [weak self] button in guard let self = self else { return } @@ -147,7 +154,17 @@ class FAPlayerDetailControlView: JXPlayerListControlView { return button }() + private lazy var bannerAdView: UIView = { + let view = UIView() + return view + }() + private lazy var bannerAdManager: FABannerAdManager = { + let manager = FABannerAdManager() + manager.contentView = self.bannerAdView + manager.delegate = self + return manager + }() deinit { NotificationCenter.default.removeObserver(self) @@ -198,6 +215,25 @@ class FAPlayerDetailControlView: JXPlayerListControlView { collectButton.isSelected = state } + + private func updateBannerAdLayout() { + self.bannerAdView.isHidden = !self.bannerAdManager.isAdAvailable + if self.bannerAdManager.isAdAvailable { + epButton.view.snp.updateConstraints { make in + make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10 + 50 + 10)) + } + } else { + epButton.view.snp.updateConstraints { make in + make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10)) + } + } + } + + override func singleTapEvent() { + super.singleTapEvent() + self.fa_viewModel?.userSwitchPlayAndPause() + } + } extension FAPlayerDetailControlView { @@ -210,7 +246,7 @@ extension FAPlayerDetailControlView { addSubview(shortNameLabel) addSubview(playButton) addSubview(collectButton) - + addSubview(bannerAdView) epButton.view.snp.makeConstraints { make in make.left.equalToSuperview().offset(16) @@ -246,8 +282,20 @@ extension FAPlayerDetailControlView { make.height.equalTo(44) } - + bannerAdView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.left.equalToSuperview().offset(16) + make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10)) + make.height.equalTo(50) + } } } + +extension FAPlayerDetailControlView: FABannerAdManagerDelegate { + + func fa_bannerAdManagerDidLoadFinish(manager: FABannerAdManager) { + self.updateBannerAdLayout() + } +} diff --git a/Fableon/Object/Class/Player/VC/FAPlayerDetailViewController.swift b/Fableon/Object/Class/Player/VC/FAPlayerDetailViewController.swift index ca7fb83..11ae3b0 100644 --- a/Fableon/Object/Class/Player/VC/FAPlayerDetailViewController.swift +++ b/Fableon/Object/Class/Player/VC/FAPlayerDetailViewController.swift @@ -8,6 +8,7 @@ import UIKit import JXPlayer import FDFullscreenPopGesture +import SnapKit class FAPlayerDetailViewController: JXPlayerListViewController { @@ -30,22 +31,45 @@ class FAPlayerDetailViewController: JXPlayerListViewController { return self.viewModel as! FAShortDetailViewModel } + private var epText: String? { + didSet { + returnButton.setNeedsUpdateConfiguration() + } + } + private lazy var returnButton: UIButton = { - let button = UIButton(type: .custom) - button.setImage(UIImage(named: "Frame 3011"), for: .normal) - button.addAction(UIAction(handler: { [weak self] _ in + var configuration = UIButton.Configuration.plain() + configuration.image = UIImage(named: "Frame 3011") + configuration.imagePadding = 4 + configuration.contentInsets = .init(top: 0, leading: 10, bottom: 0, trailing: 10) + + let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in self?.handleBackButton() - }), for: .touchUpInside) + })) + + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + var newConfiguration = button.configuration + if let text = self.epText { + newConfiguration?.attributedTitle = AttributedString(text, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 18, weight: .regular), + .foregroundColor : UIColor.white + ])) + } else { + newConfiguration?.attributedTitle = nil + } + button.configuration = newConfiguration + } + + return button }() - private lazy var epLabel: UILabel = { - let label = UILabel() - label.font = .font(ofSize: 18, weight: .regular) - label.textColor = .init(named: .color_FFFFFF) - return label + private(set) lazy var nativeAdContentView: UIView = { + let view = UIView() + view.isHidden = true + return view }() - override func viewDidLoad() { super.viewDidLoad() @@ -59,6 +83,8 @@ class FAPlayerDetailViewController: JXPlayerListViewController { requestDetailList() + self.fa_viewModel.loadNativeAd() + fa_setupLayout() self.fa_viewModel.requestRecommandData() @@ -71,6 +97,7 @@ class FAPlayerDetailViewController: JXPlayerListViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + FAOpenAdManager.manager.vcAllowedShowAd = false } override func viewDidDisappear(_ animated: Bool) { @@ -142,19 +169,21 @@ class FAPlayerDetailViewController: JXPlayerListViewController { extension FAPlayerDetailViewController { private func fa_setupLayout() { + view.addSubview(nativeAdContentView) view.addSubview(returnButton) - view.addSubview(epLabel) + + nativeAdContentView.snp.remakeConstraints { make in + make.center.equalToSuperview() + make.width.equalTo(self.fa_viewModel.nativeAdManager.contentSize.width) + make.height.equalTo(self.fa_viewModel.nativeAdManager.contentSize.height) + } returnButton.snp.makeConstraints { make in - make.left.equalToSuperview().offset(16) - make.top.equalToSuperview().offset(UIScreen.safeTop) + make.left.equalToSuperview().offset(6) + make.top.equalTo(view.safeAreaLayoutGuide) make.height.equalTo(44) } - epLabel.snp.makeConstraints { make in - make.centerY.equalTo(returnButton) - make.left.equalTo(returnButton.snp.right).offset(4) - } } } @@ -185,7 +214,7 @@ extension FAPlayerDetailViewController: JXPlayerListViewControllerDelegate, JXPl func jx_playerListViewController(_ viewController: JXPlayerListViewController, didChangeIndexPathForVisible indexPath: IndexPath) { let model = self.fa_viewModel.dataArr[indexPath.section].episodeList?[indexPath.row] - epLabel.text = "Ep.\(model?.episode ?? "")" + self.epText = "Ep.\(model?.episode ?? "")" } func jx_shouldAutoScrollNextEpisode(_ viewController: JXPlayerListViewController) -> Bool { diff --git a/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift b/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift index a11ed6d..3b91aae 100644 --- a/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift +++ b/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift @@ -8,6 +8,7 @@ import SwiftUI import JXPlayer import YYText +import SnapKit //@MainActor class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject { @@ -45,6 +46,21 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject { private var payDataRequest: FAPayDataRequest? + override var isPlaying: Bool { + didSet { + if !self.isPlaying { + self.showNativeAd() + } else { + self.dismissNativeAd() + } + } + } + + private(set) lazy var nativeAdManager: FANativeAdManager = { + let manager = FANativeAdManager() + return manager + }() + func requestDetailData(indexPath: IndexPath? = nil, completer: ((_ code: Int) -> Void)?) { isShowRecommand = false @@ -236,12 +252,14 @@ extension FAShortDetailViewModel { private func _showPayRetainAlert(_ videoInfo: FAVideoInfoModel) { - payDataRequest = FAPayDataRequest() payDataRequest?.requestPayRetainInfo { [weak self] model in guard let self = self else { return } - guard let model = model else { return } + guard let model = model else { + self.showRewardedAd() + return + } let view = FAPayRetainAlert() view.model = model @@ -250,10 +268,63 @@ extension FAShortDetailViewModel { guard let self = self else { return } self.requestDetailData(indexPath: self.currentIndexPath, completer: nil) } + view.didDismissHandle = { [weak self] in + guard let self = self else { return } + self.showRewardedAd() + } view.show(in: FATool.keyWindow) } } + + ///展示激励广告 + private func showRewardedAd() { + let manager = FARewardedAdManager.manager + if manager.isAdAvailable { + manager.delegate = self + manager.show() + } + } + + ///加载原生广告 + func loadNativeAd() { + self.nativeAdManager.load() + } + + ///展示原生广告 + private func showNativeAd() { + guard let view = (self.playerListVC as? FAPlayerDetailViewController)?.nativeAdContentView else { return } + guard self.nativeAdManager.isAdAvailable else { return } + guard view.isHidden else { return } + + view.isHidden = false + self.nativeAdManager.contentView = view + self.nativeAdManager.show() + } + + private func dismissNativeAd() { + guard let view = (self.playerListVC as? FAPlayerDetailViewController)?.nativeAdContentView else { return } + + view.isHidden = true + } +} + +//MARK: FARewardedAdManagerDelegate +extension FAShortDetailViewModel: FARewardedAdManagerDelegate { + + func fa_rewardedAdManagerDidDismiss(adManager: FARewardedAdManager) { + guard let videoInfo = self.currentCell?.model as? FAVideoInfoModel else { return } + guard let shortPlayId = videoInfo.short_play_id else { return } + guard let videoId = videoInfo.short_play_video_id else { return } + + FAAPI.requestAdUnlockVideo(shortPlayId: shortPlayId, videoId: videoId) { [weak self] model in + guard let self = self else { return } + guard model?.status == .success else { return } + + self.requestDetailData(indexPath: self.currentIndexPath, completer: nil) + } + + } } extension FAShortDetailViewModel { diff --git a/Fableon/Object/Class/Recommend/C/FARecommendViewController.swift b/Fableon/Object/Class/Recommend/C/FARecommendViewController.swift index 0baf1c4..eb6ca42 100644 --- a/Fableon/Object/Class/Recommend/C/FARecommendViewController.swift +++ b/Fableon/Object/Class/Recommend/C/FARecommendViewController.swift @@ -61,6 +61,11 @@ class FARecommendViewController: JXPlayerListViewController { self.navigationController?.setNavigationBarHidden(true, animated: true) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + FAOpenAdManager.manager.vcAllowedShowAd = false + } + override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) self.viewModel.currentCell?.pause() diff --git a/Fableon/Object/Libs/AdManager/Banner/FABannerAdManager.swift b/Fableon/Object/Libs/AdManager/Banner/FABannerAdManager.swift new file mode 100644 index 0000000..f7e038d --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Banner/FABannerAdManager.swift @@ -0,0 +1,136 @@ +// +// FABannerAdManager.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/24. +// + +import UIKit + +@objc protocol FABannerAdManagerDelegate: NSObjectProtocol { + ///广告加载失败 + @objc optional func fa_bannerAdManager(manager: FABannerAdManager, didLoadFail error: Error) + ///广告加载成功 + @objc optional func fa_bannerAdManagerDidLoadFinish(manager: FABannerAdManager) + ///广告被展示 + @objc optional func fa_bannerAdManagerDidShow(manager: FABannerAdManager) + /// 广告展示失败 + @objc optional func fa_bannerAdManager(manager: FABannerAdManager, didDisplayFail error: Error) + ///广告被关闭 + @objc optional func fa_bannerAdManagerDidDismiss(manager: FABannerAdManager) + ///广告被点击 + @objc optional func fa_bannerAdManagerDidClick(manager: FABannerAdManager) +} + + +protocol FABannerAdDelegate: NSObjectProtocol { + ///广告加载失败 + func fa_bannerAd(bannerAd: FABannerAd, didLoadFail error: Error) + ///广告加载成功 + func fa_bannerAdDidLoadFinish(bannerAd: FABannerAd) + ///广告被展示 + func fa_bannerAdDidShow(bannerAd: FABannerAd) + ///广告展示失败 + func fa_bannerAd(bannerAd: FABannerAd, didDisplayFail error: Error) + ///广告被关闭 + func fa_bannerAdDidDismiss(bannerAd: FABannerAd) + ///广告被点击 + func fa_bannerAdDidClick(ad: FABannerAd) +} + +protocol FABannerAd: NSObjectProtocol { + + var delegate: FABannerAdDelegate? { get set } + + var adView: UIView? { get } + + var adPlatform: FAAdPlatform { get } + + var adType: FAAdType { get } + + var adUnitID: String { get } + + var isReady: Bool { get set } + + func loadAd() + +} + +class FABannerAdManager: NSObject { + + + private(set) var bannerAd: FABannerAd? { + didSet { + oldValue?.adView?.removeFromSuperview() + oldValue?.delegate = nil + } + } + + weak var delegate: FABannerAdManagerDelegate? + + + ///外部传入,用来承载广告的视图 + var contentView: UIView? { + didSet { + self.updateLayout() + } + } + + var isAdAvailable: Bool { + return bannerAd?.isReady ?? false + } + + func loadAd() { + let ad = FATradPlusBannerAd() + ad.delegate = self + + self.bannerAd = ad + + self.updateLayout() + self.bannerAd?.loadAd() + } + + func cleanAd() { + self.bannerAd = nil + } + + private func updateLayout() { + if let adView = bannerAd?.adView, let contentView = self.contentView { + contentView.addSubview(adView) + adView.frame = contentView.bounds + adView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + } + } +} + + +//MARK: FABannerAdManager +extension FABannerAdManager: FABannerAdDelegate { + + func fa_bannerAd(bannerAd: any FABannerAd, didDisplayFail error: any Error) { + self.delegate?.fa_bannerAdManager?(manager: self, didDisplayFail: error) + } + + func fa_bannerAd(bannerAd: any FABannerAd, didLoadFail error: any Error) { + self.delegate?.fa_bannerAdManager?(manager: self, didLoadFail: error) + } + + func fa_bannerAdDidLoadFinish(bannerAd: any FABannerAd) { + self.delegate?.fa_bannerAdManagerDidLoadFinish?(manager: self) + } + + func fa_bannerAdDidShow(bannerAd: any FABannerAd) { + self.delegate?.fa_bannerAdManagerDidShow?(manager: self) + } + + func fa_bannerAdDidDismiss(bannerAd: any FABannerAd) { + self.delegate?.fa_bannerAdManagerDidDismiss?(manager: self) + } + + func fa_bannerAdDidClick(ad: any FABannerAd) { + self.delegate?.fa_bannerAdManagerDidClick?(manager: self) + } + + + +} diff --git a/Fableon/Object/Libs/AdManager/Banner/FATradPlusBannerAd.swift b/Fableon/Object/Libs/AdManager/Banner/FATradPlusBannerAd.swift new file mode 100644 index 0000000..fb135d9 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Banner/FATradPlusBannerAd.swift @@ -0,0 +1,86 @@ +// +// FATradPlusBannerAd.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/24. +// + +import UIKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + +class FATradPlusBannerAd: NSObject, FABannerAd { + +#if canImport(TradPlusAds) + private lazy var bannerView: TradPlusAdBanner = { + let view = TradPlusAdBanner() + view.delegate = self + view.translatesAutoresizingMaskIntoConstraints = false + // view.adSize = . + return view + }() +#endif + + weak var delegate: FABannerAdDelegate? + + var adView: UIView? { +#if canImport(TradPlusAds) + return self.bannerView +#else + return nil +#endif + } + + var isReady: Bool = false + + var adPlatform: FAAdPlatform { + return .tradPlus + } + + var adType: FAAdType { + return .banner + } + + var adUnitID: String { + return self.adPlatform.bannerUnitId + } + + func loadAd() { + self.bannerView.setAdUnitID(self.adUnitID) + self.bannerView.loadAd(withSceneId: nil) + } + +} + +#if canImport(TradPlusAds) +extension FATradPlusBannerAd: TradPlusADBannerDelegate { + + func tpBannerAdLoaded(_ adInfo: [AnyHashable : Any]) { + self.isReady = true + debugLog("+++++++++++广告加载成功") + self.delegate?.fa_bannerAdDidLoadFinish(bannerAd: self) + } + + func tpBannerAdLoadFailWithError(_ error: any Error) { + self.delegate?.fa_bannerAd(bannerAd: self, didLoadFail: error) + } + + func tpBannerAdImpression(_ adInfo: [AnyHashable : Any]) { + debugLog("+++++++++++广告加载展示成功") + self.delegate?.fa_bannerAdDidShow(bannerAd: self) + } + + func tpBannerAdShow(_ adInfo: [AnyHashable : Any], didFailWithError error: any Error) { + self.delegate?.fa_bannerAd(bannerAd: self, didDisplayFail: error) + } + + func tpBannerAdClicked(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_bannerAdDidClick(ad: self) + } + + func viewControllerForPresentingModalView() -> UIViewController? { + return nil + } +} +#endif diff --git a/Fableon/Object/Libs/AdManager/FAAdManager.swift b/Fableon/Object/Libs/AdManager/FAAdManager.swift index 508fe25..608cba2 100644 --- a/Fableon/Object/Libs/AdManager/FAAdManager.swift +++ b/Fableon/Object/Libs/AdManager/FAAdManager.swift @@ -6,6 +6,7 @@ // import UIKit +import SmartCodable #if canImport(TradPlusAds) import TradPlusAds #endif @@ -31,9 +32,16 @@ class FAAdManager: NSObject { } +enum FAAdType { + case rewarded + case interstitial + case banner + case open + case native +} -enum FAAdPlatform { - case tradPlus +enum FAAdPlatform: String, SmartCaseDefaultable { + case tradPlus = "tradplus" ///激励广告单元Id var rewardedUnitId: String { @@ -59,4 +67,21 @@ enum FAAdPlatform { } } + ///插屏广告 + var interstitialUnitId: String { + switch self { + case .tradPlus: + return "F8303BAF407F8ED3642B1F8B703D4822" + } + } + + ///原生广告 + var nativeUnitId: String { + switch self { + case .tradPlus: + return "C4463BAD71D16B4B840703EAEBD0D422" + } + } + } + diff --git a/Fableon/Object/Libs/AdManager/Native/FANativeAdManager.swift b/Fableon/Object/Libs/AdManager/Native/FANativeAdManager.swift new file mode 100644 index 0000000..2f8c05b --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Native/FANativeAdManager.swift @@ -0,0 +1,145 @@ +// +// FANativeAdManager.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/29. +// + +import UIKit + +@objc protocol FANativeAdManagerDelegate: NSObjectProtocol { + ///广告加载失败 + @objc optional func fa_nativeAdManager(manager: FANativeAdManager, didLoadFail error: Error) + ///广告加载成功 + @objc optional func fa_nativeAdManagerDidLoadFinish(manager: FANativeAdManager) + ///广告被展示 + @objc optional func fa_nativeAdManagerDidShow(manager: FANativeAdManager) + /// 广告展示失败 + @objc optional func fa_nativeAdManager(manager: FANativeAdManager, didDisplayFail error: Error) + ///广告被关闭 + @objc optional func fa_nativeAdManagerDidDismiss(manager: FANativeAdManager) + ///广告被点击 + @objc optional func fa_nativeAdManagerDidClick(manager: FANativeAdManager) +} + + +protocol FANativeAdDelegate: NSObjectProtocol { + ///广告加载失败 + func fa_nativeAd(nativeAd: FANativeAd, didLoadFail error: Error) + ///广告加载成功 + func fa_nativeAdDidLoadFinish(nativeAd: FANativeAd) + ///广告被展示 + func fa_nativeAdDidShow(nativeAd: FANativeAd) + ///广告展示失败 + func fa_nativeAd(nativeAd: FANativeAd, didDisplayFail error: Error) + ///广告被关闭 + func fa_nativeAdDidDismiss(nativeAd: FANativeAd) + ///广告被点击 + func fa_nativeAdDidClick(nativeAd: FANativeAd) +} + +protocol FANativeAd: NSObjectProtocol { + + var delegate: FANativeAdDelegate? { get set } + + var adView: UIView? { get set } + + var adSize: CGSize? { get set } + + var adPlatform: FAAdPlatform { get } + + var adType: FAAdType { get } + + var adUnitID: String { get } + + var isReady: Bool { get } + + func loadAd() + func show() + + +} + +class FANativeAdManager: NSObject { + + weak var delegate: FANativeAdManagerDelegate? + + ///外部传入,用来承载广告的视图 + var contentView: UIView? { + didSet { + self.nativeAd?.adView = contentView + } + } + + let contentSize: CGSize = .init(width: 300, height: 400) + + var isAdAvailable: Bool { + return nativeAd?.isReady ?? false + } + + ///广告是否在加载中 + private(set) var isLoadingAd = false + + ///是否展示过 + var hasShow = false + + + private var nativeAd: FANativeAd? { + didSet { + oldValue?.delegate = nil + nativeAd?.delegate = self + } + } + + + + func load() { + guard !self.isLoadingAd else { return } + + self.isLoadingAd = true + self.nativeAd = FATradPlusNativeAd() + self.nativeAd?.adSize = self.contentSize + self.nativeAd?.adView = contentView + self.nativeAd?.delegate = self + self.nativeAd?.loadAd() + } + + func show() { + guard !hasShow else { return } + self.hasShow = true + self.nativeAd?.show() + } + +} + +extension FANativeAdManager: FANativeAdDelegate { + + func fa_nativeAdDidLoadFinish(nativeAd: any FANativeAd) { + self.isLoadingAd = false + self.delegate?.fa_nativeAdManagerDidLoadFinish?(manager: self) + } + + func fa_nativeAdDidShow(nativeAd: any FANativeAd) { + self.delegate?.fa_nativeAdManagerDidShow?(manager: self) + } + + func fa_nativeAd(nativeAd: any FANativeAd, didLoadFail error: any Error) { + self.isLoadingAd = false + self.delegate?.fa_nativeAdManager?(manager: self, didLoadFail: error) + } + + func fa_nativeAd(nativeAd: any FANativeAd, didDisplayFail error: any Error) { + self.delegate?.fa_nativeAdManager?(manager: self, didDisplayFail: error) + } + + func fa_nativeAdDidDismiss(nativeAd: any FANativeAd) { + self.delegate?.fa_nativeAdManagerDidDismiss?(manager: self) + } + + func fa_nativeAdDidClick(nativeAd: any FANativeAd) { + self.delegate?.fa_nativeAdManagerDidClick?(manager: self) + } + + + +} diff --git a/Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAd.swift b/Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAd.swift new file mode 100644 index 0000000..d6402e7 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAd.swift @@ -0,0 +1,101 @@ +// +// FATradPlusNativeAd.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/29. +// + +import UIKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + +class FATradPlusNativeAd: NSObject, FANativeAd { + +#if canImport(TradPlusAds) + private var nativeAd: TradPlusAdNative? +#endif + + weak var delegate: FANativeAdDelegate? + + var adView: UIView? + + var adSize: CGSize? + + var adPlatform: FAAdPlatform { + return .tradPlus + } + + var adType: FAAdType { + return .native + } + + var adUnitID: String { + return adPlatform.nativeUnitId + } + + var isReady: Bool { +#if canImport(TradPlusAds) + return self.nativeAd?.isAdReady ?? false +#else + return false +#endif + } + + func loadAd() { +#if canImport(TradPlusAds) + guard let adSize = self.adSize else { return } + self.nativeAd = TradPlusAdNative() + self.nativeAd?.setAdUnitID(self.adUnitID) + self.nativeAd?.setTemplateRenderSize(adSize) + self.nativeAd?.delegate = self + self.nativeAd?.loadAd() +#endif + } + + func show() { + guard self.isReady else { return } + guard let adView = adView else { return } +// let view = FATradPlusNativeAdView() +// +// let nativeRenderer = TradPlusNativeRenderer() +// nativeRenderer.setTitleLable(view.titleLabel, canClick: true) + +// self.nativeAd?.showAD(with: nativeRenderer, subview: adView, sceneId: nil) + self.nativeAd?.showAD(withRenderingViewClass: FATradPlusNativeAdView.self, subview: adView, sceneId: nil) + + } + + +} + +//MARK: TradPlusADNativeDelegate +#if canImport(TradPlusAds) +extension FATradPlusNativeAd: TradPlusADNativeDelegate { + + func tpNativeAdLoaded(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_nativeAdDidLoadFinish(nativeAd: self) + } + + func tpNativeAdImpression(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_nativeAdDidShow(nativeAd: self) + } + + func tpNativeAdLoadFailWithError(_ error: any Error) { + self.delegate?.fa_nativeAd(nativeAd: self, didLoadFail: error) + } + + func tpNativeAdShow(_ adInfo: [AnyHashable : Any], didFailWithError error: any Error) { + self.delegate?.fa_nativeAd(nativeAd: self, didDisplayFail: error) + } + + func tpNativeAdClicked(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_nativeAdDidClick(nativeAd: self) + } + + func tpNativeAdClose(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_nativeAdDidDismiss(nativeAd: self) + } + +} +#endif diff --git a/Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAdView.swift b/Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAdView.swift new file mode 100644 index 0000000..651ef09 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Native/FATradPlusNativeAdView.swift @@ -0,0 +1,160 @@ +// +// FATradPlusNativeAdView.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/29. +// + +import UIKit +import SnapKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + +class FATradPlusNativeAdView: UIView { + + + lazy var mainImageView: FAImageView = { + let imageView = FAImageView() + return imageView + }() + + lazy var iconImageView: UIImageView = { + let imageView = FAImageView() + imageView.layer.cornerRadius = 5 + imageView.layer.masksToBounds = true + return imageView + }() + + lazy var titleLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.textAlignment = .center + label.numberOfLines = 0 + return label + }() + + lazy var textLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.textAlignment = .center + label.numberOfLines = 0 + return label + }() + + lazy var ctaLabel: UILabel = { + let label = UILabel() + label.textColor = .white + label.textAlignment = .center + label.numberOfLines = 0 + label.layer.cornerRadius = 5 + label.layer.masksToBounds = true + label.backgroundColor = .CC_3333 + return label + }() + + lazy var adChoiceImageView: UIImageView = { + let imageView = UIImageView() + return imageView + }() + + lazy var adLabel: UILabel = { + let label = UILabel() + label.textColor = .orange + label.font = .font(ofSize: 10, weight: .regular) + label.text = "AD" + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = .white + fa_layoutUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func fa_layoutUI() { + addSubview(mainImageView) + addSubview(iconImageView) + addSubview(titleLabel) + addSubview(textLabel) + addSubview(ctaLabel) + addSubview(adChoiceImageView) + addSubview(adLabel) + + mainImageView.snp.makeConstraints { make in + make.left.right.top.equalToSuperview() +// make.height.equalTo(80) + make.height.equalTo(mainImageView.snp.width).multipliedBy(0.5) + } + + iconImageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(mainImageView.snp.bottom).offset(10) + make.width.height.equalTo(50) + } + + titleLabel.snp.makeConstraints { make in + make.top.equalTo(iconImageView.snp.bottom).offset(10) + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + } + + textLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.right.lessThanOrEqualToSuperview().offset(-10) + } + + ctaLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(textLabel.snp.bottom).offset(10) + make.right.equalToSuperview().offset(-10) + make.height.equalTo(40) + } + + adChoiceImageView.snp.makeConstraints { make in + make.width.height.equalTo(10) + make.right.equalToSuperview().offset(-10) + make.bottom.equalToSuperview().offset(-10) + } + + adLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(10) + make.centerY.equalTo(adChoiceImageView) + } + } + +} + +#if canImport(TradPlusAds) +extension FATradPlusNativeAdView: TradPlusNativeAdRendering { + + func nativeTitleTextLabel() -> UILabel! { + return titleLabel + } + + func nativeMainTextLabel() -> UILabel! { + return textLabel + } + + func nativeIconImageView() -> UIImageView! { + return iconImageView + } + + func nativeMainImageView() -> UIImageView! { + return mainImageView + } + + func nativeCallToActionTextLabel() -> UILabel! { + return ctaLabel + } + + func nativePrivacyInformationIconImageView() -> UIImageView! { + return adChoiceImageView + } +} +#endif diff --git a/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift b/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift index b3916a0..b9db6b3 100644 --- a/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift +++ b/Fableon/Object/Libs/AdManager/Open/FAOpenAdManager.swift @@ -34,6 +34,7 @@ protocol FAOpenAdDelegate: NSObjectProtocol { protocol FAOpenAd: NSObjectProtocol { var delegate: FAOpenAdDelegate? { get set } var adPlatform: FAAdPlatform { get } + var adType: FAAdType { get } var adUnitID: String { get } var isReady: Bool { get } @@ -47,6 +48,8 @@ class FAOpenAdManager: NSObject { weak var delegate: FAOpenAdManagerDelegate? + var openAdVC: FAOpenViewController = FAOpenViewController() + private var appOpenAd: FAOpenAd? { didSet { oldValue?.delegate = nil @@ -54,12 +57,20 @@ class FAOpenAdManager: NSObject { } } + ///控制当前页面是否可以展示广告,冷启动有效 + var vcAllowedShowAd = true + ///广告是否在加载中 private(set) var isLoadingAd = false + ///广告正在被展示 private(set) var isShowingAd = false /// 标记是否在等待广告加载完成后自动展示 - private var isWaitingToShow = false + private(set) var isWaitingToShow = false private var timeOutTimer: Timer? + var isAdAvailable: Bool { + return appOpenAd?.isReady ?? false + } + deinit { NotificationCenter.default.removeObserver(self) } @@ -71,7 +82,7 @@ class FAOpenAdManager: NSObject { } func loadAd() { - if isLoadingAd || isAdAvailable() { + if isLoadingAd || isAdAvailable { return } isLoadingAd = true @@ -81,10 +92,11 @@ class FAOpenAdManager: NSObject { } func showAd() { - guard let ad = appOpenAd, isAdAvailable() else { + guard let ad = appOpenAd, isAdAvailable else { loadAd() return } + if self.openAdVC.view.isHidden { return } isWaitingToShow = false isShowingAd = true @@ -97,7 +109,7 @@ class FAOpenAdManager: NSObject { guard !isShowingAd else { return } // 1. 如果广告已就绪,直接展示 - if isAdAvailable() { + if isAdAvailable { showAd() return } @@ -108,18 +120,16 @@ class FAOpenAdManager: NSObject { loadAd() } - private func isAdAvailable() -> Bool { - return appOpenAd?.isReady ?? false - } + // MARK: - Timer (防止加载时间过长,用户已进入首页后突然弹出广告) private func startTimeoutTimer() { clearTimer() -// timeOutTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] _ in -// Task { @MainActor in -// self?.handleTimeOut() -// } -// } + timeOutTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] _ in + Task { @MainActor in + self?.handleTimeOut() + } + } } @objc private func handleTimeOut() { @@ -150,7 +160,6 @@ extension FAOpenAdManager: FAOpenAdDelegate { clearTimer() requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) delegate?.fa_openAdManager?(manager: self, didLoadFail: error) - delegate = nil } func fa_openAdDidLoadFinish(ad: FAOpenAd) { @@ -171,7 +180,6 @@ extension FAOpenAdManager: FAOpenAdDelegate { clearTimer() requestStatAd(type: "show_failed", errorMsg: error.localizedDescription) delegate?.fa_openAdManager?(manager: self, didDisplayFail: error) - delegate = nil } func fa_openAdDidShow(ad: FAOpenAd) { @@ -183,9 +191,11 @@ extension FAOpenAdManager: FAOpenAdDelegate { isShowingAd = false appOpenAd = nil delegate?.fa_openAdManagerDidDismiss?(manager: self) - // 关闭后自动预加载下一条,提高下次展示成功率 - loadAd() - delegate = nil + // 关闭后自动预加载下一条,5秒后开始加载 + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in + guard let self = self else { return } + self.loadAd() + } } func fa_openAdDidClick(ad: FAOpenAd) { @@ -216,6 +226,9 @@ extension FAOpenAdManager { } @objc private func didBecomeActiveNotification() { - showAdIfAvailable() + if self.isAdAvailable, self.vcAllowedShowAd { + self.openAdVC.view.isHidden = false + self.showAd() + } } } diff --git a/Fableon/Object/Libs/AdManager/Open/FAOpenViewController.swift b/Fableon/Object/Libs/AdManager/Open/FAOpenViewController.swift new file mode 100644 index 0000000..2f485b0 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Open/FAOpenViewController.swift @@ -0,0 +1,57 @@ +// +// FAOpenViewController.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/24. +// + +import UIKit + +class FAOpenViewController: UIViewController { + + private lazy var lanuchVC: UIViewController? = { + return FATool.getLanuchViewController() + }() + + override func viewDidLoad() { + super.viewDidLoad() + if let vc = lanuchVC { + addChild(vc) + view.addSubview(vc.view) + } + + FAOpenAdManager.manager.delegate = self + + } + + + +} + +//MARK: FAOpenAdManagerDelegate +extension FAOpenViewController: FAOpenAdManagerDelegate { + + func fa_openAdManagerDidShow(manager: FAOpenAdManager) { + + } + + func fa_openAdManagerDidDismiss(manager: FAOpenAdManager) { + self.view.isHidden = true + } + + func fa_openAdManager(manager: FAOpenAdManager, didLoadFail error: any Error) { + self.view.isHidden = true + } + + func fa_openAdManager(manager: FAOpenAdManager, didOtherFail error: any Error) { + self.view.isHidden = true + } + + func fa_openAdManager(manager: FAOpenAdManager, didDisplayFail error: any Error) { + self.view.isHidden = true + } + + + + +} diff --git a/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift b/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift index 0ad9fe6..1e58935 100644 --- a/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift +++ b/Fableon/Object/Libs/AdManager/Open/FATradPlusOpenAd.swift @@ -21,6 +21,10 @@ class FATradPlusOpenAd: NSObject, FAOpenAd { var adPlatform: FAAdPlatform { return .tradPlus } + + var adType: FAAdType { + return .open + } var adUnitID: String { return self.adPlatform.openUnitId diff --git a/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdInfo.swift b/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdInfo.swift new file mode 100644 index 0000000..b77b566 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdInfo.swift @@ -0,0 +1,27 @@ +// +// FARewardedAdInfo.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/26. +// + +import UIKit +import SmartCodable + +class FARewardedAdData: NSObject, SmartCodable { + + required override init() { } + + var ad: FARewardedAdInfo? +} + +class FARewardedAdInfo: NSObject, SmartCodable { + + required override init() { } + + var id: String? + var platform_name: String? + var ads_id: String? + var status: String? + var platform_key: FAAdPlatform? +} diff --git a/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdManager.swift b/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdManager.swift new file mode 100644 index 0000000..59d84ff --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdManager.swift @@ -0,0 +1,157 @@ +// +// FARewardedAdManager.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/24. +// + +import UIKit + +@objc protocol FARewardedAdManagerDelegate: NSObjectProtocol { + + ///发放奖励 +// @objc optional func rewardedAdManager(adManager: BRRewardedAdManager, userDidEarnReward adInfo: VPAdInfo) + ///广告加载成功 + @objc optional func fa_rewardedAdManagerDidLoadFinish(adManager: FARewardedAdManager) + ///广告加载失败 + @objc optional func fa_rewardedAdManager(adManager: FARewardedAdManager, didLoadFail error: Error) + ///广告展示失败 + @objc optional func fa_rewardedAdManager(adManager: FARewardedAdManager, didDisplayFail error: Error) + ///广告被展示 + @objc optional func fa_rewardedAdManagerDidShow(adManager: FARewardedAdManager) + ///广告被关闭 + @objc optional func fa_rewardedAdManagerDidDismiss(adManager: FARewardedAdManager) + ///广告被点击 + @objc optional func fa_rewardedAdManagerDidClick(adManager: FARewardedAdManager) + ///其它错误 + @objc optional func fa_rewardedAdManager(adManager: FARewardedAdManager, didOtherFail error: Error) + +} + +protocol FARewardedAdDelegate: NSObjectProtocol { + + ///发放奖励 +// func rewardedAd(ad: BRRewardedAd, userDidEarnReward adInfo: VPAdInfo) + ///广告加载失败 + func fa_rewardedAd(ad: FARewardedAd, didLoadFail error: Error) + ///广告加载成功 + func fa_rewardedAdDidLoadFinish(ad: FARewardedAd) + ///广告展示失败 + func fa_rewardedAd(ad: FARewardedAd, didDisplayFail error: Error) + ///广告被展示 + func fa_rewardedAdDidShow(ad: FARewardedAd) + ///广告被关闭 + func fa_rewardedAdDidDismiss(ad: FARewardedAd) + ///广告被点击 + func fa_rewardedAdDidClick(ad: FARewardedAd) +} + +protocol FARewardedAd: NSObjectProtocol { + + var delegate: FARewardedAdDelegate? { get set } + var adPlatform: FAAdPlatform { get } + var adType: FAAdType { get } + var adUnitID: String { get } + var networkName: String { get set } + var isReady: Bool { get } + + func loadAd() + func showAd() + +} + +class FARewardedAdManager: NSObject { + + static let manager = FARewardedAdManager() + + weak var delegate: FARewardedAdManagerDelegate? + + var rewardedAd: FARewardedAd? { + didSet { + oldValue?.delegate = nil + rewardedAd?.delegate = self + } + } + + var isAdAvailable: Bool { + return rewardedAd?.isReady ?? false + } + + + + + override init() { + super.init() + } + + func load() { + if self.isAdAvailable { return } + +// if loadAdType != .rewarded { +// loadAdType = .rewarded +// } else { +// loadAdType = .interstitial +// } +// +// if loadAdType == .rewarded { +// self.rewardedAd = FATradPlusRewardedAd() +// } else { + self.rewardedAd = FATradPlusInterstitialAd() +// } + self.rewardedAd?.loadAd() + +// self.requestAdOverview() + } + + func show() { + guard self.isAdAvailable else { return } + + self.rewardedAd?.showAd() + } + + +} + +//MARK: FARewardedAdDelegate +extension FARewardedAdManager: FARewardedAdDelegate { + + func fa_rewardedAd(ad: any FARewardedAd, didLoadFail error: any Error) { + self.rewardedAd = nil + self.delegate?.fa_rewardedAdManager?(adManager: self, didLoadFail: error) + } + + func fa_rewardedAd(ad: any FARewardedAd, didDisplayFail error: any Error) { + self.rewardedAd = nil + self.delegate?.fa_rewardedAdManager?(adManager: self, didDisplayFail: error) + } + + func fa_rewardedAdDidLoadFinish(ad: any FARewardedAd) { + self.delegate?.fa_rewardedAdManagerDidLoadFinish?(adManager: self) + } + + func fa_rewardedAdDidShow(ad: any FARewardedAd) { + self.delegate?.fa_rewardedAdManagerDidShow?(adManager: self) + } + + func fa_rewardedAdDidDismiss(ad: any FARewardedAd) { + self.rewardedAd = nil + self.delegate?.fa_rewardedAdManagerDidDismiss?(adManager: self) + //加载新的广告 + self.load() + } + + func fa_rewardedAdDidClick(ad: any FARewardedAd) { + self.delegate?.fa_rewardedAdManagerDidClick?(adManager: self) + } +} + +extension FARewardedAdManager { + + private func requestAdOverview() { + + FAAPI.requestRewardedAdOverview { [weak self] list in + guard let self = self else { return } + + } + } +} diff --git a/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdOverview.swift b/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdOverview.swift new file mode 100644 index 0000000..c945d5e --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Rewarded/FARewardedAdOverview.swift @@ -0,0 +1,28 @@ +// +// FARewardedAdOverview.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/26. +// + +import UIKit +import SmartCodable + +class FARewardedAdOverview: NSObject, SmartCodable { + + required override init() { } + + var id: String? + var platform_key: FAAdPlatform? + var watch_times_limit: Int? + var polling_times: Int? + + var ad_type: FARewardedAdWeight? +} + +class FARewardedAdWeight: NSObject, SmartCodable { + required override init() { } + + var reward: Int? + var interstitial: Int? +} diff --git a/Fableon/Object/Libs/AdManager/Rewarded/FATradPlusInterstitialAd.swift b/Fableon/Object/Libs/AdManager/Rewarded/FATradPlusInterstitialAd.swift new file mode 100644 index 0000000..af099cb --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Rewarded/FATradPlusInterstitialAd.swift @@ -0,0 +1,91 @@ +// +// FATradPlusInterstitialAd.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/26. +// + +import UIKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + +class FATradPlusInterstitialAd: NSObject, FARewardedAd { + +#if canImport(TradPlusAds) + private var interstitialAd: TradPlusAdInterstitial? +#endif + + var delegate: FARewardedAdDelegate? + + var adPlatform: FAAdPlatform { + return .tradPlus + } + + var adType: FAAdType { + return .interstitial + } + + var adUnitID: String { + return adPlatform.interstitialUnitId + } + + var networkName: String = "" + + var isReady: Bool { +#if canImport(TradPlusAds) + return self.interstitialAd?.isAdReady ?? false +#else + return false +#endif + } + + func loadAd() { +#if canImport(TradPlusAds) + self.interstitialAd = TradPlusAdInterstitial() + self.interstitialAd?.setAdUnitID(self.adUnitID) + self.interstitialAd?.delegate = self + self.interstitialAd?.loadAd() +#endif + } + + func showAd() { +#if canImport(TradPlusAds) + guard self.isReady else { return } + self.interstitialAd?.showAd(withSceneId: nil) +#endif + } + + +} + +#if canImport(TradPlusAds) +//MARK: TradPlusADInterstitialDelegate +extension FATradPlusInterstitialAd: TradPlusADInterstitialDelegate { + + func tpInterstitialAdLoaded(_ adInfo: [AnyHashable : Any]) { + self.networkName = (adInfo["adNetworkName"] as? String) ?? "unknown" + self.delegate?.fa_rewardedAdDidLoadFinish(ad: self) + } + + func tpInterstitialAdImpression(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_rewardedAdDidShow(ad: self) + } + + func tpInterstitialAdLoadFailWithError(_ error: any Error) { + self.delegate?.fa_rewardedAd(ad: self, didLoadFail: error) + } + + func tpInterstitialAdShow(_ adInfo: [AnyHashable : Any], didFailWithError error: any Error) { + self.delegate?.fa_rewardedAd(ad: self, didDisplayFail: error) + } + + func tpInterstitialAdClicked(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_rewardedAdDidClick(ad: self) + } + + func tpInterstitialAdDismissed(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_rewardedAdDidDismiss(ad: self) + } +} +#endif diff --git a/Fableon/Object/Libs/AdManager/Rewarded/FATradPlusRewardedAd.swift b/Fableon/Object/Libs/AdManager/Rewarded/FATradPlusRewardedAd.swift new file mode 100644 index 0000000..a9d4240 --- /dev/null +++ b/Fableon/Object/Libs/AdManager/Rewarded/FATradPlusRewardedAd.swift @@ -0,0 +1,90 @@ +// +// FATradPlusRewardedAd.swift +// Fableon +// +// Created by 湖北秦九 on 2026/1/24. +// + +import UIKit +#if canImport(TradPlusAds) +import TradPlusAds +#endif + +class FATradPlusRewardedAd: NSObject, FARewardedAd { + +#if canImport(TradPlusAds) + private var rewardedAd: TradPlusAdRewarded? +#endif + + weak var delegate: FARewardedAdDelegate? + + var adPlatform: FAAdPlatform = .tradPlus + + var adType: FAAdType { + return .rewarded + } + + var adUnitID: String { + return self.adPlatform.rewardedUnitId + } + + var networkName: String = "" + + var isReady: Bool { +#if canImport(TradPlusAds) + return self.rewardedAd?.isAdReady ?? false +#else + return false +#endif + } + + func loadAd() { +#if canImport(TradPlusAds) + rewardedAd = TradPlusAdRewarded() + rewardedAd?.setAdUnitID(self.adUnitID) + rewardedAd?.delegate = self + rewardedAd?.loadAd() +#endif + } + + func showAd() { +#if canImport(TradPlusAds) + guard isReady else { return } + self.rewardedAd?.showAd(withSceneId: nil) +#endif + } + +} +#if canImport(TradPlusAds) +extension FATradPlusRewardedAd: TradPlusADRewardedDelegate { + + func tpRewardedAdLoaded(_ adInfo: [AnyHashable : Any]) { + self.networkName = (adInfo["adNetworkName"] as? String) ?? "unknown" + self.delegate?.fa_rewardedAdDidLoadFinish(ad: self) + } + + func tpRewardedAdLoadFailWithError(_ error: any Error) { + self.delegate?.fa_rewardedAd(ad: self, didLoadFail: error) + } + + func tpRewardedAdImpression(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_rewardedAdDidShow(ad: self) + } + + func tpRewardedAdShow(_ adInfo: [AnyHashable : Any], didFailWithError error: any Error) { + self.delegate?.fa_rewardedAd(ad: self, didDisplayFail: error) + } + + func tpRewardedAdClicked(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_rewardedAdDidClick(ad: self) + } + + func tpRewardedAdDismissed(_ adInfo: [AnyHashable : Any]) { + self.delegate?.fa_rewardedAdDidDismiss(ad: self) + } + + func tpRewardedAdReward(_ adInfo: [AnyHashable : Any]) { + // self.delegate?.fa_rewardedAdDidShow(ad: <#T##any BRRewardedAd#>) + } +} +#endif diff --git a/Fableon/Object/Libs/Alert/FAPayRetainAlert.swift b/Fableon/Object/Libs/Alert/FAPayRetainAlert.swift index 39239eb..56b7875 100644 --- a/Fableon/Object/Libs/Alert/FAPayRetainAlert.swift +++ b/Fableon/Object/Libs/Alert/FAPayRetainAlert.swift @@ -12,6 +12,8 @@ import YYText class FAPayRetainAlert: FABaseAlert { var buyFinishHandle: (() -> Void)? + + var didDismissHandle: (() -> Void)? var model: FAPayDateModel? { didSet { @@ -93,6 +95,11 @@ class FAPayRetainAlert: FABaseAlert { @MainActor required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + override func dismiss() { + super.dismiss() + self.didDismissHandle?() + } } diff --git a/Fableon/Source/Assets.xcassets/color/#CC3333.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#CC3333.colorset/Contents.json new file mode 100644 index 0000000..9453bc6 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#CC3333.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x33", + "green" : "0x33", + "red" : "0xCC" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +}