激励广告,开屏广告,横幅广告对接

This commit is contained in:
zjx 2025-07-15 17:19:22 +08:00
parent dba94a4e73
commit 63448e61ab
26 changed files with 764 additions and 96 deletions

View File

@ -34,11 +34,6 @@ target 'Veloria' do
pod 'FSPagerView' #banner
pod 'GoogleMobileAdsMediationAppLovin'
pod 'GoogleMobileAdsMediationIronSource'
pod 'GoogleMobileAdsMediationFacebook'
pod 'GoogleMobileAdsMediationMintegral'
pod 'GoogleMobileAdsMediationPangle'
pod 'AppLovinMediationFacebookAdapter'
pod 'AppLovinMediationByteDanceAdapter'

View File

@ -31,21 +31,6 @@ PODS:
- FSPagerView (0.8.3)
- Google-Mobile-Ads-SDK (12.7.0):
- GoogleUserMessagingPlatform (>= 1.1)
- GoogleMobileAdsMediationAppLovin (13.3.1.0):
- AppLovinSDK (= 13.3.1)
- Google-Mobile-Ads-SDK (~> 12.0)
- GoogleMobileAdsMediationFacebook (6.20.0.0):
- FBAudienceNetwork (= 6.20.0)
- Google-Mobile-Ads-SDK (~> 12.0)
- GoogleMobileAdsMediationIronSource (8.10.0.0.0):
- Google-Mobile-Ads-SDK (~> 12.0)
- IronSourceSDK (= 8.10.0.0)
- GoogleMobileAdsMediationMintegral (7.7.8.0):
- Google-Mobile-Ads-SDK (~> 12.0)
- MintegralAdSDK/All (= 7.7.8)
- GoogleMobileAdsMediationPangle (7.4.0.7.0):
- Ads-Global (= 7.4.0.7)
- Google-Mobile-Ads-SDK (~> 12.0)
- GoogleUserMessagingPlatform (3.0.0)
- HWPanModal (0.9.9)
- IronSourceAdQualitySDK (7.25.2)
@ -69,15 +54,6 @@ PODS:
- MintegralAdSDK/NativeAd (= 7.7.8)
- MintegralAdSDK/NewInterstitialAd (= 7.7.8)
- MintegralAdSDK/RewardVideoAd (= 7.7.8)
- MintegralAdSDK/All (7.7.8):
- MintegralAdSDK/BannerAd
- MintegralAdSDK/BidNativeAd
- MintegralAdSDK/InterstitialVideoAd
- MintegralAdSDK/NativeAd
- MintegralAdSDK/NativeAdvancedAd
- MintegralAdSDK/NewInterstitialAd
- MintegralAdSDK/RewardVideoAd
- MintegralAdSDK/SplashAd
- MintegralAdSDK/BannerAd (7.7.8):
- MintegralAdSDK/NativeAd
- MintegralAdSDK/BidBannerAd (7.7.8):
@ -100,8 +76,6 @@ PODS:
- MintegralAdSDK/InterstitialVideoAd (7.7.8):
- MintegralAdSDK/NativeAd
- MintegralAdSDK/NativeAd (7.7.8)
- MintegralAdSDK/NativeAdvancedAd (7.7.8):
- MintegralAdSDK/NativeAd
- MintegralAdSDK/NewInterstitialAd (7.7.8):
- MintegralAdSDK/InterstitialVideoAd
- MintegralAdSDK/NativeAd
@ -142,11 +116,6 @@ DEPENDENCIES:
- AppLovinMediationMintegralAdapter
- EmptyDataSet-Swift
- FSPagerView
- GoogleMobileAdsMediationAppLovin
- GoogleMobileAdsMediationFacebook
- GoogleMobileAdsMediationIronSource
- GoogleMobileAdsMediationMintegral
- GoogleMobileAdsMediationPangle
- HWPanModal
- Kingfisher
- KTVHTTPCache
@ -178,11 +147,6 @@ SPEC REPOS:
- FBAudienceNetwork
- FSPagerView
- Google-Mobile-Ads-SDK
- GoogleMobileAdsMediationAppLovin
- GoogleMobileAdsMediationFacebook
- GoogleMobileAdsMediationIronSource
- GoogleMobileAdsMediationMintegral
- GoogleMobileAdsMediationPangle
- GoogleUserMessagingPlatform
- HWPanModal
- IronSourceAdQualitySDK
@ -217,11 +181,6 @@ SPEC CHECKSUMS:
FBAudienceNetwork: 51d3681e66c00ee36811c0d96e9fa39d5673eba8
FSPagerView: 670405b2f18e2a87fa37f20b00de783e562c25a8
Google-Mobile-Ads-SDK: 90a3936b11fcb1a9a69b2a33fb608e793666ce73
GoogleMobileAdsMediationAppLovin: 8c4341aabacd116c36b42df5e679c173be8bce62
GoogleMobileAdsMediationFacebook: 9ca21f40f6873d557900cef231315ef21965b8c8
GoogleMobileAdsMediationIronSource: ad044b1e14fbe4768078e99a53beb906aebbc39c
GoogleMobileAdsMediationMintegral: 0aefaa2f0608c210eb26dd6a6207d8c1bd992bbd
GoogleMobileAdsMediationPangle: 2f212a58b53625c522bf4caba0e7d80699e6c0b0
GoogleUserMessagingPlatform: f8d0cdad3ca835406755d0a69aa634f00e76d576
HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2
IronSourceAdQualitySDK: 639d5a93e15e823538f87b75f3809c4905afc30b
@ -240,6 +199,6 @@ SPEC CHECKSUMS:
ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13
ZLPhotoBrowser: 20f32e6429448cc1c008795a1b55472d5772939c
PODFILE CHECKSUM: dc8e4711fa0c2059c86af834964e103b14959425
PODFILE CHECKSUM: e4a0004dc214f5060b9f7d934af7cadc1f0df315
COCOAPODS: 1.16.2

