Updating obsolete Admob Interstitial ads for Xamarin Android

Updating obsolete Admob Interstitial ads for Xamarin Android

In April 2021, Google updated their Interstitial Admob’s API with some breaking changes. After updating Xamarin.GooglePlayServices.Ads from version 71 to 118 or higher, a following error can be encountered in the Android project when using InterstitialAd.

CS0246: The type or namespace name 'type/namespace' could not be found (are you missing a using directive or an assembly reference?)

While researching on the internet, I could not find complete information on the specific changes I should make to update the implementation while maintaining the same functionality that I had before. Currently, I handle interstitial ads by loading the ad and showing it only if it has already been loaded, and if certain conditions in the application are met.

When looking at the Xamarin GooglePlayServicesComponents samples for the new version, I discovered a new commit with an example of how to request and load an Interstitial ad. However, there is still no sample on how to show the ad at the specific moment it is needed within the application, rather than immediately after it is loaded from Admob. Additionally, there are some missing workarounds required to ensure that the InterstitialCallback functions properly.

The Interstitial API was updated two years ago, and I couldn’t find any articles showing how to update our applications to the latest version. Therefore, I decided to write and share a workaround for this issue.

Implementation before the update

This is a simple example of how I implemented Interstitial Ads in Android using version 71.x. I did not include any interface to share code with the iOS implementation.

public class AdInterstitial
{
		InterstitialAd interstitialAd;
		
		public AdInterstitial()
    {
        interstitialAd = new InterstitialAd(Android.App.Application.Context);
        interstitialAd.AdUnitId = ADMOB_INTERSTITIAL_ID; //Insert your interstitial admob id here
        LoadAd();
    }

    void LoadAd()
    {
        var requestbuilder = new AdRequest.Builder();
        interstitialAd.LoadAd(requestbuilder.Build());
    }

    public void ShowAd()
    {
        if (interstitialAd.IsLoaded)
        {
            interstitialAd.Show();
            LoadAd();
        }
    }

}

This implementation allows us to request a new ad every time we show the one already loaded. We can show the new ad by using the ShowAd method, which can be implemented through an interface to maintain consistent behavior across Android and iOS. This method also verifies that the ad is loaded before attempting to show it.

Updating the AdInterstitial class

This is a simple example of how we can maintain the same behavior while using the new version of Xamarin.GooglePlayServices.Ads. There are still some missing files needed to complete the implementation, but I will cover those shortly.

public class AdInterstitial
{
    public static InterstitialAd interstitialAd;
    public static bool adLoaded;

    public AdInterstitial()
    {
        adLoaded = false;
        LoadAd();
    }

    void LoadAd()
    {
        InterstitialAd.Load(Android.App.Application.Context, ADMOB_INTERSTITIAL_ID, new AdRequest.Builder().Build(), new InterstitialCallbackinherit());
    }

    public void ShowAd()
    {
        if (AdInterstitial.adLoaded)
        {
            interstitialAd.Show(MainActivity.instance);
            LoadAd();
        }
    }

}

The changes that can be observed in this file are the following:

  • The InterstitialAd is a static variable and is not instantiated in the constructor. However, it will be instantiated later on.
  • The LoadAd method has been updated to InterstitialAd.Load. To use it, you must pass the context, the Interstitial ID, an AdRequest (we still create a new request every time.), and an InterstitialAdLoadCallback. We are also creating a child class called InterstitialCallbackinherit that extends InterstitialAdLoadCallback, which we will cover soon.
  • As the method IsLoaded is no longer available for InterstitialAd, we need to introduce a new boolean called adLoaded. This boolean is used in the ShowAd method to call the Show method only when the ad has already loaded.
  • The Show method of the interstitialAd now requires an Android Activity parameter. To address this, I created a static instance of the MainActivity class to be used in this method. See the code below:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    public static MainActivity instance;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        (...)

        instance = this;

        LoadApplication(new App());
    }
}

Override OnAdLoaded method

As previously mentioned, the last parameter of InterstitialAd.Load is an InterstitialAdLoadCallback. To implement our solution, we created a InterstitialCallbackinherit class that extends this callback and overrides the OnAdLoaded method.

However, we cannot override the OnAdLoaded method using the official InterstitialAdLoadCallback because it does not implement it from the AdLoadCallback. This issue was raised in a question on Microsoft Q&A (thanks to Leon Lu for sharing).

To solve this problem, we need to create the following InterstitialCallback class:

public abstract class InterstitialCallback : Android.Gms.Ads.Interstitial.InterstitialAdLoadCallback
{
    [Register("onAdLoaded", "(Lcom/google/android/gms/ads/interstitial/InterstitialAd;)V", "GetOnAdLoadedHandler")]
    public virtual void OnAdLoaded(Android.Gms.Ads.Interstitial.InterstitialAd interstitialAd)
    {
    }

    private static Delegate cb_onAdLoaded;
    private static Delegate GetOnAdLoadedHandler()
    {
        if (cb_onAdLoaded is null)
            cb_onAdLoaded = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr>)n_onAdLoaded);
        return cb_onAdLoaded;
    }
    private static void n_onAdLoaded(IntPtr jnienv, IntPtr native__this, IntPtr native_p0)
    {
        InterstitialCallback thisobject = GetObject<InterstitialCallback>(jnienv, native__this, JniHandleOwnership.DoNotTransfer);
        Android.Gms.Ads.Interstitial.InterstitialAd resultobject = GetObject<Android.Gms.Ads.Interstitial.InterstitialAd>(native_p0, JniHandleOwnership.DoNotTransfer);
        thisobject.OnAdLoaded(resultobject);
    }
}

We can now create our InterstitialCallbackinherit class, which extends InterstitialCallback and overrides OnAdLoaded.

public class InterstitialCallbackinherit : InterstitialCallback
{

    public override void OnAdLoaded(Android.Gms.Ads.Interstitial.InterstitialAd interstitialAd)
    {
        AdInterstitial.interstitialAd = interstitialAd;
        AdInterstitial.adLoaded = true;
				base.OnAdLoaded(interstitialAd);
    }

    public override void OnAdFailedToLoad(LoadAdError p0)
    {
        base.OnAdFailedToLoad(p0);
        AdInterstitial.adLoaded = false;
    }

}

The goal of this override is twofold:

  • Update the adLoaded boolean to true when the ad is loaded. This ensures that the ad is ready to be shown whenever we want.
  • Instantiate the interstitialAd object, which is defined as static in the AdInterstitial class.

You may be wondering why they changed the approach to instantiation. The answer can be found in the SDK migration to v20 documentation. According to the documentation, interstitial formats now follow a standardized API design, in which all full-screen format APIs use the following principles:

  • A static load method
  • A similar load callback or handler mechanism
  • Reliance on the FullScreenContentCallback class for presentation callbacks.

Manifest update

The last thing to consider is adding a new metadata entry to the AndroidManifest.xml that includes the Admob Application ID.

<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-xxxxxxxxxxxxxxx~xxxxxxxxxxx" />

Working sample

I have created a simple project demonstrating the updated implementation of interstitials for Android. It is a full example of how to handle loading and showing Interstitials on both Android and iOS.


Leave a Reply

Your email address will not be published. Required fields are marked *