Search code examples
androidxamarin.formsadmobadsbanner

Xamarin Forms AdMob Adaptive Banner Ad Android


I want to add an AdMob Adaptive Banner Ad to the bottom of a page in my app, but no matter what I do I cannot get it to display correctly. I have no problem loading the ad (and the interstitial ads I have work fine too), but I can never get it to position itself correctly. I've tried a million combinations of bits of code and properties and looked at everything I can find on the internet, to no avail.

My code has three parts:

A custom view in the shared project, inherited from the Frame class (despite some guidance on internet saying to inherit from View, ads are entirely invisible unless I inherit from Frame).

using Xamarin.Forms;

namespace MyApp.Views
{
    public class AdAdaptiveBannerView : Frame
    {
        public AdAdaptiveBannerView()
        {
        }
    }
}

The custom renderer in the Android project.

using Android.Content;
using Android.Gms.Ads;
using Android.Widget;
using System;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyApp.Views.AdAdaptiveBannerView), typeof(MyApp.Droid.AdAdaptiveBanner_Droid))]
namespace MyApp.Droid
{
    public class AdAdaptiveBanner_Droid : ViewRenderer<Views.AdAdaptiveBannerView, AdView>
    {
        public static AdView adView;

        public AdAdaptiveBanner_Droid(Context context) : base(context)
        {
        }

        private AdView CreateAdView()
        {
            adView = new AdView(Android.App.Application.Context)
            {
                AdUnitId = "ca-app-pub-3940256099942544/6300978111", //ca-app-pub-3940256099942544/6300978111 is a banner test unit.
                LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent), //For Adaptive Banner.
                AdSize = AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSize(Android.App.Application.Context, (int)(DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density))
                //LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent), //For SmartBanner.
                //AdSize = AdSize.SmartBanner
            };

            adView.AdListener = new ListeningRegular();
            adView.LoadAd(new AdRequest.Builder().Build());

            return adView;
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Views.AdAdaptiveBannerView> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null && Control == null) SetNativeControl(CreateAdView());
        }
    }

    internal class ListeningRegular : AdListener
    {
        public override void OnAdLoaded()
        {
            Console.WriteLine("Ad has loaded.");
            base.OnAdLoaded();
        }

        public override void OnAdClosed()
        {
            Console.WriteLine("Ad has closed.");
            AdAdaptiveBanner_Droid.adView.Dispose();
            AdAdaptiveBanner_Droid.adView = null;
            AdAdaptiveBanner_Droid.adView.AdListener = null;
            GC.Collect();
            base.OnAdClosed();
        }
    }
}

And the content page XAML in the shared project (I set the background colour to something so I could see what's going on more easily).

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-MyApp.Views"
             x:Class="MyApp.Pages.Page1">
    <ContentPage.Content>
        <StackLayout>
            <Grid VerticalOptions="EndAndExpand">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <views:AdAdaptiveBannerView BackgroundColor="DeepSkyBlue" />
            </Grid>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

As I say, this loads the ad okay but it always crops the bottom of the ad off. Apart from it looking silly, Google's policy explicitly forbids this.

It also randomly decides when opening the page to either fill the width of the screen or only take up the standard banner ad width, like the following two images (taken from a physical Samsung Galaxy S6 running Android 7).

Adaptive Banner Ad that fills the width

and

Adaptive Banner Ad that does not fill the width

I thought this might be because GetCurrentOrientationAnchoredAdaptiveBannerAdSize didn't know what orientation the device was in and was randomly selecting between portrait and landscape, but if I use GetLandscapeAnchoredAdaptiveBannerAdSize and GetPortraitAnchoredAdaptiveBannerAdSize depending on DeviceDisplay.MainDisplayInfo.Orientation it still chooses randomly.

If I give up trying to use an Adaptive Banner and instead use a Smart Banner (by uncommenting the two commented lines in the second chunk of code above and commenting out the two lines above it) it looks just as bad, with a weird border around it.

enter image description here

It also randomly chooses which sized ad (i.e. see where it says 'This is a XxY test ad') to load, even though I thought this was supposed to depend on the screen width and so should always be the same.

I've tried putting it inside various containers (e.g. the grid, as shown in the code above) and nothing. This post is long enough already; If I described everything I tried it would be 50 pages.

For a long time, my impression was that it was something to do with padding because it inherits from Frame (which has default padding of 20), but no combination of padding (setting this to 0 makes the ad disappear entirely), margins, vertical options, horizontal options, row definition properties or anything helps.

Also, I don't know how to make it react to the device being rotated, so that's another problem as when you rotate the screen it looks wrong (and you can only set AdSize once).

Please can anyone help?

Edit: I've just tried adding the banner advert programmatically instead of in the XAML, and it gives exactly the same result. This is so frustrating.


Solution

  • After many hours of faff, it looks like I have a solution. I have to use the code behind the getCurrentOrientationAnchoredAdaptiveBannerAdSize method (thanks to @youssef mountassir for the code) to set the height request of the adaptive banner view in the content page. I couldn't figure out how to do this inside the renderer.

    It still occasionally has a thin black band at the top and bottom but I suspect that's something up with the test ads.

    What I really want to know is why I have to do this when nobody else seems to have to.

    To answer my second question, that is, how to update it when rotating the device, was more straightforward. I add the ad view to the page programmatically, then when the device rotates I replace it with a new one.