View File

@ -135,6 +135,11 @@
BF33390B2E24A86D00B10F76 /* VPAdInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33390A2E24A86D00B10F76 /* VPAdInfo.swift */; };
BF33390D2E24AA4500B10F76 /* VPGoogleRewardedAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33390C2E24AA4500B10F76 /* VPGoogleRewardedAd.swift */; };
BF33390F2E24CD8400B10F76 /* VPStatAdModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33390E2E24CD8400B10F76 /* VPStatAdModel.swift */; };
BF3339112E25FF8900B10F76 /* VPApplovinRewardedAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339102E25FF8900B10F76 /* VPApplovinRewardedAd.swift */; };
BF3339142E26249A00B10F76 /* VPApplovinAppOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339132E26249A00B10F76 /* VPApplovinAppOpenAd.swift */; };
BF3339172E2624B800B10F76 /* VPAppOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339162E2624AF00B10F76 /* VPAppOpenAdManager.swift */; };
BF33391B2E26339300B10F76 /* VPAppOpenAdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33391A2E26339300B10F76 /* VPAppOpenAdViewController.swift */; };
BF33391F2E264BE200B10F76 /* VPBannerAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33391E2E264BE200B10F76 /* VPBannerAdManager.swift */; };
BF5E75AF2DE4632200DE9DFE /* VPAboutUsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */; };
BF5E75B12DE4656600DE9DFE /* VPCampaignWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */; };
BF5E75B32DE465EC00DE9DFE /* Dictionary+SPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B22DE465EA00DE9DFE /* Dictionary+SPAdd.swift */; };
@ -422,6 +427,11 @@
BF33390A2E24A86D00B10F76 /* VPAdInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAdInfo.swift; sourceTree = "<group>"; };
BF33390C2E24AA4500B10F76 /* VPGoogleRewardedAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGoogleRewardedAd.swift; sourceTree = "<group>"; };
BF33390E2E24CD8400B10F76 /* VPStatAdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPStatAdModel.swift; sourceTree = "<group>"; };
BF3339102E25FF8900B10F76 /* VPApplovinRewardedAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPApplovinRewardedAd.swift; sourceTree = "<group>"; };
BF3339132E26249A00B10F76 /* VPApplovinAppOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPApplovinAppOpenAd.swift; sourceTree = "<group>"; };
BF3339162E2624AF00B10F76 /* VPAppOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAppOpenAdManager.swift; sourceTree = "<group>"; };
BF33391A2E26339300B10F76 /* VPAppOpenAdViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAppOpenAdViewController.swift; sourceTree = "<group>"; };
BF33391E2E264BE200B10F76 /* VPBannerAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPBannerAdManager.swift; sourceTree = "<group>"; };
BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAboutUsViewController.swift; sourceTree = "<group>"; };
BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCampaignWebViewController.swift; sourceTree = "<group>"; };
BF5E75B22DE465EA00DE9DFE /* Dictionary+SPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+SPAdd.swift"; sourceTree = "<group>"; };
@ -1199,6 +1209,8 @@
BF3339022E249DA900B10F76 /* AdManager */ = {
isa = PBXGroup;
children = (
BF33391D2E264B4C00B10F76 /* Banner */,
BF3339122E261E5600B10F76 /* AppOpen */,
BF3339052E24A24000B10F76 /* Rewarded */,
BF3339032E249F4B00B10F76 /* VPAdManager.swift */,
BF33390A2E24A86D00B10F76 /* VPAdInfo.swift */,
@ -1212,10 +1224,28 @@
children = (
BF3339062E24A2DC00B10F76 /* VPRewardedAdManager.swift */,
BF33390C2E24AA4500B10F76 /* VPGoogleRewardedAd.swift */,
BF3339102E25FF8900B10F76 /* VPApplovinRewardedAd.swift */,
);
path = Rewarded;
sourceTree = "<group>";
};
BF3339122E261E5600B10F76 /* AppOpen */ = {
isa = PBXGroup;
children = (
BF3339162E2624AF00B10F76 /* VPAppOpenAdManager.swift */,
BF3339132E26249A00B10F76 /* VPApplovinAppOpenAd.swift */,
);
path = AppOpen;
sourceTree = "<group>";
};
BF33391D2E264B4C00B10F76 /* Banner */ = {
isa = PBXGroup;
children = (
BF33391E2E264BE200B10F76 /* VPBannerAdManager.swift */,
);
path = Banner;
sourceTree = "<group>";
};
BF5E75B42DE46D9500DE9DFE /* Empty */ = {
isa = PBXGroup;
children = (
@ -1253,6 +1283,7 @@
isa = PBXGroup;
children = (
BFCCE11E2DFAD18000EDE165 /* VPGuideViewController.swift */,
BF33391A2E26339300B10F76 /* VPAppOpenAdViewController.swift */,
);
path = Guide;
sourceTree = "<group>";
@ -1596,6 +1627,7 @@
BF3339072E24A2DC00B10F76 /* VPRewardedAdManager.swift in Sources */,
BF0FA7B32DE447FE00C9E5F2 /* VPMeCell.swift in Sources */,
BF0FA6DF2DDC5E4D00C9E5F2 /* String+VPAdd.swift in Sources */,
BF3339172E2624B800B10F76 /* VPAppOpenAdManager.swift in Sources */,
BF0FA7002DDC665300C9E5F2 /* VPShortModel.swift in Sources */,
BF692AB72E06450C00A5C2DA /* VPRevolutionSelectedCell.swift in Sources */,
1B056E7B2DDB37BA007EE38D /* VPGradientView.swift in Sources */,
@ -1672,6 +1704,7 @@
BFF5AFA62DE700420044227A /* VPMeVipPrivilegeItemView.swift in Sources */,
BF5E75D12DE5692D00DE9DFE /* JXPopAnimatedTransition.swift in Sources */,
BF5E75D22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift in Sources */,
BF33391B2E26339300B10F76 /* VPAppOpenAdViewController.swift in Sources */,
BFF5B2342DEFF2030044227A /* VPDeleteAccountTipView.swift in Sources */,
BF3339012E16844B00B10F76 /* VPVideoAdSiteInfoModel.swift in Sources */,
BF5E75D32DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift in Sources */,
@ -1683,6 +1716,7 @@
BFCCE10D2DF951F600EDE165 /* SceneDelegate+APNS.swift in Sources */,
BFF5B2372DF013410044227A /* VPAlertWindowManager.swift in Sources */,
BF5E75BE2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift in Sources */,
BF3339112E25FF8900B10F76 /* VPApplovinRewardedAd.swift in Sources */,
BFF5AFB22DE7FC130044227A /* CGMutablePath+VPAdd.swift in Sources */,
BF0FA73D2DDED2D000C9E5F2 /* VPVideoAPI.swift in Sources */,
BFF5AFD42DE9A5FB0044227A /* VPVIPRecordCell.swift in Sources */,
@ -1755,6 +1789,7 @@
BF0FA7022DDC667C00C9E5F2 /* VPVideoInfoModel.swift in Sources */,
BF0FA77B2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift in Sources */,
BF0FA7BE2DE4592A00C9E5F2 /* UserDefaults+VPAdd.swift in Sources */,
BF33391F2E264BE200B10F76 /* VPBannerAdManager.swift in Sources */,
BFA21DA22E01696700B3573D /* VPStoreCoinsSmallItemView.swift in Sources */,
BFF5B2232DEEF8DA0044227A /* VPLoginButton.swift in Sources */,
BF0FA76F2DE062A700C9E5F2 /* VPRateSelectedView.swift in Sources */,
@ -1774,6 +1809,7 @@
BFF5AFCC2DE98C7F0044227A /* VPOrderRecordsViewController.swift in Sources */,
1B056E412DDAC30A007EE38D /* VPModel.swift in Sources */,
BFA21D982E01477200B3573D /* VPStoreViewController.swift in Sources */,
BF3339142E26249A00B10F76 /* VPApplovinAppOpenAd.swift in Sources */,
BF0FA70A2DDC69C800C9E5F2 /* VPTableViewCell.swift in Sources */,
BFF5B2752DF2C3750044227A /* VPDetailRecommandView.swift in Sources */,
BF0FA7A12DE1AA5100C9E5F2 /* VPTableView.swift in Sources */,
@ -1889,7 +1925,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qjwl168.veloria.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1932,7 +1968,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qjwl168.veloria.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -128,6 +128,16 @@ extension SceneDelegate {
}
window?.rootViewController = guideVc
window?.makeKeyAndVisible()
} else if !self.isOpenApp, hasOpenApp == true, VPNetworkReachabilityManager.manager.isReachable == true, VPLoginManager.manager.userInfo?.user_level == .ad {
let vc = VPAppOpenAdViewController()
vc.didEndBlock = { [weak self] in
self?.setTabBarController()
self?.vp_retryHandleOpenAppMessage()
}
window?.rootViewController = vc
window?.makeKeyAndVisible()
} else {
setTabBarController()
}

View File

@ -38,6 +38,7 @@ class VPWebView: WKWebView {
VPWebMessageOpenFeedbackList,
VPWebMessageOpenFeedbackDetail,
VPWebMessageOpenPhotoPicker,
WebMessageOpenCheckSignIn,
]

View File

@ -19,6 +19,8 @@ let VPWebMessageOpenFeedbackList: VPWebViewMessageName = "openFeedbackList"
let VPWebMessageOpenFeedbackDetail: VPWebViewMessageName = "openFeedbackDetail"
///
let VPWebMessageOpenPhotoPicker: VPWebViewMessageName = "openPhotoPicker"
///
let WebMessageOpenCheckSignIn: VPWebViewMessageName = "openCheckSignIn"
extension VPWebViewController {
@ -72,6 +74,11 @@ extension VPWebViewController {
}
}
case WebMessageOpenCheckSignIn:
self.needAutoRefresh = false
let manager = VPRewardedAdManager.manager
manager.statScene = .reward
manager.showAd(delegate: self)
default:
break
@ -125,3 +132,25 @@ extension VPWebViewController {
}
}
}
//MARK: -------------- VPRewardedAdManagerDelegate --------------
extension VPWebViewController: VPRewardedAdManagerDelegate {
func rewardedAdManager(adManager: VPRewardedAdManager, didDismiss adInfo: VPAdInfo) {
needAutoRefresh = true
let js = "uploadCheckSignIn()"
self.webView.evaluateJavaScript(js)
}
func rewardedAdManager(adManager: VPRewardedAdManager, didLoadFail error: Error) {
needAutoRefresh = true
}
func rewardedAdManager(adManager: VPRewardedAdManager, didDisplayFail error: Error) {
needAutoRefresh = true
}
func rewardedAdManager(adManager: VPRewardedAdManager, didOtherFail error: Error) {
needAutoRefresh = true
}
}

