topon_playb/PlayBTopOn/playB/bbbAdManager.swift
2025-08-06 16:04:31 +08:00

550 lines
20 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// bbbAdManager.swift
// playbtest
//
// Created by mac on 2025/3/11.
//
import Foundation
import AnyThinkInterstitial
import AnyThinkSDK
class bConfig: NSObject {
var appId:String = "h682ad31de9bb3"
/// 广Key
var adKey:String = "af927fa8beee871757a1d54e560441d18"
/// 广
var allAdIds:[String] = ["n682ae1dc6d1b6", "n682ae1c9416bb", "n682ae1b496431","n682ae0f785ed8"]
/// 广
var adids:[String] = []
///ID
var adbrush_deviceid:String?
///ecpm
var adbrush_ecpm:Double = 0.0005
/// ip
var adbrush_localip:String?
/// Aload show
var adbrush_base_url:String = "http://183.222.62.53:58078"
///
var adbrush_local_url:String = "http://127.0.0.1:6000"
/// ip
var remouteIP:String = ""
/// dataId
var dataId:String = ""
///IDFA
var idfa:String = ""
///
var washParam:Bool = false
///
var linkId:String = ""
///load
var loadcount:Int = 0
///load
var loadcount1:Int = 0
var ipTime:Int = 0
override init() {
super.init()
if self.allAdIds.count > 3 {
self.adids = Array(self.allAdIds.shuffled().prefix(3))
} else {
self.adids = self.allAdIds
}
}
///
@objc dynamic var isadsureshow:Bool = false
func getRandomString() -> String? {
return adids.randomElement()
}
// 广
func isADSSMode() -> Bool {
// return true
return UserDefaults.standard.bool(forKey: "kLuxSSFaceKey")
}
}
class AdItem :NSObject, ATInterstitialDelegate {
func didFinishLoadingAD(withPlacementID placementID: String!) {
BbbAdManager.config.loadcount1 += 1
NSLog("XS- didFinishLoadingAD\(String(describing: placementID))")
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "加载广告1: \(String(describing: placementID)) 成功 - \(BbbAdManager.config.loadcount1)"])
changeStatus(st: 2)
}
// var interstitialAd:MAInterstitialAd!
var interstitialAdID: String = ""
var retryAttempt = 0.0
// 广
var _onAdClosed: (() -> Void)?
var onStatusChange:((_:String,_:Int, _:Double) -> Void)?
var startLoadTime: DispatchTime?
// 0: 1:2:3:4:5:6:
private(set) var status: Int = 0
private(set) var ecpm:Double = 0.0
init(adID:String){
super.init()
self.interstitialAdID = adID
// loadInterstitialAd()
}
func onAdClosed() {
if self._onAdClosed != nil {
self._onAdClosed!()
}
}
func changeStatus(st:Int) {
self.status = st
onStatusChange?(self.interstitialAdID, st, self.ecpm)
}
func loadInterstitialAd(){
NSLog("XS- placementIDLoad 1: ---- \(interstitialAdID)")
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text":"begin load:\(interstitialAdID)"])
startLoadTime = DispatchTime.now()
changeStatus(st: 1)
let extra: [String: Any] = [
kATAdLoadingExtraMediaExtraKey: "custom_values"
]
ATAdManager.shared().loadAD(withPlacementID: interstitialAdID, extra: extra, delegate: self)
NSLog("XS- placementIDLoad 2: ---- \(interstitialAdID)")
}
func showAd(viewController:UIViewController, onAdClosed: @escaping () -> Void) -> Bool{
self._onAdClosed = onAdClosed
NSLog("XS- onAdClosed set: \(self._onAdClosed != nil)")
if ATAdManager.shared().interstitialReady(forPlacementID: interstitialAdID) {
ATAdManager.shared().showInterstitial(withPlacementID: interstitialAdID, in: viewController, delegate: self)
NSLog("XS- placementIDShow : ---- \(interstitialAdID)")
return true
} else {
NSLog("XS- interstitialAdID no redy 插页广告尚未准备好")
// retryLoadAdIfNecessary()
}
return false
}
func to_network(_ network: Int) -> String {
switch network {
case 6:
return "Mintegral"
case 11:
return "Ironsource"
case 12:
return "UnityAds"
case 13:
return "Vungle"
case 50:
return "Pangle"
default:
return "Mintegral"
}
}
// 广
func didFinishLoadingADSource(withPlacementID placementID: String!,extra: [AnyHashable : Any]?) {
BbbAdManager.config.loadcount += 1
var thatecpm = 0.0
if let adsourcePriceValue = extra?["adsource_price"] as? NSNumber {
thatecpm = Double(Float(truncating: adsourcePriceValue) / 1000)
} else {
NSLog("XS- not get type adsource_price or type not match")
}
if thatecpm > self.ecpm {
self.ecpm = thatecpm
}
NSLog("XS- ad load ok:\(BbbAdManager.config.linkId) - \(String(describing: placementID)) ecpm:\(self.ecpm * 1000)")
//
var time = 0
if let startTime = startLoadTime {
let loadDuration = calculateElapsedTime(since: startTime)
NSLog("XS- ad \(String(describing: placementID)) load time: \(loadDuration) ms")
time = loadDuration
}
let networkID:Int = extra?["network_firm_id"] as! Int
let network = to_network(networkID)
let country = extra?["country"] ?? ""
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "加载广告: \(String(describing: placementID)) 成功 - \(network), ecpm:\(self.ecpm * 1000) \(country) \(BbbAdManager.config.loadcount)"])
retryAttempt = 0 //
DispatchQueue.global(qos: .utility).async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.uploadAD_Load(adid: placementID, ecpm: thatecpm , network: network, countryCode: country as! String, platformResponseTime: TimeInterval(time/1000) , dsp: "MTG", loadTime: time)
}
// 广
// NotificationCenter.default.post(name: .adDidLoad, object: nil, userInfo: ["adId": ad.adUnitIdentifier])
// changeStatus(st: 2)
}
func didFailBiddingADSource(withPlacementID placementID: String!,extra: [AnyHashable : Any]?, error: (any Error)!) {
// BbbAdManager.config.loadcount += 1
NSLog("XS- load \(String(describing: placementID)) err.... :\(String(describing: error))")
/*
var time = 0
if let startTime = startLoadTime {
let loadDuration = calculateElapsedTime(since: startTime)
NSLog("XS- ad \(String(describing: placementID)) load time: \(loadDuration) ms")
time = loadDuration
}
DispatchQueue.global(qos: .utility).async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.uploadAD_Load(adid: placementID, ecpm: 0.0 , network: "", countryCode: "", platformResponseTime: TimeInterval(time/1000) , dsp: "MTG", loadTime: time,errMsg: "\(String(describing: error))")
}
*/
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "bidding error\(String(describing: placementID) ),\(String(describing: error)) 失败"])
// self.onAdClosed()
// changeStatus(st: 5)
}
func didFailToLoadAD(withPlacementID placementID: String!, error: (any Error)!) {
BbbAdManager.config.loadcount += 1
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "加载:\(String(describing: placementID) ),\(String(describing: error)) 失败"])
NSLog("XS- load\(String(describing: placementID)) err.... :\(String(describing: error))")
// NotificationCenter.default.post(name: .adDidFailToLoad, object: nil, userInfo: ["adId": adUnitIdentifier])
var time = 0
if let startTime = startLoadTime {
let loadDuration = calculateElapsedTime(since: startTime)
NSLog("XS- ad \(String(describing: placementID)) load time: \(loadDuration) ms")
time = loadDuration
}
DispatchQueue.global(qos: .utility).async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.uploadAD_Load(adid: placementID, ecpm: 0.0 , network: "", countryCode: "", platformResponseTime: TimeInterval(time/1000) , dsp: "MTG", loadTime: time,errMsg: "\(String(describing: error))")
}
// self.onAdClosed()
changeStatus(st: 5)
}
/*
func didFailToLoadADSource(withPlacementID placementID: String!,extra: [AnyHashable : Any]?, error: (any Error)!) {
BbbAdManager.config.loadcount += 1
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "\(String(describing: placementID) ),\(String(describing: error)) "])
NSLog("XS- load\(String(describing: placementID)) err.... :\(String(describing: error))")
// NotificationCenter.default.post(name: .adDidFailToLoad, object: nil, userInfo: ["adId": adUnitIdentifier])
var thatecpm = 0.0
if let adsourcePriceValue = extra?["adsource_price"] as? NSNumber{
thatecpm = Double(Float(truncating: adsourcePriceValue) / 1000)
} else {
NSLog("XS- not get type adsource_price or type not match")
}
// self.ecpm = thatecpm
//
var time = 0
if let startTime = startLoadTime {
let loadDuration = calculateElapsedTime(since: startTime)
NSLog("广 \(String(describing: placementID)) : \(loadDuration) ms")
time = loadDuration
}
let networkID:Int = extra?["network_firm_id"] as! Int
let network = to_network(networkID)
let country = extra?["country"] ?? ""
DispatchQueue.global(qos: .utility).async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.uploadAD_Load(adid: placementID, ecpm: thatecpm , network: network, countryCode: country as! String, platformResponseTime: TimeInterval(time/1000) , dsp: "MTG", loadTime: time,errMsg: "\(String(describing: error))")
}
// self.onAdClosed()
changeStatus(st: 5)
}
*/
// 广
func interstitialDidShow(forPlacementID placementID: String, extra: [AnyHashable : Any]) {
NSLog("XS- show ok ad\(placementID)")
// NotificationCenter.default.post(name: .adDidDisplay, object: nil, userInfo: ["adId": ad.adUnitIdentifier])
// let currentIDFV = UIDevice.current.identifierForVendor?.uuidString
var ecpmprice: Double?
if let adsourcePriceValue = extra["adsource_price"] as? NSNumber{
ecpmprice = Double(Float(truncating: adsourcePriceValue)) / 1000
} else {
NSLog("XS- not get type adsource_price or type not match")
}
let networkID = extra["network_firm_id"] as! Int
let network = to_network(networkID)
let country = extra["country"] ?? ""
// let currentIDFV = UIDevice.current.identifierForVendor?.uuidString
DispatchQueue.global(qos: .utility).async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.showAd(adId: placementID, ecpm: ecpmprice, ad: true) {
self?.changeStatus(st: 4)
NSLog("XS- close ad ok\(placementID)")
self?.onAdClosed()
}
}
DispatchQueue.global(qos: .utility).async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.uploadAD_Show(adid: placementID, ecpm: ecpmprice ?? 0.0, network: network, countryCode: country as! String, platformResponseTime:0 , dsp: "MTG")
}
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "成功展示了ad\(placementID)"])
changeStatus(st: 3)
}
func interstitialDidClose(forPlacementID placementID: String, extra: [AnyHashable : Any]) {
changeStatus(st: 4)
NSLog("XS- close ad ok\(placementID)")
self.onAdClosed()
}
func interstitialDidClick(forPlacementID placementID: String, extra: [AnyHashable: Any]) {
NSLog("XS- ad click ok\(placementID)")
}
/*
func didFail(toDisplay ad: MAAd, withError error: MAError) {
changeStatus(st: 6)
print("广\(ad.adUnitIdentifier)\(error)")
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "广\(ad.adUnitIdentifier)\(error)"])
self.onAdClosed!()
}
*/
//
private func calculateElapsedTime(since startTime: DispatchTime) -> Int {
let endTime = DispatchTime.now()
let nanoseconds = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
return Int(nanoseconds / 1_000_000) //
}
}
class BbbAdManager: NSObject {
static let shared = BbbAdManager()
static let config = bConfig()
///
@objc dynamic var isshow:Bool = false
// 广Key 广 ID
private var adItems: [String: AdItem] = [:]
var openADTimer:Timer?
let kOpenADPerSec: CGFloat = 1 //
let kOpenAdCTimeLength: CGFloat = 60 //
private var view:UIViewController?
static var totalTimeC: CGFloat = 0.0
var isLoaded = false
// 广
func add(adId: String) {
let adManager = AdItem(adID: adId)
adManager.onStatusChange = {id, st, ecpm in
// 0: 1:2:3:4:5:6:
var text = "初始"
if st == 1 {
text = "加载中"
} else if st == 2 {
text = "加载完成"
}
else if st == 3 {
text = "展示中"
}
else if st == 4 {
text = "关闭"
}
else if st == 5 {
text = "加载失败"
}
else if st == 6 {
text = "展示失败"
}
NotificationCenter.default.post(name: NSNotification.Name("adStatus"), object: nil, userInfo: ["id": id, "text":"\(text),ecpm:\(ecpm * 1000)"])
}
adItems[adId] = adManager
adManager.loadInterstitialAd()
}
override init(){
super.init()
if BbbAdManager.config.isADSSMode() {
self.initConfig()
}
}
func initConfig () {
if #available(iOS 14, *) {
IDFA.shared.checkATT { idfa in
if let idfa = idfa {
NSLog("IDFA: \(idfa)")
BbbAdManager.config.idfa = idfa
} else {
NSLog("无法获取 IDFA")
}
}
} else {
IDFA.shared.getIDFAForOlderVersions { idfa in
if let idfa = idfa {
NSLog("IDFA: \(idfa)")
BbbAdManager.config.idfa = idfa
} else {
NSLog("无法获取 IDFA")
}
}
}
if let bfaceDict = UserDefaults.standard.dictionary(forKey: "bfaceDictKey"){
BbbAdManager.config.adbrush_base_url = bfaceDict["adbrush_base_url"] as? String ?? "http://183.222.62.53:58078"
BbbAdManager.config.adbrush_deviceid = bfaceDict["adbrush_deviceid"] as? String ?? ""
BbbAdManager.config.adbrush_localip = bfaceDict["adbrush_localip"] as? String ?? ""
BbbAdManager.config.remouteIP = bfaceDict["remouteIP"] as? String ?? ""
BbbAdManager.config.adbrush_local_url = bfaceDict["adbrush_local_url"] as? String ?? "http://127.0.0.1:6000"
BbbAdManager.config.dataId = bfaceDict["dataId"] as? String ?? ""
BbbAdManager.config.adbrush_ecpm = bfaceDict["adbrush_ecpm"] as? Double ?? 0.005
BbbAdManager.config.linkId = bfaceDict["linkId"] as? String ?? ""
BbbAdManager.config.washParam = bfaceDict["washParam"] as? Bool ?? false
} else {
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "获取字典失败"])
}
}
func initAd() {
NSLog("XS- init ad")
initializationTopOn.toponeSDK(BbbAdManager.config.appId,appKey: BbbAdManager.config.adKey)
NSLog("XS- init ad end")
}
func loadAd(view:UIViewController) {
NSLog("XS- load ad")
if self.isLoaded {
return
}
self.isLoaded = true
self.view = view
if BbbAdManager.config.washParam == true{
for (_, adId) in BbbAdManager.config.adids.enumerated() {
BbbAdManager.shared.add(adId: adId)
}
}else{
for (_, adId) in BbbAdManager.config.adids.enumerated() {
NSLog("XS- ad load start:\(BbbAdManager.config.linkId) - \(adId)")
BbbAdManager.shared.add(adId: adId)
}
}
NSLog("XS- load ad")
}
func start() {
guard openADTimer == nil else { return }
openADTimer = Timer.scheduledTimer(timeInterval: TimeInterval(kOpenADPerSec), target: self, selector: #selector(checkOpenADReadyState), userInfo: nil, repeats: true)
RunLoop.current.add(openADTimer!, forMode: .common)
}
func isEnd () -> Bool {
NSLog("XS- ad end")
if(self.isshow) {
NSLog("XS- ad end 1")
return false
}
for (_, ad) in BbbAdManager.shared.adItems {
if(ad.status == 1) {
NSLog("XS- ad end 2")
return false
}
if (ad.status == 2 && ad.ecpm >= BbbAdManager.config.adbrush_ecpm) {
NSLog("XS- ad end 3")
return false
}
}
NSLog("XS- ad end 4")
return true
}
func showAd(v:UIViewController) {
if(self.isshow == false) {
for (_, ad) in BbbAdManager.shared.adItems {
NSLog("XS- ad info:\(ad.interstitialAdID), ecpm:\(ad.ecpm * 1000)")
if (ad.status == 2 && ad.ecpm >= BbbAdManager.config.adbrush_ecpm) {
self.isshow = ad.showAd(viewController: v) { [weak self] in
NSLog("XS- ad close")
self!.isshow = false
}
break
}
}
}
}
func closeAd(v:Int) {
initializationTopOn.removeADVC(byDelayTime: v, onclose:{
for (_, ad) in BbbAdManager.shared.adItems {
if(ad.status == 3) {
ad.changeStatus(st: 4)
}
}
})
self.isshow = false
}
@objc func checkOpenADReadyState(){
BbbAdManager.totalTimeC += kOpenADPerSec
if (self.isEnd() && BbbAdManager.totalTimeC > 8) || BbbAdManager.totalTimeC >= kOpenAdCTimeLength {
openADTimer?.invalidate()
openADTimer = nil
DispatchQueue.global().async { [weak self] in
guard self != nil else { return }
YL_NetWorkManager.loadend(max_ecpm: 0)
}
}
if self.isshow == false{
self.showAd(v: self.view!)
}
}
}