using GoogleMobileAds.Api; using System; using System.Collections; using System.Collections.Generic; using System.Data.SqlTypes; using UnityEngine; public class ADSManager : MonoBehaviour { protected const int reloadInterval = 5; protected const int maxRetryCount = 20; // 이벤트 연결용 public event Action OnCompletedRewardedAd; public event Action OnCompletedInterstitialAd; public event Action OnDestroyBannerAd; private bool isInitialize = false; private Dictionary adDictionary = new Dictionary(5); private WaitForSecondsRealtime waitForSeconds = new WaitForSecondsRealtime(reloadInterval); private void Awake() { if (GameManager.Network != null) { GameManager.Network.OnNetworkOnline += OnNetworkOnline; } } private void OnDestroy() { StopAllCoroutines(); } private void OnNetworkOnline(bool isOnline) { if (isOnline && isInitialize == false) { InitADSManager(); } } public void InitADSManager() { // Initialize the Google Mobile Ads SDK. MobileAds.Initialize((InitializationStatus initStatus) => { // This callback is called once the MobileAds SDK is initialized. adDictionary.Clear(); // 라이브 if (GameManager.DB.IsRemoveADS == false) { adDictionary.Add("Game_Interstitial", new InterstitialAd("ca-app-pub-6390804219581974/4957790852", "Game_Interstitial")); adDictionary.Add("Top_Banner", new BannerAd("ca-app-pub-6390804219581974/6518284533", "Top_Banner")); } adDictionary.Add("Result_Reward", new RewardAd("ca-app-pub-6390804219581974/3644709187", "Result_Reward")); adDictionary.Add("Heart_Reward", new RewardAd("ca-app-pub-6390804219581974/3947961516", "Heart_Reward")); adDictionary.Add("Gold_Reward", new RewardAd("ca-app-pub-6390804219581974/2331627517", "Gold_Reward")); //// 게등위 테스트용 //if (GameManager.DB.IsRemoveADS == false) //{ // adDictionary.Add("Game_Interstitial", new InterstitialAd("ca-app-pub-3940256099942544/1033173712", "Game_Interstitial")); // adDictionary.Add("Top_Banner", new BannerAd("ca-app-pub-3940256099942544/9214589741", "Top_Banner")); //} //adDictionary.Add("Result_Reward", new RewardAd("ca-app-pub-3940256099942544/5224354917", "Result_Reward")); //adDictionary.Add("Heart_Reward", new RewardAd("ca-app-pub-3940256099942544/5224354917", "Heart_Reward")); //adDictionary.Add("Gold_Reward", new RewardAd("ca-app-pub-3940256099942544/5224354917", "Gold_Reward")); foreach (var ad in adDictionary.Values) { ad.OnFailLoadAD += OnFailLoadAD; ad.LoadAd(); } isInitialize = true; }); } private void OnFailLoadAD(string id) { StartCoroutine(ReloadAd(id)); } private IEnumerator ReloadAd(string id) { yield return waitForSeconds; if(adDictionary.Count > 0) { adDictionary[id].LoadAd(); } } #region Rewarded public void ShowResultRewardedAd(string name) { if (GameManager.Network.IsOnline == false) { //GameManager.UI.ShowNStackPopup(EPopupType.FailNetworkPopup).SetData("Heart_Reward", ownerName); GameManager.UI.ShowNStackPopup(EPopupType.NotOnline_ClosePopup); } else { adDictionary["Result_Reward"].ShowAd(name); } } public void HideResultRewardedAd() { adDictionary["Result_Reward"].HideAd(); } public void ShowHeartRewardedAd(string name) { if (GameManager.Network.IsOnline == false) { //GameManager.UI.ShowNStackPopup(EPopupType.FailNetworkPopup).SetData("Heart_Reward", ownerName); GameManager.UI.ShowNStackPopup(EPopupType.NotOnline_ClosePopup); } else { adDictionary["Heart_Reward"].ShowAd(name); } } public void HideHeartRewardedAd() { adDictionary["Heart_Reward"].HideAd(); } public void ShowGoldRewardedAd(string name) { if (GameManager.Network.IsOnline == false) { //GameManager.UI.ShowNStackPopup(EPopupType.FailNetworkPopup).SetData("Heart_Reward", ownerName); GameManager.UI.ShowNStackPopup(EPopupType.NotOnline_ClosePopup); } else { adDictionary["Gold_Reward"].ShowAd(name); } } public void HideGoldRewardedAd() { adDictionary["Gold_Reward"].HideAd(); } #endregion #region Interstitial public void ShowInterstitialAd(Action success = null) { if (GameManager.DB.IsRemoveADS) { OnCompletedInterstitialAd?.Invoke(false); } else { if (GameManager.Network.IsOnline == false) { //GameManager.UI.ShowNStackPopup(EPopupType.FailNetworkPopup).SetData("Game_Interstitial"); GameManager.UI.ShowNStackPopup(EPopupType.NotOnline_ClosePopup); } else { adDictionary["Game_Interstitial"].ShowAd(); success?.Invoke(); } } } public void HideInterstitialAd() { adDictionary["Game_Interstitial"].HideAd(); } #endregion #region Banner public void ShowBanner() { if (isInitialize && GameManager.DB.IsRemoveADS == false) { adDictionary["Top_Banner"].ShowAd(); } OnDestroyBannerAd?.Invoke(GameManager.DB.IsRemoveADS); } public void HideBanner() { if (adDictionary.ContainsKey("Top_Banner")) adDictionary["Top_Banner"].HideAd(); OnDestroyBannerAd?.Invoke(true); } #endregion public class Ad : MonoBehaviour { public Action OnFailLoadAD; protected string id; protected string adUnitId; protected bool adAvailable = false; protected bool isTest = false; public int retryLoadCount = 0; public bool AdAvailable { get { return adAvailable; } } public Ad(string adUnitId, string id) { this.adUnitId = adUnitId; this.id = id; } public virtual void LoadAd() { } public virtual void ShowAd() { } public virtual void ShowAd(string ownerName) { } public virtual void HideAd() { } public void ResetRetryLoadCount() { retryLoadCount = 0; } } public class RewardAd : Ad { protected string owner = String.Empty; public string Owner { get { return owner; } } private GoogleMobileAds.Api.RewardedAd ad; private WaitForSecondsRealtime waitForSeconds = new WaitForSecondsRealtime(reloadInterval); public RewardAd(string adUnitId, string id) : base(adUnitId, id) { } public override void LoadAd() { #if UNITY_EDITOR || UNITY_ANDROID if (isTest) { adUnitId = "ca-app-pub-3940256099942544/5224354917"; } #elif UNITY_IPHONE adUnitId = "ca-app-pub-3940256099942544/4411468910"; #else adUnitId = "unused"; #endif // Clean up the old ad before loading a new one. if (this.ad != null) { this.ad.Destroy(); this.ad = null; } Debug.Log("Loading the rewarded ad."); // create our request used to load the ad. var adRequest = new AdRequest(); // send the request to load the ad. RewardedAd.Load(adUnitId, adRequest, async (RewardedAd ad, LoadAdError error) => { // if error is not null, the load request failed. if (error != null || ad == null) { Debug.LogError("Rewarded ad failed to load an ad " + "with error : " + error); adAvailable = false; //GameManager.UI.ShowNStackPopup(EPopupType.FailLoadADSPopup); retryLoadCount++; if (retryLoadCount < maxRetryCount) { OnFailLoadAD?.Invoke(this.id); } return; } Debug.Log("Rewarded ad loaded with response : " + ad.GetResponseInfo() + ad.GetAdUnitID().ToString()); this.ad = ad; adAvailable = true; RegisterEventHandlers(this.ad); }); } public override void ShowAd(string ownerName) { if (adAvailable == true && ad != null && ad.CanShowAd()) { const string rewardMsg = "Rewarded ad rewarded the user. Type: {0}, amount: {1}."; ad.Show((Reward reward) => { // TODO: Reward the user. Debug.Log(String.Format(rewardMsg, reward.Type, reward.Amount)); }); owner = ownerName; } else { GameManager.UI.ShowNStackPopup(EPopupType.FailLoadADSPopup); owner = String.Empty; GameManager.ADS.OnCompletedRewardedAd?.Invoke(false, owner); } } public override void HideAd() { if (ad != null) { ad.Destroy(); ad = null; } } private void RegisterEventHandlers(GoogleMobileAds.Api.RewardedAd ad) { // Raised when the ad is estimated to have earned money. ad.OnAdPaid += (AdValue adValue) => { Debug.Log(String.Format("Rewarded ad paid {0} {1}.", adValue.Value, adValue.CurrencyCode)); }; // Raised when an impression is recorded for an ad. ad.OnAdImpressionRecorded += () => { Debug.Log("Rewarded ad recorded an impression."); }; // Raised when a click is recorded for an ad. ad.OnAdClicked += () => { Debug.Log("Rewarded ad was clicked."); }; // Raised when an ad opened full screen content. ad.OnAdFullScreenContentOpened += () => { Debug.Log("Rewarded ad full screen content opened."); }; // Raised when the ad closed full screen content. ad.OnAdFullScreenContentClosed += () => { Debug.Log("Rewarded Ad full screen content closed."); GameManager.ADS.OnCompletedRewardedAd?.Invoke(true, owner); owner = String.Empty; // Reload the ad so that we can show another as soon as possible. LoadAd(); }; // Raised when the ad failed to open full screen content. ad.OnAdFullScreenContentFailed += (AdError error) => { Debug.LogError("Rewarded ad failed to open full screen content " + "with error : " + error); GameManager.UI.ShowNStackPopup(EPopupType.FailLoadADSPopup); GameManager.ADS.OnCompletedRewardedAd?.Invoke(false, owner); owner = String.Empty; // Reload the ad so that we can show another as soon as possible. LoadAd(); }; } } public class InterstitialAd : Ad { private GoogleMobileAds.Api.InterstitialAd ad; public InterstitialAd(string adUnitId, string id) : base(adUnitId, id) { } public override void LoadAd() { #if UNITY_EDITOR || UNITY_ANDROID if (isTest) { adUnitId = "ca-app-pub-3940256099942544/1033173712"; } #elif UNITY_IPHONE //adUnitId = "ca-app-pub-3940256099942544/4411468910"; #else adUnitId = "unused"; #endif // Clean up the old ad before loading a new one. if (ad != null) { ad.Destroy(); ad = null; } Debug.Log("Loading the interstitial ad."); // create our request used to load the ad. var adRequest = new AdRequest(); // send the request to load the ad. GoogleMobileAds.Api.InterstitialAd.Load(adUnitId, adRequest, (GoogleMobileAds.Api.InterstitialAd ad, LoadAdError error) => { // if error is not null, the load request failed. if (error != null || ad == null) { Debug.LogError("interstitial ad failed to load an ad " + "with error : " + error); adAvailable = false; retryLoadCount++; if (retryLoadCount < maxRetryCount) { OnFailLoadAD?.Invoke(this.id); } return; } Debug.Log("Interstitial ad loaded with response : " + ad.GetResponseInfo()); this.ad = ad; adAvailable = true; RegisterReloadHandler(ad); }); } public override void ShowAd() { if (adAvailable == true && ad != null && ad.CanShowAd()) { Debug.Log("Showing interstitial ad."); ad.Show(); } else { GameManager.UI.ShowNStackPopup(EPopupType.FailLoadADSPopup); GameManager.ADS.OnCompletedInterstitialAd?.Invoke(false); Debug.LogError("Interstitial ad is not ready yet."); } } public override void HideAd() { if (ad != null) { ad.Destroy(); ad = null; } } private void RegisterReloadHandler(GoogleMobileAds.Api.InterstitialAd interstitialAd) { // Raised when the ad is estimated to have earned money. interstitialAd.OnAdPaid += (AdValue adValue) => { Debug.Log(String.Format("Interstitial ad paid {0} {1}.", adValue.Value, adValue.CurrencyCode)); }; // Raised when an impression is recorded for an ad. interstitialAd.OnAdImpressionRecorded += () => { Debug.Log("Interstitial ad recorded an impression."); }; // Raised when a click is recorded for an ad. interstitialAd.OnAdClicked += () => { Debug.Log("Interstitial ad was clicked."); }; // Raised when an ad opened full screen content. interstitialAd.OnAdFullScreenContentOpened += () => { Debug.Log("Interstitial ad full screen content opened."); }; // Raised when the ad closed full screen content. interstitialAd.OnAdFullScreenContentClosed += () => { Debug.Log("Interstitial Ad full screen content closed."); GameManager.ADS.OnCompletedInterstitialAd?.Invoke(true); // Reload the ad so that we can show another as soon as possible. LoadAd(); }; // Raised when the ad failed to open full screen content. interstitialAd.OnAdFullScreenContentFailed += (AdError error) => { Debug.LogError("Interstitial ad failed to open full screen content " + "with error : " + error); GameManager.UI.ShowNStackPopup(EPopupType.FailLoadADSPopup); GameManager.ADS.OnCompletedInterstitialAd?.Invoke(false); // Reload the ad so that we can show another as soon as possible. LoadAd(); }; } } public class BannerAd : Ad { private GoogleMobileAds.Api.BannerView ad; public BannerAd(string adUnitId, string id) : base(adUnitId, id) { } public override void LoadAd() { #if UNITY_EDITOR || UNITY_ANDROID if (isTest) { adUnitId = "ca-app-pub-3940256099942544/9214589741"; } #elif UNITY_IPHONE //adUnitId = "ca-app-pub-3940256099942544/4411468910"; #else adUnitId = "unused"; #endif if (GameManager.DB.IsRemoveADS == true) { adAvailable = false; return; } // Clean up banner ad before creating a new one. if (ad != null) { ad.Destroy(); ad = null; } AdSize adaptiveSize = AdSize.GetPortraitAnchoredAdaptiveBannerAdSizeWithWidth(AdSize.FullWidth); ad = new BannerView(adUnitId, adaptiveSize, GoogleMobileAds.Api.AdPosition.Top); // Register for ad events. ad.OnBannerAdLoaded += OnBannerAdLoaded; ad.OnBannerAdLoadFailed += OnBannerAdLoadFailed; AdRequest adRequest = new AdRequest(); ad.LoadAd(adRequest); } public override void ShowAd() { if (GameManager.DB.IsRemoveADS == false && adAvailable == true && ad != null) { ad.Show(); } } public override void HideAd() { if (ad != null) { ad.Hide(); //ad.Destroy(); //ad = null; } } public void DestroyBannerAd() { if (ad != null) { Debug.Log("Destroying banner view."); ad.Destroy(); ad = null; GameManager.ADS.OnDestroyBannerAd?.Invoke(true); } } private void OnBannerAdLoaded() { Debug.Log("Banner view loaded an ad with response : " + ad.GetResponseInfo()); adAvailable = true; // 실제 로드된 배너의 픽셀 크기 float width = ad.GetWidthInPixels(); float height = ad.GetHeightInPixels(); Debug.Log($"Banner loaded: {width} x {height}"); // Unity UI 좌표계로 변환 (CanvasScaler에 따라 다름) //float heightInUnits = (float)height / Screen.height * CanvasRectTransform.rect.height; // 예: 상단 UI 패널을 배너 높이만큼 내리기 //topPanel.anchoredPosition = new Vector2( // topPanel.anchoredPosition.x, // topPanel.anchoredPosition.y - heightInUnits //); } private void OnBannerAdLoadFailed(LoadAdError error) { Debug.LogError("Banner view failed to load an ad with error : " + error); adAvailable = false; retryLoadCount++; if (retryLoadCount < maxRetryCount) { OnFailLoadAD?.Invoke(this.id); } } } }