View File

@ -15,6 +15,8 @@ class VPWebViewController: VPViewController {
///
var autoTitle = true
var needAutoRefresh = true
private(set) lazy var webView: VPWebView = {
let controller = WKUserContentController()

View File

@ -0,0 +1,52 @@
//
// VPAppOpenAdViewController.swift
// Veloria
//
// Created by on 2025/7/15.
//
import UIKit
class VPAppOpenAdViewController: VPViewController {
var didEndBlock: (() -> Void)?
private(set) lazy var lanuchVC: UIViewController? = {
let vc = VPAppTool.lanuchViewController
return vc
}()
override func viewDidLoad() {
super.viewDidLoad()
if let vc = lanuchVC {
addChild(vc)
view.addSubview(vc.view)
}
let manager = VPAppOpenAdManager.manager
manager.delegate = self
manager.showAdIfAvailable()
}
}
//MARK: -------------- VPAppOpenAdManagerDelegate --------------
extension VPAppOpenAdViewController: VPAppOpenAdManagerDelegate {
func appOpenAdManagerDidDismiss(adManager: VPAppOpenAdManager) {
self.didEndBlock?()
}
func appOpenAdManager(adManager: VPAppOpenAdManager, didLoadFail error: any Error) {
self.didEndBlock?()
}
func appOpenAdManager(adManager: VPAppOpenAdManager, didDisplayFail error: any Error) {
self.didEndBlock?()
}
func appOpenAdManager(adManager: VPAppOpenAdManager, didOtherFail error: any Error) {
self.didEndBlock?()
}
}

View File

@ -53,6 +53,8 @@ class VPMeViewController: VPViewController {
vp_setupUI()
requestUserInfo()
reloadData()
}
override func viewWillAppear(_ animated: Bool) {
@ -82,14 +84,25 @@ class VPMeViewController: VPViewController {
extension VPMeViewController {
@objc private func userInfoUpdateNotification() {
self.footerView.userInfo = VPLoginManager.manager.userInfo
private func reloadData() {
let userInfo = VPLoginManager.manager.userInfo
if userInfo?.user_level == .ad {
self.tableView.tableFooterView = nil
} else {
self.footerView.userInfo = VPLoginManager.manager.userInfo
self.tableView.tableFooterView = self.footerView
}
self.dataArr = createDataArr()
self.tableView.reloadData()
}
@objc private func userInfoUpdateNotification() {
reloadData()
}
@objc private func loginStateDidChangeNotification() {
self.dataArr = createDataArr()
self.tableView.reloadData()
reloadData()
}
private func showVipAlert() {
@ -126,8 +139,6 @@ extension VPMeViewController {
extension VPMeViewController {
private func vp_setupUI() {
tableView.tableFooterView = self.footerView
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
@ -152,6 +163,8 @@ extension VPMeViewController: UITableViewDelegate, UITableViewDataSource {
cell.userInfo = VPLoginManager.manager.userInfo
} else if let cell = cell as? VPMeVipCell {
cell.userInfo = VPLoginManager.manager.userInfo
} else if let cell = cell as? VPMeToolCell {
cell.userInfo = VPLoginManager.manager.userInfo
}
return cell
@ -236,19 +249,27 @@ extension VPMeViewController {
[
VPMeItem(cellKey: .userInfo),
],
[
VPMeItem(cellKey: .vip)
],
[
VPMeItem(cellKey: .coin)
],
[
VPMeItem(cellKey: .tool)
]
]
if VPLoginManager.manager.userInfo?.user_level != .ad {
dataArr.append([
VPMeItem(cellKey: .vip)
])
dataArr.append([
VPMeItem(cellKey: .coin)
])
}
dataArr.append([
VPMeItem(cellKey: .tool)
])
var cellArr: [VPMeItem] = []
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_07"), title: "veloria_order_record".localized, type: .orderRecord, cellKey: .normal))
if VPLoginManager.manager.userInfo?.user_level != .ad {
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_07"), title: "veloria_order_record".localized, type: .orderRecord, cellKey: .normal))
}
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "veloria_language".localized, type: .language, cellKey: .normal))
if VPLoginManager.manager.userInfo?.is_tourist == false {
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_06"), title: "veloria_delete_account".localized, type: .deleteAccount, cellKey: .normal))

View File

@ -9,9 +9,20 @@ import UIKit
class VPMeToolCell: VPTableViewCell {
var userInfo: VPUserInfo? {
didSet {
stackView.removeAllArrangedSubview()
if userInfo?.user_level != .ad {
stackView.addArrangedSubview(walletButton)
stackView.addArrangedSubview(storeButton)
}
stackView.addArrangedSubview(rewardsButton)
stackView.addArrangedSubview(favoritesButton)
}
}
private lazy var stackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [walletButton, storeButton, rewardsButton, favoritesButton])
let view = UIStackView()
view.axis = .horizontal
view.distribution = .fillEqually
view.alignment = .center

View File

@ -149,6 +149,15 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
}
override func handleBack() {
super.handleBack()
if VPLoginManager.manager.userInfo?.user_level == .ad {
if VPRewardedAdManager.manager.isReady {
VPRewardedAdManager.manager.showAd()
}
}
}
}

View File

@ -41,6 +41,10 @@ class VPDetailRecommandView: HWPanModalContentView {
}
}
private lazy var bannerAd: VPBannerAdManager = {
let ad = VPBannerAdManager()
return ad
}()
//MARK: UI
private lazy var bgView: UIView = {
@ -152,7 +156,11 @@ class VPDetailRecommandView: HWPanModalContentView {
//MARK: HWPanModalPresentable
override func longFormHeight() -> PanModalHeight {
return PanModalHeightMake(.content, 473 + UIScreen.tabbarSafeBottomMargin)
if VPLoginManager.manager.userInfo?.user_level == .ad {
return PanModalHeightMake(.content, 473 + bannerAd.size.height + UIScreen.tabbarSafeBottomMargin)
} else {
return PanModalHeightMake(.content, 473 + UIScreen.tabbarSafeBottomMargin)
}
}
override func showDragIndicator() -> Bool {
@ -217,6 +225,10 @@ extension VPDetailRecommandView {
@objc private func handleCloseButton() {
self.clickCloseButton?()
if VPLoginManager.manager.userInfo?.user_level == .ad {
self.bannerAd.requestStatAd(type: "close", errorMsg: nil)
}
self.dismiss(animated: true) {
}
@ -284,6 +296,16 @@ extension VPDetailRecommandView {
make.top.equalTo(bannerView.snp.bottom).offset(74)
}
if VPLoginManager.manager.userInfo?.user_level == .ad {
addSubview(bannerAd.adView)
bannerAd.adView.snp.makeConstraints { make in
make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin))
make.centerX.equalToSuperview()
make.size.equalTo(self.bannerAd.size)
}
}
}
}

View File

@ -119,7 +119,11 @@ class VPVideoLockView: UIView {
}
@objc private func handleAdUnlockButton() {
self.clickAdUnlockButton?()
if hasLastEpisodeUnlocked {
VPToast.show(text: "veloria_jump_unlock_error".localized)
} else {
self.clickAdUnlockButton?()
}
}
@objc private func userInfoUpdateNotification() {

View File

@ -167,8 +167,10 @@ extension VPVideoPlayViewModel {
}
//MARK: -------------- VPRewardedAdDelegate --------------
extension VPVideoPlayViewModel: VPRewardedAdDelegate {
func rewardedAd(ad: VPRewardedAd, userDidEarnReward adInfo: VPAdInfo) {
extension VPVideoPlayViewModel: VPRewardedAdManagerDelegate {
func rewardedAdManager(adManager: VPRewardedAdManager, didDismiss adInfo: VPAdInfo) {
let videoInfo = self.currentPlayer?.videoInfo
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
@ -182,6 +184,7 @@ extension VPVideoPlayViewModel: VPRewardedAdDelegate {
self.videoUnlockFinishBlock?()
}
}
}
}

View File

@ -22,7 +22,9 @@ class VPRewardsViewController: VPCampaignWebViewController {
override func viewDidAppear(_ animated: Bool) {
if hasViewDidAppear {
self.reload()
if needAutoRefresh {
self.reload()
}
}
super.viewDidAppear(animated)
}

View File

@ -0,0 +1,164 @@
//
// VPAppOpenAdManager.swift
// Veloria
//
// Created by on 2025/7/15.
//
import UIKit
@objc protocol VPAppOpenAdManagerDelegate: NSObjectProtocol {
///广
@objc optional func appOpenAdManagerDidLoadFinish(adManager: VPAppOpenAdManager)
///广
@objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didLoadFail error: Error)
///广
@objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didDisplayFail error: Error)
///广
@objc optional func appOpenAdManagerDidShow(adManager: VPAppOpenAdManager)
///广
@objc optional func appOpenAdManagerDidDismiss(adManager: VPAppOpenAdManager)
///广
@objc optional func appOpenAdManagerDidClick(adManager: VPAppOpenAdManager)
///
@objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didOtherFail error: Error)
}
@objc protocol VPAppOpenAdDelegate: NSObjectProtocol {
///广
@objc optional func appOpenAd(ad: VPAppOpenAd, didLoadFail error: Error)
///广
@objc optional func appOpenAdDidLoadFinish(ad: VPAppOpenAd)
///广
@objc optional func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error)
///广
@objc optional func appOpenAdDidShow(ad: VPAppOpenAd)
///广
@objc optional func appOpenAdDidDismiss(ad: VPAppOpenAd)
///广
@objc optional func appOpenAdDidClick(ad: VPAppOpenAd)
}
@objc protocol VPAppOpenAd: NSObjectProtocol {
weak var delegate: VPAppOpenAdDelegate? { get set }
var adPlatformKey: String { get }
var adUnitID: String { get }
var isReady: Bool { get }
func loadAd()
func showAd()
}
class VPAppOpenAdManager: NSObject {
static let manager = VPAppOpenAdManager()
weak var delegate: VPAppOpenAdManagerDelegate?
private(set) var appOpenAd: VPAppOpenAd? {
didSet {
oldValue?.delegate = nil
appOpenAd?.delegate = self
}
}
private var isLoading = false
deinit {
NotificationCenter.default.removeObserver(self)
}
override init() {
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
func showAdIfAvailable() {
guard !isLoading else { return }
self.isLoading = true
appOpenAd = VPApplovinAppOpenAd()
appOpenAd?.loadAd()
}
private func clean() {
appOpenAd = nil
delegate = nil
isLoading = false
}
}
//MARK: -------------- VPAppOpenAdDelegate --------------
extension VPAppOpenAdManager: VPAppOpenAdDelegate {
///广
func appOpenAd(ad: VPAppOpenAd, didLoadFail error: Error) {
requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
self.delegate?.appOpenAdManager?(adManager: self, didLoadFail: error)
clean()
}
///广
func appOpenAdDidLoadFinish(ad: VPAppOpenAd) {
self.delegate?.appOpenAdManagerDidLoadFinish?(adManager: self)
self.appOpenAd?.showAd()
}
///广
func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error) {
requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
self.delegate?.appOpenAdManager?(adManager: self, didDisplayFail: error)
clean()
}
///广
func appOpenAdDidShow(ad: VPAppOpenAd) {
requestStatAd(type: "start", errorMsg: nil)
self.delegate?.appOpenAdManagerDidShow?(adManager: self)
}
///广
func appOpenAdDidDismiss(ad: VPAppOpenAd) {
requestStatAd(type: "close", errorMsg: nil)
self.delegate?.appOpenAdManagerDidDismiss?(adManager: self)
clean()
}
///广
func appOpenAdDidClick(ad: VPAppOpenAd) {
requestStatAd(type: "click", errorMsg: nil)
self.delegate?.appOpenAdManagerDidClick?(adManager: self)
}
}
extension VPAppOpenAdManager {
private func requestStatAd(type: String, errorMsg: String?) {
guard let appOpenAd = self.appOpenAd else { return }
let model = VPStatAdModel()
model.type = type
model.ads_id = appOpenAd.adUnitID
model.ad_platform_key = VPAdPlatformKey(rawValue: appOpenAd.adPlatformKey)
model.error_msg = errorMsg
model.scene = .splash
VPStatAPI.requestStatAd(model: model)
}
@objc private func didEnterBackgroundNotification() {
self.requestStatAd(type: "Interrupt", errorMsg: nil)
}
}

View File

@ -0,0 +1,84 @@
//
// VPApplovinAppOpenAd.swift
// Veloria
//
// Created by on 2025/7/15.
//
import UIKit
#if canImport(AppLovinSDK)
import AppLovinSDK
#endif
class VPApplovinAppOpenAd: NSObject, VPAppOpenAd {
private lazy var appOpenAd = MAAppOpenAd(adUnitIdentifier: adUnitID)
weak var delegate: (any VPAppOpenAdDelegate)?
var adPlatformKey: String {
return VPAdPlatformKey.applovin.rawValue
}
var adUnitID: String {
return VPAdManager.applovin_appOpenAdUnitID
}
var isReady: Bool {
if ALSdk.shared().isInitialized && appOpenAd.isReady {
return true
} else {
return false
}
}
func loadAd() {
VPAdManager.initialize_applovinSdk { [weak self] in
guard let self = self else { return }
appOpenAd.delegate = self
appOpenAd.load()
}
}
func showAd() {
guard isReady else { return }
appOpenAd.show()
}
}
extension VPApplovinAppOpenAd: MAAdDelegate {
func didLoad(_ ad: MAAd) {
self.delegate?.appOpenAdDidLoadFinish?(ad: self)
}
func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
let nsError = NSError(domain: error.message, code: error.code.rawValue)
self.delegate?.appOpenAd?(ad: self, didLoadFail: nsError)
}
func didDisplay(_ ad: MAAd) {
self.delegate?.appOpenAdDidShow?(ad: self)
}
func didHide(_ ad: MAAd) {
self.delegate?.appOpenAdDidDismiss?(ad: self)
}
func didClick(_ ad: MAAd) {
self.delegate?.appOpenAdDidClick?(ad: self)
}
func didFail(toDisplay ad: MAAd, withError error: MAError) {
let nsError = NSError(domain: error.message, code: error.code.rawValue)
self.delegate?.appOpenAd?(ad: self, didDisplayFail: nsError)
}
}

View File

@ -0,0 +1,94 @@
//
// VPBannerAdManager.swift
// Veloria
//
// Created by on 2025/7/15.
//
import UIKit
#if canImport(AppLovinSDK)
import AppLovinSDK
#endif
class VPBannerAdManager: NSObject {
let adUnitID = VPAdManager.applovin_bannerAdUnitID
let size = CGSize.init(width: UIScreen.width, height: 59)
private(set) lazy var adView: MAAdView = {
let view = MAAdView(adUnitIdentifier: adUnitID)
view.frame = .init(x: 0, y: 0, width: size.width, height: size.height)
view.delegate = self
return view
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
override init() {
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
self.adView.loadAd()
}
}
//MARK: -------------- MAAdViewAdDelegate --------------
extension VPBannerAdManager: MAAdViewAdDelegate {
func didExpand(_ ad: MAAd) {
}
func didCollapse(_ ad: MAAd) {
}
func didLoad(_ ad: MAAd) {
requestStatAd(type: "start", errorMsg: nil)
}
func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
requestStatAd(type: "load_failed", errorMsg: error.message)
}
func didDisplay(_ ad: MAAd) {
}
func didHide(_ ad: MAAd) {
requestStatAd(type: "close", errorMsg: nil)
}
func didClick(_ ad: MAAd) {
requestStatAd(type: "click", errorMsg: nil)
}
func didFail(toDisplay ad: MAAd, withError error: MAError) {
requestStatAd(type: "show_failed", errorMsg: error.message)
}
}
extension VPBannerAdManager {
func requestStatAd(type: String, errorMsg: String?) {
let model = VPStatAdModel()
model.type = type
model.ads_id = adUnitID
model.ad_platform_key = .applovin
model.error_msg = errorMsg
model.scene = .banner
VPStatAPI.requestStatAd(model: model)
}
@objc private func didEnterBackgroundNotification() {
self.requestStatAd(type: "Interrupt", errorMsg: nil)
}
}

View File

@ -0,0 +1,91 @@
//
// VPApplovinRewardedAd.swift
// Veloria
//
// Created by on 2025/7/15.
//
import UIKit
#if canImport(AppLovinSDK)
import AppLovinSDK
#endif
class VPApplovinRewardedAd: NSObject, VPRewardedAd {
#if canImport(AppLovinSDK)
private var rewardedAd: MARewardedAd?
#endif
weak var delegate: (any VPRewardedAdDelegate)?
var adInfo: VPAdInfo?
var isReady: Bool {
#if canImport(AppLovinSDK)
return rewardedAd?.isReady ?? false
#else
return false
#endif
}
func loadAd(adInfo: VPAdInfo) {
self.adInfo = adInfo
#if canImport(AppLovinSDK)
rewardedAd = MARewardedAd.shared(withAdUnitIdentifier: adInfo.ads_id ?? "")
rewardedAd?.delegate = self
rewardedAd?.load()
#endif
}
func showAd() {
#if canImport(AppLovinSDK)
if isReady {
rewardedAd?.show()
}
#endif
}
}
#if canImport(AppLovinSDK)
//MARK: -------------- MARewardedAdDelegate --------------
extension VPApplovinRewardedAd: MARewardedAdDelegate {
func didLoad(_ ad: MAAd) {
self.delegate?.rewardedAdDidLoadFinish?(ad: self)
}
func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
let nsError = NSError(domain: error.message, code: error.code.rawValue)
self.delegate?.rewardedAd?(ad: self, didLoadFail: nsError)
}
func didDisplay(_ ad: MAAd) {
self.delegate?.rewardedAdDidShow?(ad: self)
}
func didHide(_ ad: MAAd) {
self.delegate?.rewardedAdDidDismiss?(ad: self)
}
func didClick(_ ad: MAAd) {
self.delegate?.rewardedAdDidClick?(ad: self)
}
func didFail(toDisplay ad: MAAd, withError error: MAError) {
let nsError = NSError(domain: error.message, code: error.code.rawValue)
self.delegate?.rewardedAd?(ad: self, didDisplayFail: nsError)
}
func didRewardUser(for ad: MAAd, with reward: MAReward) {
if let adInfo = self.adInfo {
self.delegate?.rewardedAd?(ad: self, userDidEarnReward: adInfo)
}
}
}
#endif

View File

@ -6,12 +6,11 @@
//
import UIKit
#if canImport(GoogleMobileAds)
import GoogleMobileAds
#endif
class VPGoogleRewardedAd: VPModel, VPRewardedAd {
class VPGoogleRewardedAd: NSObject, VPRewardedAd {

View File

@ -7,6 +7,28 @@
import UIKit
@objc protocol VPRewardedAdManagerDelegate: NSObjectProtocol {
///
@objc optional func rewardedAdManager(adManager: VPRewardedAdManager, userDidEarnReward adInfo: VPAdInfo)
///广
@objc optional func rewardedAdManagerDidLoadFinish(adManager: VPRewardedAdManager)
///广
@objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didLoadFail error: Error)
///广
@objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didDisplayFail error: Error)
///广
@objc optional func rewardedAdManagerDidShow(adManager: VPRewardedAdManager)
///广
@objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didDismiss adInfo: VPAdInfo)
///广
@objc optional func rewardedAdManagerDidClick(adManager: VPRewardedAdManager)
///
@objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didOtherFail error: Error)
}
@objc protocol VPRewardedAdDelegate: NSObjectProtocol {
///
@ -40,7 +62,7 @@ class VPRewardedAdManager: NSObject {
static let manager = VPRewardedAdManager()
private weak var delegate: VPRewardedAdDelegate?
private weak var delegate: VPRewardedAdManagerDelegate?
///广
private var isLoadingAd = false
@ -92,6 +114,11 @@ class VPRewardedAdManager: NSObject {
self.rewardedAd = ad
ad.loadAd(adInfo: adInfo)
case .applovin:
let ad = VPApplovinRewardedAd()
self.rewardedAd = ad
ad.loadAd(adInfo: adInfo)
default:
self.adInfo = nil
break
@ -99,13 +126,15 @@ class VPRewardedAdManager: NSObject {
}
}
func showAd(delegate: VPRewardedAdDelegate? = nil) {
func showAd(delegate: VPRewardedAdManagerDelegate? = nil) {
if isEnable && !isLoadingAd && !isReady {//广广广
loadAd()
}
if !isEnable || !isReady {
VPToast.show(text: "veloria_no_ads_tip".localized)
let error = NSError(domain: "veloria_no_ads_tip".localized, code: -1)
self.delegate?.rewardedAdManager?(adManager: self, didOtherFail: error)
return
}
@ -130,7 +159,7 @@ extension VPRewardedAdManager: VPRewardedAdDelegate {
///
func rewardedAd(ad: VPRewardedAd, userDidEarnReward adInfo: VPAdInfo) {
self.requestStatAd(type: "reward", errorMsg: nil)
self.delegate?.rewardedAd?(ad: ad, userDidEarnReward: adInfo)
self.delegate?.rewardedAdManager?(adManager: self, userDidEarnReward: adInfo)
}
///广
func rewardedAd(ad: VPRewardedAd, didLoadFail error: Error) {
@ -138,7 +167,7 @@ extension VPRewardedAdManager: VPRewardedAdDelegate {
isLoadingAd = false
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
self.delegate?.rewardedAd?(ad: ad, didLoadFail: error)
self.delegate?.rewardedAdManager?(adManager: self, didLoadFail: error)
self.clean()
}
@ -146,14 +175,14 @@ extension VPRewardedAdManager: VPRewardedAdDelegate {
func rewardedAdDidLoadFinish(ad: VPRewardedAd) {
isLoadingAd = false
self.delegate?.rewardedAdDidLoadFinish?(ad: ad)
self.delegate?.rewardedAdManagerDidLoadFinish?(adManager: self)
}
///广
func rewardedAd(ad: VPRewardedAd, didDisplayFail error: Error) {
isEnable = false
self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
self.delegate?.rewardedAd?(ad: ad, didDisplayFail: error)
self.delegate?.rewardedAdManager?(adManager: self, didDisplayFail: error)
self.clean()
}
@ -162,7 +191,7 @@ extension VPRewardedAdManager: VPRewardedAdDelegate {
self.adsDate = Date()
self.requestStatAd(type: "start", errorMsg: nil)
self.delegate?.rewardedAdDidShow?(ad: ad)
self.delegate?.rewardedAdManagerDidShow?(adManager: self)
}
///广
func rewardedAdDidDismiss(ad: VPRewardedAd) {
@ -172,9 +201,13 @@ extension VPRewardedAdManager: VPRewardedAdDelegate {
if let adsDate = self.adsDate {
seconds = Int(Date().timeIntervalSince(adsDate))
}
self.requestStatAd(type: "close", seconds: seconds, errorMsg: nil) { [weak self] in
guard let self = self else { return }
self.delegate?.rewardedAdDidDismiss?(ad: ad)
if let adInfo = ad.adInfo {
self.delegate?.rewardedAdManager?(adManager: self, didDismiss: adInfo)
}
self.clean()
//广
@ -192,7 +225,7 @@ extension VPRewardedAdManager: VPRewardedAdDelegate {
}
self.requestStatAd(type: "click", seconds: seconds, errorMsg: nil)
self.delegate?.rewardedAdDidClick?(ad: ad)
self.delegate?.rewardedAdManagerDidClick?(adManager: self)
}
}

View File

@ -16,24 +16,39 @@ import AppLovinSDK
class VPAdManager: NSObject {
static var completer: (() -> Void)?
static func start() {
#if canImport(GoogleMobileAds)
MobileAds.shared.start()
#endif
/*
//
let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in
builder.mediationProvider = ALMediationProviderMAX
#if DEBUG
builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()]
#endif
}
ALSdk.shared().initialize(with: initConfig) { sdkConfig in
// Start loading ads
initialize_applovinSdk()
}
///AppLovinSDK
static func initialize_applovinSdk(completer: (() -> Void)? = nil) {
if completer != nil {
self.completer = completer
}
*/
#if canImport(AppLovinSDK)
if !ALSdk.shared().isInitialized {
//
let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in
builder.mediationProvider = ALMediationProviderMAX
#if DEBUG
builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()]
#endif
}
ALSdk.shared().initialize(with: initConfig) { sdkConfig in
// Start loading ads
self.completer?()
}
} else {
self.completer?()
}
#endif
}
}
@ -67,5 +82,14 @@ extension VPAdManager {
#endif
}
///广ID
static var applovin_appOpenAdUnitID: String {
return "d587df0fd75ff03b"
}
///广ID
static var applovin_bannerAdUnitID: String {
return "1eb6278843149711"
}
}

View File

@ -21,7 +21,7 @@ class VPStatAdModel: VPModel, SmartCodable {
var type: String? //start click error click show_failed load_failed Interrupt(退) close
var ads_id: String?
var view_seconds: Int?
var ad_platform_key:VPAdPlatformKey?
var ad_platform_key: VPAdPlatformKey?
var scene: AdScene? // splash reward banner detail me turntable
var short_play_id: String?
var short_play_video_id: String?

View File

@ -47,6 +47,16 @@ class JXIAPManager: NSObject {
private var product: SKProduct?
private var productId: String?
/*
let discount = SKPaymentDiscount(
identifier: offerIdentifier,// ID
keyIdentifier: keyIdentifier, //ID
nonce: UUID(), //
signature: signature, //
timestamp: timestamp //
)
*/
private var discount: SKPaymentDiscount?
private var orderId: String?
private var applicationUsername: String? {
get {
@ -80,10 +90,11 @@ class JXIAPManager: NSObject {
SKPaymentQueue.default().add(self)
}
func start(productId: String, orderId: String) {
func start(productId: String, orderId: String, discount: SKPaymentDiscount? = nil) {
self.product = nil
self.productId = productId
self.orderId = orderId
self.discount = discount
let set = Set([productId])
let productsRequest = SKProductsRequest(productIdentifiers: set)
@ -98,8 +109,12 @@ class JXIAPManager: NSObject {
//
let payment = SKMutablePayment(product: product)
payment.applicationUsername = applicationUsername
if let discount = self.discount {
payment.paymentDiscount = discount
}
self.payment = payment
//
SKPaymentQueue.default().add(payment)
}

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgFunGcNwcsaFT875o
zGS8jL4l771Th8a/UBOZvohPuDWgCgYIKoZIzj0DAQehRANCAARUJueeGOqNXQm1
sVYhlmcDDhvlEinF1N8EFfh2wTKiTgWzscuYAUZkwI75aLkvwNaMllYcaJ+LuuBS
HZpG+bR9
-----END PRIVATE KEY-----

View File

@ -0,0 +1,2 @@
Issuer ID: 543348c9-2f43-4dd3-80b4-38a48b70c73c
密钥ID: X937MMWD5B