2025-09-01 15:57:10 +00:00
using System ;
2025-08-30 13:48:51 +00:00
using System.Collections ;
using System.Collections.Generic ;
2025-09-01 15:57:10 +00:00
using System.Linq ;
2025-09-15 15:12:13 +00:00
using EFSDK ;
2025-09-01 15:57:10 +00:00
using GoogleMobileAds.Api ;
2025-08-30 13:48:51 +00:00
using UnityEngine ;
2025-09-01 10:32:50 +00:00
namespace WZ
2025-09-01 15:57:10 +00:00
{
2025-09-15 15:12:13 +00:00
class ShowNativePosition
{
public NativeOverlayAd NativeOverlayAd ;
public NativeAdPosition Position ;
public ShowNativePosition ( NativeOverlayAd nativeOverlayAd , NativeAdPosition position )
{
NativeOverlayAd = nativeOverlayAd ;
Position = position ;
}
}
2025-09-01 15:57:10 +00:00
public class AdmobNativeAdManager
2025-08-30 13:48:51 +00:00
{
2025-09-01 15:57:10 +00:00
private Dictionary < string , NativeOverlayAd > _nativeAds = new Dictionary < string , NativeOverlayAd > ( ) ;
private Dictionary < string , double > _adRevenueCache = new Dictionary < string , double > ( ) ;
private Dictionary < string , int > _retryCounters = new Dictionary < string , int > ( ) ;
2025-09-03 08:56:30 +00:00
private Dictionary < string , float > _adStartLoadTimes = new Dictionary < string , float > ( ) ;
2025-09-15 15:12:13 +00:00
private Dictionary < string , ShowNativePosition > showingNativeAds = new ( ) ;
2025-09-03 05:42:30 +00:00
2025-09-01 15:57:10 +00:00
public void InitializeAdUnits ( List < string > adUnitIds )
{
foreach ( var adUnitId in adUnitIds )
{
CreateNativeAd ( adUnitId ) ;
}
}
private void CreateNativeAd ( string adUnitId )
2025-08-31 13:19:46 +00:00
{
2025-09-10 06:33:32 +00:00
if ( string . IsNullOrEmpty ( adUnitId ) ) return ;
2025-09-01 15:57:10 +00:00
if ( _nativeAds . ContainsKey ( adUnitId ) )
{
LoggerUtils . Debug ( $"[Admob] Native Ad unit {adUnitId} already exists" ) ;
return ;
}
2025-08-30 13:48:51 +00:00
2025-09-01 15:57:10 +00:00
LoadAd ( adUnitId ) ;
_adRevenueCache [ adUnitId ] = 0 ;
2025-08-31 13:19:46 +00:00
}
2025-09-15 15:12:13 +00:00
public void LoadAd ( string adUnitId , bool timingRefresh = false )
2025-08-31 13:19:46 +00:00
{
2025-09-15 15:12:13 +00:00
LoggerUtils . Debug ( $"[Admob] Native Ad unit {adUnitId} load start , timingRefresh {timingRefresh}" ) ;
2025-09-10 09:54:52 +00:00
//判断在线参数是否包含这个id
if ( ! AdmobAdsManager . Instance . FindAdsID ( AdsType . Native , adUnitId ) )
{
return ;
}
2025-09-01 15:57:10 +00:00
NativeOverlayAd . Load ( adUnitId , new AdRequest ( ) , new NativeAdOptions ( ) , ( NativeOverlayAd ad , LoadAdError error ) = >
{
2025-09-03 05:42:30 +00:00
_adStartLoadTimes [ adUnitId ] = Time . realtimeSinceStartup ;
2025-09-15 15:12:13 +00:00
LoggerUtils . Debug ( $"[Admob] Native Ad unit {adUnitId} load end, timingRefresh {timingRefresh}. {ad} error {error}" ) ;
2025-09-01 15:57:10 +00:00
if ( error ! = null | | ad = = null )
{
2025-09-17 10:42:58 +00:00
if ( ! timingRefresh )
2025-09-02 02:07:10 +00:00
{
2025-09-17 10:42:58 +00:00
if ( ! _retryCounters . TryAdd ( adUnitId , 0 ) )
{
_retryCounters [ adUnitId ] + + ;
}
2025-09-02 02:07:10 +00:00
}
2025-09-03 08:56:30 +00:00
2025-09-17 10:42:58 +00:00
2025-09-03 08:56:30 +00:00
var adSource = "" ;
if ( ad ! = null )
{
adSource = ad . GetResponseInfo ( ) . GetLoadedAdapterResponseInfo ( ) . AdSourceName ;
}
var reason = "" ;
if ( error ! = null )
{
reason = error . GetMessage ( ) ;
}
2025-09-03 05:42:30 +00:00
AdsActionEvents . TrackAdFailToLoad ( PlatformType . Admob ,
2025-09-03 08:56:30 +00:00
adSource ,
2025-09-03 05:42:30 +00:00
adUnitId ,
AdsType . Native ,
2025-09-04 09:19:05 +00:00
Time . realtimeSinceStartup - _adStartLoadTimes [ adUnitId ] ,
reason ) ;
2025-09-03 08:56:30 +00:00
2025-09-17 10:42:58 +00:00
// 定时任务的刷新,由定时任务自己去刷新
if ( timingRefresh )
{
if ( ! showingNativeAds . ContainsKey ( adUnitId ) )
{
LoggerUtils . Debug ( $"[Admob] Native Ad unit {adUnitId}, 已经隐藏了, 失败了也不需要在重新load了" ) ;
return ;
}
TimingRefresh ( adUnitId ) ;
return ;
}
2025-09-01 15:57:10 +00:00
var retryDelay = Math . Pow ( 2 , Math . Min ( 6 , _retryCounters [ adUnitId ] ) ) ;
2025-09-17 10:42:58 +00:00
TimerUtils . Instance . DelayExecute ( ( float ) retryDelay , ( ) = > { LoadAd ( adUnitId ) ; } ) ;
2025-09-15 15:12:13 +00:00
LoggerUtils . Error ( $"[Admob] Native Ad unit {adUnitId}, timingRefresh {timingRefresh} ad failed to load an ad with error : " + error + " \n retryDelay :" + retryDelay ) ;
2025-09-01 15:57:10 +00:00
return ;
}
2025-09-15 07:55:38 +00:00
2025-09-10 09:54:52 +00:00
if ( ! AdmobAdsManager . Instance . FindAdsID ( AdsType . Native , adUnitId ) )
{
return ;
}
2025-09-03 08:56:30 +00:00
2025-09-03 05:42:30 +00:00
AdsActionEvents . TrackAdLoaded ( PlatformType . Admob ,
ad . GetResponseInfo ( ) . GetLoadedAdapterResponseInfo ( ) . AdSourceName ,
adUnitId ,
AdsType . Native ,
Time . realtimeSinceStartup - _adStartLoadTimes [ adUnitId ] ) ;
2025-09-01 15:57:10 +00:00
_retryCounters [ adUnitId ] = 0 ;
2025-09-15 15:12:13 +00:00
// 临时缓存上一次的native ad, 以便于刷新的时候, 显示了新的, 隐藏老的。
var tempAd = _nativeAds . GetValueOrDefault ( adUnitId , null ) ;
2025-09-02 08:22:20 +00:00
var nativeEcpm = AdmobUtils . GetNativeEcpm ( ad ) ;
2025-09-01 15:57:10 +00:00
_nativeAds [ adUnitId ] = ad ;
2025-09-02 08:22:20 +00:00
_adRevenueCache [ adUnitId ] = nativeEcpm ;
2025-09-15 15:12:13 +00:00
LoggerUtils . Debug ( $"Admob Native ad loaded with, timingRefresh {timingRefresh} nativeEcpm = {nativeEcpm} response : " + ad . GetResponseInfo ( ) . ToString ( ) ) ;
2025-09-01 15:57:10 +00:00
AdsKeyEvents . Instance . LogAdFPUEvents ( AdsType . Native ) ;
2025-08-31 13:19:46 +00:00
2025-09-01 15:57:10 +00:00
ad . OnAdPaid + = ( AdValue adValue ) = >
{
LoggerUtils . Debug ( $"[Admob] Native ad paid {adValue.Value} {adValue.CurrencyCode}." ) ;
AdmobAdsManager . Instance . TrackAdImpression ( ad . GetResponseInfo ( ) . GetLoadedAdapterResponseInfo ( ) ,
adValue ,
AdsType . Native ,
2025-09-02 13:42:07 +00:00
adUnitId ) ;
2025-09-01 15:57:10 +00:00
} ;
ad . OnAdImpressionRecorded + = ( ) = > { LoggerUtils . Debug ( "[Admob] Native ad recorded an impression." ) ; } ;
2025-09-03 05:42:30 +00:00
ad . OnAdClicked + = ( ) = >
{
AdsActionEvents . TrackAdClicked ( PlatformType . Admob ,
ad . GetResponseInfo ( ) . GetLoadedAdapterResponseInfo ( ) . AdSourceName ,
adUnitId ,
AdsType . Native ,
"" ,
AdmobUtils . GetNativeEcpm ( ad ) ) ;
LoggerUtils . Debug ( "[Admob] Native ad was clicked." ) ;
} ;
2025-09-01 15:57:10 +00:00
ad . OnAdFullScreenContentOpened + = ( ) = > { LoggerUtils . Debug ( "[Admob] Native ad full screen content opened." ) ; } ;
2025-09-03 08:56:30 +00:00
ad . OnAdFullScreenContentClosed + = ( ) = >
{
2025-09-03 05:42:30 +00:00
AdsActionEvents . TrackAdClicked ( PlatformType . Admob ,
ad . GetResponseInfo ( ) . GetLoadedAdapterResponseInfo ( ) . AdSourceName ,
adUnitId ,
AdsType . Native ,
"" ,
AdmobUtils . GetNativeEcpm ( ad ) ) ;
2025-09-03 08:56:30 +00:00
LoggerUtils . Debug ( "[Admob] Native ad full screen content closed." ) ;
} ;
2025-09-15 15:12:13 +00:00
if ( timingRefresh & & tempAd ! = null )
{
if ( showingNativeAds . TryGetValue ( adUnitId , out var showing ) )
{
2025-09-17 10:30:03 +00:00
var showingNativeOverlayAd = showing . NativeOverlayAd ;
if ( showingNativeOverlayAd ! = tempAd )
{
LoggerUtils . Error ( "[Admob] Native ad Error!!!! showing.NativeOverlayAd != tempAd" ) ;
}
2025-09-15 15:12:13 +00:00
LoggerUtils . Warning ( "[Admob] Native ad timing refresh , show ad" ) ;
2025-09-17 10:30:03 +00:00
ShowAd ( showing . Position , adUnitId , tempAd , showingNativeOverlayAd ) ;
2025-09-15 15:12:13 +00:00
}
else
{
2025-09-17 10:42:58 +00:00
LoggerUtils . Warning ( $"[Admob] Native ad timing refresh , show fail , showing native ads not ad unit id , {adUnitId} , 广告已经隐藏了,刷新成功,不需要再去显示出来" ) ;
2025-09-15 15:12:13 +00:00
}
}
2025-09-01 15:57:10 +00:00
} ) ;
2025-08-31 13:19:46 +00:00
}
2025-09-01 15:57:10 +00:00
// 显示价格最高的广告
public void ShowHighestPayingAd ( NativeAdPosition position )
{
LoggerUtils . Debug ( $"[Admob] Native ad ShowHighestPayingAd {position}" ) ;
var highestPayingAdUnit = GetHighestPayingAdUnit ( ) ;
LoggerUtils . Debug ( $"[Admob] Native ad ShowHighestPayingAd {position} , highestPayingAdUnit = {highestPayingAdUnit}" ) ;
if ( ! string . IsNullOrEmpty ( highestPayingAdUnit ) )
{
ShowAd ( position , highestPayingAdUnit ) ;
}
}
// 显示特定广告位的广告
2025-09-17 10:30:03 +00:00
public void ShowAd ( NativeAdPosition position , string adUnitId , NativeOverlayAd lastAd = null , NativeOverlayAd lastShowAd = null )
2025-09-01 15:57:10 +00:00
{
2025-09-10 09:54:52 +00:00
if ( ! AdmobAdsManager . Instance . FindAdsID ( AdsType . Native , adUnitId ) )
{
return ;
}
2025-09-15 07:55:38 +00:00
2025-09-01 15:57:10 +00:00
LoggerUtils . Debug ( $"[Admob] Native ad ShowAd start {adUnitId} , {position}" ) ;
if ( _nativeAds . TryGetValue ( adUnitId , out var ad ) )
{
LoggerUtils . Debug ( $"[Admob] Native ad ShowAd end {adUnitId} , {position}" ) ;
// Define a native template style with a custom style.
var style = position . NativeTemplateStyle ? ? new NativeTemplateStyle ( )
{
TemplateId = NativeTemplateId . Medium ,
// TemplateId = "big"
// MainBackgroundColor = Color.green,
CallToActionText = new NativeTemplateTextStyle ( )
{
FontSize = 9 ,
Style = NativeTemplateFontStyle . Bold
}
} ;
// Renders a native overlay ad at the default size
// and anchored to the bottom of the screne.
ad . RenderTemplate ( style , new AdSize ( position . Width , position . Height ) , position . X , position . Y ) ;
2025-09-18 09:37:37 +00:00
var showNativePosition = showingNativeAds [ adUnitId ] ;
var lastAdResponseId = lastAd ? . GetResponseInfo ( ) ? . GetResponseId ( ) ;
var lastShowAdResponseId = lastShowAd ? . GetResponseInfo ( ) ? . GetResponseId ( ) ;
var lastShowAdResponseId2 = showNativePosition ? . NativeOverlayAd ? . GetResponseInfo ( ) ? . GetResponseId ( ) ;
var showAdResponseId = ad . GetResponseInfo ( ) ? . GetResponseId ( ) ;
LoggerUtils . Debug (
$"[Admob] Native ad ShowAd [showingNativeAds] {adUnitId} , lastAdResponseId = {lastAdResponseId} , lastShowAdResponseId = {lastShowAdResponseId} , lastShowAdResponseId2 = {lastShowAdResponseId2} , showAdResponseId = {showAdResponseId}" ) ;
2025-09-15 15:12:13 +00:00
showingNativeAds [ adUnitId ] = new ShowNativePosition ( ad , position ) ;
2025-09-01 15:57:10 +00:00
ad . Show ( ) ;
2025-09-18 09:37:37 +00:00
try
{
lastAd ? . Hide ( ) ;
lastShowAd ? . Hide ( ) ;
showNativePosition ? . NativeOverlayAd ? . Hide ( ) ;
}
catch ( Exception e )
{
LoggerUtils . Error ( $"[Admob] Native ad Hide fail {adUnitId} , e : {e.Message}" ) ;
}
2025-09-15 15:12:13 +00:00
TimingRefresh ( adUnitId ) ;
}
}
private void TimingRefresh ( string adUnitId )
{
var nativeReflashGap = int . Parse ( FireBaseRemoteConfigManager . Instance . GetRemoteConfigString ( "Native_Reflash_Gap" , "0" ) ) ;
if ( nativeReflashGap < = 0 )
{
LoggerUtils . Debug ( $"[Admob] Native ad ({adUnitId}) timing refresh failed. nativeReflashGap = 0" ) ;
return ;
}
if ( adUnitId = = StaticValue . AdmobFullNativeId )
{
LoggerUtils . Debug ( $"[Admob] Native ad ({adUnitId}) timing refresh finished. ad unit id is full native id." ) ;
return ;
}
if ( ! showingNativeAds . ContainsKey ( adUnitId ) )
{
LoggerUtils . Debug ( $"[Admob] Native ad ({adUnitId}) timing refresh finished. ad unit is not show." ) ;
return ;
2025-09-01 15:57:10 +00:00
}
2025-09-15 15:12:13 +00:00
WLoom . QueueOnMainThread ( o = >
{
var refreshAdUnitId = ( string ) o ;
LoggerUtils . Debug ( $"[Admob] Native ad ({adUnitId}) timing refresh load start refreshAdUnitId : {refreshAdUnitId}." ) ;
if ( showingNativeAds . ContainsKey ( refreshAdUnitId ) )
{
LoadAd ( refreshAdUnitId , true ) ;
}
else
{
LoggerUtils . Warning ( $"[Admob] Native ad ({adUnitId}) timing refresh finished. ad unit is not show. refreshAdUnitId : {refreshAdUnitId}." ) ;
}
} , adUnitId , nativeReflashGap ) ;
2025-09-01 15:57:10 +00:00
}
2025-09-03 05:42:30 +00:00
private float GetLoadedTime ( string adUnitId )
2025-09-03 08:56:30 +00:00
{
return _adStartLoadTimes . TryGetValue ( adUnitId , out var time ) ? time : 0 ;
2025-09-03 05:42:30 +00:00
}
2025-09-03 08:56:30 +00:00
2025-09-01 15:57:10 +00:00
// 检查特定广告位是否可用
2025-09-02 02:07:10 +00:00
public bool IsAdAvailable ( string adUnitId )
2025-09-01 15:57:10 +00:00
{
return _nativeAds . TryGetValue ( adUnitId , out _ ) ;
}
// 获取所有可用的广告位
public List < string > GetAvailableAdUnits ( )
{
return _nativeAds . Select ( kvp = > kvp . Key ) . ToList ( ) ;
}
// 获取价格最高的广告位ID
public string GetHighestPayingAdUnit ( )
{
string highestPayingAdUnit = null ;
double highestRevenue = - 1 ;
LoggerUtils . Debug ( $"[Admob] Native ad GetHighestPayingAdUnit {_adRevenueCache.Count}" ) ;
foreach ( var kvp in _adRevenueCache )
{
var adUnitId = kvp . Key ;
var revenue = kvp . Value ;
// 确保广告确实已加载并且价格更高
if ( IsAdAvailable ( adUnitId ) & & revenue > highestRevenue )
{
highestRevenue = revenue ;
highestPayingAdUnit = adUnitId ;
}
}
return highestPayingAdUnit ;
}
// 获取价格最高的广告收益信息
public double GetHighestPayingAdRevenue ( )
{
var highestPayingAdUnit = GetHighestPayingAdUnit ( ) ;
if ( ! string . IsNullOrEmpty ( highestPayingAdUnit ) & &
_adRevenueCache . TryGetValue ( highestPayingAdUnit , out var revenue ) )
{
return revenue ;
}
return 0 ;
}
2025-09-15 07:55:38 +00:00
2025-09-08 08:36:59 +00:00
// 获取广告收益信息
public double GetAdRevenue ( string adUnit )
{
if ( ! string . IsNullOrEmpty ( adUnit ) & &
_adRevenueCache . TryGetValue ( adUnit , out var revenue ) )
{
return revenue ;
}
return - 1 ;
}
2025-09-15 07:55:38 +00:00
2025-09-01 15:57:10 +00:00
// 清理资源
public void Destroy ( )
{
foreach ( var ad in _nativeAds . Values )
{
ad . Destroy ( ) ;
}
_nativeAds . Clear ( ) ;
_adRevenueCache . Clear ( ) ;
}
2025-09-12 07:56:39 +00:00
public IEnumerator RemoveNative ( string adUnitId )
2025-09-01 15:57:10 +00:00
{
2025-09-15 07:55:38 +00:00
// 不需要等待了
// yield return new WaitForSeconds(0.2f);
2025-09-01 15:57:10 +00:00
if ( adUnitId = = null | | string . IsNullOrEmpty ( adUnitId ) )
{
2025-09-15 15:12:13 +00:00
foreach ( var key in showingNativeAds . Keys . ToList ( ) )
2025-09-01 15:57:10 +00:00
{
2025-09-18 09:37:37 +00:00
var ad = showingNativeAds [ key ] . NativeOverlayAd ;
LoggerUtils . Debug ( $"[Admob] Native ad removing [showingNativeAds] {adUnitId} , ad {ad.GetResponseInfo()?.GetResponseId()}" ) ;
ad . Hide ( ) ;
2025-09-15 15:12:13 +00:00
// 从字典中删除元素
showingNativeAds . Remove ( key ) ;
LoadAd ( key ) ;
2025-09-01 15:57:10 +00:00
}
2025-09-12 07:56:39 +00:00
yield break ;
2025-09-01 15:57:10 +00:00
}
2025-09-15 07:55:38 +00:00
if ( showingNativeAds . TryGetValue ( adUnitId , out var tempAd ) )
2025-09-01 15:57:10 +00:00
{
2025-09-18 09:37:37 +00:00
var ad = tempAd . NativeOverlayAd ;
LoggerUtils . Debug ( $"[Admob] Native ad removing [showingNativeAds] {adUnitId} , ad {ad.GetResponseInfo()?.GetResponseId()}" ) ;
ad . Hide ( ) ;
2025-09-15 07:55:38 +00:00
showingNativeAds . Remove ( adUnitId ) ;
2025-09-02 08:24:38 +00:00
LoadAd ( adUnitId ) ;
2025-09-01 15:57:10 +00:00
}
2025-09-15 07:55:38 +00:00
else
{
LoggerUtils . Debug ( $"[Admob] Native ad removing NativeAd {adUnitId} , failed to remove NativeAd" ) ;
}
2025-09-01 15:57:10 +00:00
}
2025-09-15 07:55:38 +00:00
2025-09-10 06:21:12 +00:00
public void ClearAds ( string [ ] adUnitIds )
{
// 将数组转换为HashSet以提高查找性能
HashSet < string > validKeys = new HashSet < string > ( adUnitIds ) ;
// 收集需要移除的key
List < string > keysToRemove = new List < string > ( ) ;
foreach ( var key in _nativeAds . Keys )
{
if ( ! validKeys . Contains ( key ) )
{
keysToRemove . Add ( key ) ;
}
}
// 移除不在数组中的key
foreach ( string key in keysToRemove )
{
_nativeAds . Remove ( key ) ;
_retryCounters . Remove ( key ) ;
_adStartLoadTimes . Remove ( key ) ;
_adRevenueCache . Remove ( key ) ;
}
}
2025-09-01 15:57:10 +00:00
}
}