Search code examples
androidunity-game-engineadmobads

Game crashes after showing intersitial and rewarded ads


I am using admob for ads. Ads working very well on the Editor but on the phone it doesn't. I have a button in the game that show rewarded ads then load next level. And I am showing interstitial ads at end of the level then load next level. But after loading next level game crashes. I am trying to fix it for days but it keeps happening. I am adding my ad manager script. (unit ids not empty of course)

using System.Collections;
 using UnityEngine;
 using GoogleMobileAds.Api;
 using System;
  
 public class AdManager : MonoBehaviour
 {
     public static AdManager instance;
     private BannerView bannerView;
     private RewardedAd rewardedAd;
     private InterstitialAd interstitialAd;
  
      #if UNITY_ANDROID
         string bannerAdUnitId = " ";
        
         string rewardedAdUnitId = " ";
  
         string interstitialAdUnitId = " ";
  
     #else
         string bannerAdUnitId = "unexpected_platform";
  
         string rewardedAdUnitId = "unexpected_platform";
  
         string interstitialAdUnitId = "unexpected_platform";
  
     #endif
  
     void Awake()
     {
         if(instance != null && instance != this){
             Destroy(this.gameObject);
         }
         else{
             instance = this;
             DontDestroyOnLoad(this.gameObject);
         }
     }
  
     private void Start() {
         MobileAds.Initialize(initStatus => { });
         RequestInterstitialAd();
         RequestBannerAd();
         RequestRewardedAd();
     }
  
     //BANNER
     public void RequestBannerAd(){
         if (bannerView != null)
             bannerView.Destroy();
        
         else{
             bannerView = new BannerView(bannerAdUnitId, AdSize.Banner, AdPosition.Bottom);
  
             AdRequest request = new AdRequest.Builder().Build();
  
             bannerView.LoadAd(request);
         }
     }
  
     //REWARDED
  
     public void RequestRewardedAd(){
         if(rewardedAd != null)
             rewardedAd.Destroy();
  
         rewardedAd = new RewardedAd(rewardedAdUnitId);
  
         // Called when an ad request failed to show.
         rewardedAd.OnAdFailedToShow += HandleRewardedAdFailedToShow;
         // Called when the ad is closed.
         rewardedAd.OnAdClosed += HandleRewardedAdClosed;
  
         AdRequest request = new AdRequest.Builder().Build();
  
         rewardedAd.LoadAd(request);
  
     }
  
     public void ShowRewardedAd(){
         if (rewardedAd.IsLoaded()) {
             rewardedAd.Show();
         }
         else{
             StartCoroutine(RewardedNotLoadedFunctionCall());
         }
     }
  
     IEnumerator RewardedNotLoadedFunctionCall(){
         FindObjectOfType<GameManagement>().RewardedAdNotLoaded();
         yield return null;
     }
  
     public void HandleRewardedAdClosed(object sender, EventArgs args)
     {
         RequestRewardedAd();
         StartCoroutine(AdClosedFunctionCall());
     }
     IEnumerator AdClosedFunctionCall(){
         FindObjectOfType<GameManagement>().AdClosed();
         yield return null;
     }
  
     public void HandleRewardedAdFailedToShow(object sender, AdErrorEventArgs args)
     {
         StartCoroutine(RewardedNotLoadedFunctionCall());
     }
  
     //interstitial
  
     private void RequestInterstitialAd(){
         if(interstitialAd != null)
             interstitialAd.Destroy();
  
         interstitialAd = new InterstitialAd(interstitialAdUnitId);
  
         interstitialAd.OnAdClosed += HandleOnAdClosed;
  
         AdRequest request = new AdRequest.Builder().Build();
         interstitialAd.LoadAd(request);
     }
  
     public void ShowInterstitialAd(){
         if (interstitialAd.IsLoaded()) {
             interstitialAd.Show();
         }
         else{
             StartCoroutine(AdClosedFunctionCall());
         }
     }
  
     public void HandleOnAdClosed(object sender, EventArgs args)
     {
         RequestInterstitialAd();
         StartCoroutine(AdClosedFunctionCall());
     }
 }

logcat


Solution

  • Admob Ad does not run on the same thread as Unity's main thread.

    rewardedAd.OnAdClosed += HandleRewardedAdClosed;
    

    Calling Unity's function from Admob's thread will lead to unexpected error.

    First, add UnityMainThreadDispatcher to your project. All functions called by Admob's callback need be queued by UnityMainThreadDispatcher to main thread:

    public void HandleRewardedAdClosed(object sender, EventArgs args)
         {
            UnityMainThreadDispatcher.Instance().Enqueue(()=>{
                RequestRewardedAd();
                StartCoroutine(AdClosedFunctionCall());
            });
         }
    

    Secondly, you should not use FindObjectOfType(). This is an expensive operation and you might run into NullReferenceException if it fails to find the GameManagement object. And since this exception did not happen on Unity's main thread, the logcat message was cryptic.

    You should use Singleton or Observer pattern instead.

    Thirdly, you're giving reward to user even if they skip the reward ad. Use rewardedAd.OnUserEarnedReward to make sure user have earned the reward ad.