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 toInterstitialAd.Load
. To use it, you must pass the context, the Interstitial ID, anAdRequest
(we still create a new request every time.), and anInterstitialAdLoadCallback
. We are also creating a child class calledInterstitialCallbackinherit
that extendsInterstitialAdLoadCallback
, which we will cover soon. - As the method
IsLoaded
is no longer available for InterstitialAd, we need to introduce a new boolean calledadLoaded
. This boolean is used in theShowAd
method to call theShow
method only when the ad has already loaded. - The
Show
method of theinterstitialAd
now requires an AndroidActivity
parameter. To address this, I created a static instance of theMainActivity
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 totrue
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 theAdInterstitial
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.