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] =?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 + } +}