65  comments

There are lots of ways to turn a profit from an app. One of the most common and effective ones is in-app advertisement.

Google is by far the biggest player in the online advertising game. Google AdMob is a service that provides highly personalized ads from over one million advertisers along with useful tools and analytics to be used in apps. Integrating Google AdMob into your Flutter apps is absolutely free and, as you'll learn in this tutorial, really simple.

The Finished App

Earlier this year, Google announced the release of a new Google Mobile Ads for Flutter plugin. This plugin combines the ability to display ads from Google AdMob as well as Google Ad Manager in multiple formats on both Android and iOS.

At the end of this tutorial, we are going to have a mock news app which will display several ad formats. The home page of the app will feature an inline banner ad within the newsfeed and a banner ad at the bottom of the screen.

The last ad format we are going to implement will be an interstitial ad. When clicking on a news story tile, you'll be taken to the news article page, but before seeing the article you'll see an interstitial ad. An interstitial ad is displayed as a full-screen overlay. In our implementation we are going to display a video ad which can be dismissed after 5 seconds. When the ad is dismissed, you'll see the news article page.

After completing this tutorial, you will have all of the knowledge you need to start displaying ads in your apps.

Getting Started

In this tutorial you are going to learn several things. First, you'll learn the basics of setting up your AdMob account. You will also learn how to set up platform specific configurations for your Flutter project to be able to display ads on Android and iOS. Then we'll go over configuring and displaying banner and interstitial ads in various places within the app.

We'll be working with a starter project that will have all of the core UI elements preconfigured for you. You can grab the starter project as well as the finished project from the links below.

Before we begin, let’s add the dependency for the Google Mobile Ads for Flutter plugin to the starter project.

We are going to be using the most current version of the plugin available at the time of writing this tutorial. So, if you are going through this lesson in the future, be mindful of any potential breaking changes that may occur. Go ahead and add version 0.13.3 to the starter project's pubspec.yaml file now. 

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  google_mobile_ads: ^0.13.3

Starter Project Overview

The starter project is a simple mock UI of a news app. In this section we are going to go over all of the included files and assets. 

In the lib folder you will find the main.dart file that contains an AppWidget which returns a MaterialApp that contains the HomePage widget as the home argument.

This project contains a few different files, so we separated them into two folders to keep things a bit more tidy. In the data folder you'll find the news_article.dart file. Here we’ve got a NewsArticle class which holds a static field of type List. This field contains a List of NewsArticle objects that we use to mock the news articles inside the app. Every NewsArticle object holds a goofy news headline (just for fun) and a corresponding asset image path.

In the presentation folder you'll find three files - home_page.dart, news_article_page.dart, and widgets.dart. The home_page.dart contains a stateful HomePage widget. This is the main page of the app and it displays a Scaffold that has an AppBar with a title and a ListView.builder in the body. The ListView.builder uses the static articles field from the NewsArticle class located in the news_article.dart file to generate custom ArticleTile widgets. Every generated tile is wrapped in a GestureDetector widget. Lastly, for the onTap argument we’ve implemented a function that will route you to the NewsArticlePage when the tile is tapped.

The news_article_page.dart contains a stateless widget which will dynamically display a mock news article depending on which tile in the home page was tapped. This NewsArticlePage widget accepts a title and an image path through its constructor and displays them on the page along with some placeholder text.

The last file in the presentation folder is widgets.dart. This file contains two widgets - AppBarTitle and ArticleTile. The primary purpose of this file is to declutter our other pages.

We've gone over all of the files included in the starter project. The only thing left to mention is the assets folder. This folder holds all of the images we are displaying in our mock news articles.

Well, that's all for the starter project! Next we are going to go over creating and setting up an AdMob account.

Creating & Setting Up Your AdMob Account

When your app is in development, you should always use test ads instead of real ads. This is extremely important and shouldn't be overlooked. If you use real ads then advertisers will be charged for every click you make. If you click on the real ads too many times, Google will flag this activity as invalid and you risk being penalized for it. Even though we'll be using test ads in this tutorial, we'll still learn how to set up your AdMob account. This way when you are done developing you can swap out the test ads for your own.

Head over to admob.google.com and sign up if you don’t have an account , or sign in if you do. You'll need a Google account to create an AdMob account. When you sign up you will be taken through a few basic steps and will be asked to select things like your location, time zone and billing currency.

Creating an App

When you're done with the sign-up process, you'll see your user dashboard. If you created a brand new account then you can click “Get Started” or go to Apps in the left sidebar and then click “Add Your First App”.

From here you can choose to create an Android or iOS app. Since we are developing with Flutter you will likely want to create both. The steps for both are exactly the same. So, go ahead and create them now.

You'll be asked if your app is listed on an app store. If it isn’t, make sure to select “No”. Keep in mind that before your app can show ads, it'll need to go through Google’s approval process. This usually takes a couple of days.

Then you'll be prompted to choose a name for your app. On the same page you can also choose whether or not you want to use metrics. Metrics provide you with some useful data that will help you understand aggregated user behavior in your app. If you are serious about making money from ads, definitely enable this.

That’s it! Make sure you go through this process for both iOS and Android and you are good to move on to the next step.

Creating an Ad Unit

The next thing we need to do is create an ad unit. You should create an ad unit for every activity or location where you want to display the ads in your app. This is best practice because it'll allow you to individually track the performance of every ad unit. These units send requests to AdMob for ads and then display them in your app.

Each app will have its own ad units. So select either the Android or iOS app through the Apps menu in the sidebar and click on “Ad units”. Then click “Get Started”.

The next step is to select the ad format for this new unit. You can choose from several formats here depending on your needs. We are going to be creating banner and interstitial ads in this tutorial. The set-up process is identical for each ad format except for the rewarded ads. That is because for rewarded ads you also need to specify the reward amount and reward item name.

Go ahead and select the banner ad format. Then you'll be able to enter a name for your ad unit and change any advanced settings if necessary. Once you’re done, go ahead and click “Create ad unit”.

Keep in mind that it may take up to an hour for an ad unit to start displaying ads.

That’s it, you’re all done! At the end of the set-up you'll see an app ID and an ad unit ID. In production these are the values you should add into your app. We will go over where you need to add them in your Flutter project shortly. In the future, you can also click on “Apps” in the sidebar and select “View All Apps” to get the app IDs. To get the ad unit IDs you need to select either an iOS or an Android app and view their respective ad units by clicking on “Ad units” in the sidebar.

It's important to reiterate that you should always use test ads when in development. There are two ways you could do this. One is to designate the device you are testing on as a test device (this way is more complex) and the other way, which we recommend, is using Google’s designated test ad unit IDs. Using the test IDs provided by Google will have you up and running with test ads instantly. You can grab the test IDs for every ad format for iOS here and for Android here.

Configuring & Initializing AdMob in a Flutter Project

Now that we know how to start the monetization process through your AdMob dashboard, let’s configure our Flutter project to be able to display ads.

iOS Configuration

First, let’s configure the iOS side of things. Head over to iOS>Runner>Info.plist. You need to add some code in here. We added it at the top following the <plist version="1.0"> and the <dict> tag. 

Info.plist

<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
<key>SKAdNetworkItems</key>
  <array>
    <dict>
      <key>SKAdNetworkIdentifier</key>
      <string>cstr6suwn9.skadnetwork</string>
    </dict>
  </array>

Here, the GADApplicationIdentifier holds a string value with the AdMob app ID for your iOS app that you created in the AdMob dashboard earlier. You can add your own app ID here, but for this tutorial we are adding Google’s sample app ID. The other thing we added here is the SKAdNetworkIdentifier and the string value here should stay exactly the same as shown in the snippet as it isn't specific to your AdMob account.

Android Configuration

Now, let’s configure our Android app. First, we need to make sure that the minSdkVersion is 19 or higher, otherwise you will get an error. To change it go to android>app>build.gradle and scroll down a bit to find the minSdkVersion.

Next, we need to add some code to the AndroidManifest.xml . To do this go to android>app>src>main>AndroidManifest.xml and add the following code.

AndroidManifest.xml

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

You can add this meta tag at the bottom of the file, right above the closing application tag. The android:value here should hold the string with your Android app ID that you can get from your AdMob dashboard. Once again, though, we are using a sample ID here provided by Google.

SDK Initialization

The last thing we are going to do in this section is initialize the Mobile Ads SDK. You must do this before you can start displaying ads. Luckily, initialization is incredibly simple. Head over to the main.dart file and import the plugin at the top. Now, in the main function right above runApp add the following two lines of code.

main.dart

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  MobileAds.instance.initialize();
  runApp(AppWidget());
}

That's all! Next, we are going to set up an easy way to fetch appropriate ad unit IDs based on the requested ad format and platform your app is running on.

Creating an AdHelper Class

In the app we are creating we want to display two types of ad formats - banner and interstitial. We're also using Flutter, which means we are creating an iOS and an Android app at the same time. What we need to do now is be able to retrieve the correct ad unit ID for the specific platform and ad format. To achieve this, we are going to create an AdHelper class. Create a new file in the lib>data folder and name it ad_helper.dart. Then add the following code to it. 

ad_helper.dart

class AdHelper {
  static String get bannerAdUnitId {
    if (Platform.isAndroid) {
      return "ca-app-pub-3940256099942544/6300978111";
    } else if (Platform.isIOS) {
      return "ca-app-pub-3940256099942544/2934735716";
    } else {
      throw new UnsupportedError("Unsupported platform");
    }
  }

  static String get interstitialAdUnitId {
    if (Platform.isAndroid) {
      return "ca-app-pub-3940256099942544/8691691433";
    } else if (Platform.isIOS) {
      return "ca-app-pub-3940256099942544/5135589807";
    } else {
      throw new UnsupportedError("Unsupported platform");
    }
  }
}

As you can see here, we have a class with two static getters. One to get the banner ad unit IDs and the other to get the interstitial ad unit IDs. We check if the platform is iOS or Android using the dart:io import and return the appropriate ad unit ID for each ad format. In the case where the platform doesn't resolve to be either iOS or Android we throw an error. Remember, we are using the test ad unit IDs here. You can get the test ad units for every format for iOS here and for Android here. Once your app is ready to be published, you can replace these ad unit IDs with the ones you created in your AdMob dashboard.

Displaying a Bottom Banner Ad

It’s finally time to add our first ad. This will be a banner ad and we will display it at the bottom of the screen. It will always be visible to the user, even as they are scrolling through the page. 

Setting up Variables and Functions

Before the user can see the ad, it needs to be created and then loaded. First, let’s import the Google Mobile Ads for Flutter plugin into the home_page.dart file and create a late variable that will hold the reference to the ad we'll create. This variable will be of type BannerAd, as that is exactly the object it will reference.

home_page.dart

class _HomePageState extends State<HomePage> {
  late BannerAd _bottomBannerAd;
...

Now, we want to be able to check if the ad is loaded before displaying it. So let’s create a variable of type bool to help us out with this. We will initially set it to false. That's because at the very beginning the ad won’t be loaded and we only want it to be set to true when it is.

home_page.dart

class _HomePageState extends State<HomePage> {
...
  bool _isBottomBannerAdLoaded = false;
...

Next we are going to write a function that will create and load the banner ad for us when called.

home_page.dart

class _HomePageState extends State<HomePage> {
...
 void _createBottomBannerAd() {
    _bottomBannerAd = BannerAd(
      adUnitId: AdHelper.bannerAdUnitId,
      size: AdSize.banner,
      request: AdRequest(),
      listener: BannerAdListener(
        onAdLoaded: (_) {
          setState(() {
            _isBottomBannerAdLoaded = true;
          });
        },
        onAdFailedToLoad: (ad, error) {
          ad.dispose();
        },
      ),
    );
    _bottomBannerAd.load();
  }
...

Let’s take a deeper look at what’s happening here. We are creating a BannerAd object and initializing the _bottomBannerAd variable with it. We are passing in several arguments to create the BannerAd object, let’s go over them now.

You can see we are using the AdHelper class we created earlier to get the banner ad unit ID. Then, we are specifying the dimensions for our ad. Adsize.banner will return an ad that is sized 320X50dp.

You can choose from several standard banner sizes or even create an adaptive banner size. Check out all of the standard banner sizes on the plugin's pub.dev page.

To display ads we need to make an ad request, so here we are providing an AdRequest object as an argument to do just that. We aren't providing any arguments to the AdRequest constructor in our implementation, but you can provide things such as a List of keywords here. This can be useful if you want to request ads which match the keywords you specify.

We are using BannerAdListener to listen to the ad’s lifecycle events and perform some logic when they occur. We're listening to onAdLoaded to find out when an ad loads and when it does we set our _isBottomBannerAdLoaded variable to true. We also listen to onAdFailedToLoad. So if the ad fails to load, we call the dispose method on it to make sure we free up the resources it is taking up. It's important to remember to call dispose here, so make sure you make this a habit. In your own implementations you can also listen to other events, such as when an ad is opened, closed or when an ad receives an impression.

We’ve covered all of the details for creating a BannerAd object. However, there's one more thing we are doing in our _createBottomBannerAd function that we haven’t covered yet. At the very end you can see we are calling the load method on _bottomBannerAd. This will load the ad we created. When the ad is loaded, the _isBottomBannerAdLoaded will be set to true and then we can finally display the ad.

Before we can add the ad into our widget tree, there are two more things we need to do. First, we need to call the _createBottomBannerAd function from the initState of _HomePageState. That is because we need the ad to load and be ready to be displayed when the user reaches this page.

home_page.dart

  
@override
void initState() {
  super.initState();
  _createBottomBannerAd();
}

The last thing we need to do is call dispose on _bottomBannerAd inside of the _HomePageState dispose method. This will ensure that we free up the resources when they are no longer needed.

home_page.dart

  
@override
void dispose() {
  super.dispose();
  _bottomBannerAd.dispose();
}

Displaying the Ad in the Widget Tree

Finally, we can add our ad to the page. If you want to have a banner ad that's fixed to the bottom of the screen, there are two easy ways to do this. If your app doesn’t have a bottom navigation bar, then you can add the AdWidget as the bottomNavigationBar argument of the Scaffold. If you do have a bottom nav bar, you can instead add it as a persistentFooterButtons argument of the Scaffold. This will place it above the bottom navigation bar. Since our app doesn’t have a bottom nav, we are going to add our ad to the bottomNavigationBar.

home_page.dart

  
@override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: _isBottomBannerAdLoaded
          ? Container(
              height: _bottomBannerAd.size.height.toDouble(),
              width: _bottomBannerAd.size.width.toDouble(),
              child: AdWidget(ad: _bottomBannerAd),
            )
          : null,
...

The first thing we are doing here, is checking to make sure that the _isBottomBannerAdLoaded is set to true, which would mean our ad is loaded and ready to be displayed. If that's the case, then we return an AdWidget wrapped in a Container. If the ad isn’t loaded, we just set the bottomNavigationBar to null, which is its default value anyway.

You should wrap the AdWidget in something like a Container and specify the height and width. If you don’t do that, the ad will take up the entire screen. We are using the size property of our _bottomBannerAd to specify the height and width. For the AdWidget itself, all we are doing is providing the _bottomBannerAd we created as an ad argument.

That’s it! Save your work, restart the app, and you should see the ad at the bottom of the screen. Next we are going to add another banner ad, but this time it'll show up inside of our ListView.

Displaying an Inline Banner Ad

Showing an inline banner ad involves a few extra steps. Since we are already familiar with the simpler implementation, this should be easy.

Setting up Variables and Functions

First, we are going to create three variables. One is for the index at which we want our ad to be displayed inside the ListView. In our app we are going to set that to 3. Then we need to create a late _inlineBannerAd variable to hold the reference to the banner ad we are going to create. Lastly, just like we did for the other banner ad, we need to be able to check if the ad is loaded before displaying it. For that we are going to add a _isInlineBannerAdLoaded variable and set it to false.

home_page.dart

  
class _HomePageState extends State<HomePage> {
  final _inlineAdIndex = 3;
  ...
  late BannerAd _inlineBannerAd;
  ...
  bool _isInlineBannerAdLoaded = false;
  ...

Next, we are going to create a function which is almost identical to the one we created earlier that will take care of creating a BannerAd and loading it.

home_page.dart

  
void _createInlineBannerAd() {
    _inlineBannerAd = BannerAd(
      size: AdSize.mediumRectangle,
      adUnitId: AdHelper.bannerAdUnitId,
      request: AdRequest(),
      listener: BannerAdListener(
        onAdLoaded: (_) {
          setState(() {
            _isInlineBannerAdLoaded = true;
          });
        },
        onAdFailedToLoad: (ad, error) {
          ad.dispose();
        },
      ),
    );
    _inlineBannerAd.load();
  }

There are a few things we need to note here. First, you’ll notice we are using a different size for this ad. AdSize.mediumRectangle will display an ad that's 320X250dp. Because of the rectangular appearance of our news tiles, this just seems more fitting here.

Here we're also using the AdHelper class to retrieve the same bannerAdUnitId we used for the previous ad. While this is convenient in our little demo, this isn’t the best practice in production. What you should be doing instead is creating separate ad units for every placement or activity in your app. This will allow you to track the performance of  individual ad units.

Everything else in this function is pretty much the same as in the one we created for our bottom banner ad.

Just like before, we need to call the _createInlineBannerAd function from inside of initState and call dispose from the dispose method.

home_page.dart

  
@override
void initState() {
  super.initState();
  ...
  _createInlineBannerAd();
}

@override
void dispose() {
  super.dispose();
  ...
  _inlineBannerAd.dispose();
}

Adding the Inline Banner Ad to the Widget Tree

The last thing left to do is to display the banner ad we just created within our ListView. We only want to display this ad if it has loaded, so we need to establish the appropriate checks for this. First, let’s change the itemCount in the ListView.builder to account for our ad.

home_page.dart

  
...
body: ListView.builder(
  padding: const EdgeInsets.all(10),
  itemCount:
      NewsArticle.articles.length + (_isInlineBannerAdLoaded ? 1 : 0),
...

Here we are saying that the itemCount should be equal to the length of the List of articles if the ad isn't loaded. If it is loaded then, we want to add one to that length value. This makes sense because displaying the ad would increase the number of items we have in the ListView by one.

Now, let’s move on to the itemBuilder argument. Here we want to display an AdWidget using _inlineBannerAd if two conditions are met. We want to display the AdWidget if the ad is loaded and if the current index is equal to the index where we want the ad positioned. Earlier, we defined that index under the _inlineAdIndex variable as 3. Also, just like for the bottom banner ad, we'll wrap this AdWidget in a Container and give it a height and width obtained using _inlineBannerAd.size.

home_page.dart

  
...
itemBuilder: (context, index) {
  if (_isInlineBannerAdLoaded && index == _inlineAdIndex) {
    return Container(
      padding: EdgeInsets.only(
        bottom: 10,
      ),
      width: _inlineBannerAd.size.width.toDouble(),
      height: _inlineBannerAd.size.height.toDouble(),
      child: AdWidget(ad: _inlineBannerAd),
    );
  } else {
      final article = NewsArticle.articles[index];
      return Padding(
        padding: const EdgeInsets.only(
          bottom: 10,
        ),
        child: GestureDetector(
          onTap: () {
            _showInterstitialAd();
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => NewsArticlePage(
                  title: article.headline,
                  imagePath: article.asset,
                ),
              ),
            );
          },
          child: ArticleTile(
            article: article,
          ),
        ),
      );
    }

So, now we’ve got the return statement for the Container with the AdWidget inside of an if block. The remainder of the itemBuilder function logic is inside of an else block.

We're almost done here, but there's one last thing left to do. If you take a look at the else block, you’ll see that we are getting individual NewsArticle objects from the list of articles. We're then storing them inside of the article variable. To do this we are using the current index provided to us by the itemBuilder function. The only problem here is that when we add the banner ad to the ListView we are increasing the itemCount. That means that the index we receive is based on that itemCount. The way our code is currently structured when we get the third NewsArticle object, its index is two. The next index is three, and that is the index at which we display our ad. In the eyes of the itemBuilder, the index after the ad is four. So, now if we try to get the next NewsArticle object after the ad, we will get back the fifth NewsArticle. The one we want to get is the fourth, not the fifth. To overcome this issue, we are going to create a helpful little function.

home_page.dart

  
int _getListViewItemIndex(int index) {
  if (index >= _inlineAdIndex && _isInlineBannerAdLoaded) {
    return index - 1;
  }
  return index;
}

This function takes in an index which will be provided by the itemBuilder. Then the function checks to see if the index it received is equal to or greater than the _inlineAdIndex. In the same if statement condition it will check if the inline banner ad is loaded. If this condition returns true, we'll decrement the index by one and return that. Otherwise, if the condition returns false, we'll simply return the unmodified index. Now, let’s replace the index in NewsArticle.articles[index] with this function call.

home_page.dart

  
...
else {
   final article = NewsArticle.articles[_getListViewItemIndex(index)];
...

This takes care of the issue beautifully! Now, this function will just return the unmodified index for any NewsArticle objects displayed before the ad and also in the case that the ad isn’t loaded. Otherwise, it will return the decremented index which will get us the NewsArticle object we need.

Let’s save our work and restart the app. Now, scroll down past the third article tile and you should see the inline ad.

Displaying an Interstitial Ad

Since we can almost call ourselves experts at displaying banner ads, let’s take things up a notch. The final ad we are going to implement will be an interstitial ad. Inside an app, interstitial ads are displayed as a full-screen overlay.

As best practice, you want to place these ads at natural transition points within your app. You definitely don’t want them to appear when a user is in the middle of an important task. Overuse of ads or poor ad placement can frustrate the user to the point of deleting your app from their device.

In our implementation we want to display this ad when a user taps to open one of the articles. We'll use a test ad unit ID provided by Google that's set up to display a video interstitial ad. Before the user gets to see the article, they must wait 5 seconds before they can dismiss this interstitial video ad. When the ad is dismissed, they will see the article.

Implementing interstitial ads is a bit different from banner ads. Once we break it down, though, you'll see how simple it really is.

Loading and Creating an Interstitial Ad

The thing about interstitial ads is that any given ad you load can only be displayed once. That’s why things will look a little bit different here compared to what you’re used to by now. It will all make more and more sense as we go through this section. First, we need to add a variable to _HomePageState that will hold the reference to our ad. This will be a nullable variable.

home_page.dart

  
  InterstitialAd? _interstitialAd;

Next, we need to create a function that will load the ad and initialize our _interstitialAd variable.

home_page.dart

  
void _createInterstitialAd() {
  InterstitialAd.load(
    adUnitId: AdHelper.interstitialAdUnitId,
    request: AdRequest(),
    adLoadCallback: InterstitialAdLoadCallback(
      onAdLoaded: (InterstitialAd ad) {
        _interstitialAd = ad;
      },
      onAdFailedToLoad: (LoadAdError error) {
        _interstitialAd = null;
        _createInterstitialAd();
      },
    ),
  );
}

Looking at this code snippet, you may have already noticed some differences. One change is that instead of creating an InterstitialAd object we are calling the InterstitialAd.load method. 

Some things still look familiar, though. We are providing the ad unit ID for our interstitial ad as an adUnitId argument. Then, we are passing in an AdRequest object to request the ad.

Lastly, we are using InterstitialAdLoadCallback to perform certain actions when an ad loads or fails to load.

When the ad loads, the function callback gets access to an InterstitialAd object. So here we are initializing the _interstitialAd variable we created earlier with the InterstitialAd object we get through this callback. In the case that the ad fails to load, we must set the _interstitialAd variable to null.

We'll be calling this _createInterstitialAd function every time we need to load a new ad. One case when we need to load a new ad, is every time we show an interstitial ad. That is because as we discussed earlier an interstitial ad can only be shows once.

So, why are we setting the _interstitialAd variable to null when an ad fails to load? Well, imagine a scenario where we just showed an interstitial ad and now we need to load another one. At that point, the _interstitialAd variable still references the previous InterstitialAd object. If our new ad loads and overrides the _interstitialAd variable with a new InterstitialAd object, there’s no issue, but what if that ad fails to load? If we don’t do anything about it, the variable will still reference that previous ad, which we already showed. That is an issue, because we never want to show the same interstitial ad more than once. Setting the _interstitialAd variable to null in the case that the ad fails to load will keep us safe from trying to display an ad we already showed. The one other thing we do in the case the ad fails to load is call the _createInterstitialAd function once more to try loading another ad. 

Ad Load Failure Optimization

The way we load a new ad, if an ad fails to load, could be optimized. The way we have the code set up now could become troublesome if something goes wrong and a failure keeps recurring indefinitely. If that happens, we'll never stop trying to load a new ad. So, what we want to do instead is set up some simple logic that will only allow a limited number of load retries.

First, let's add a const to represent the maximum number of ad load attempts we want to make in case an ad fails to load.  We'll add it above the HomePage widget.

home_page.dart

  
const int maxFailedLoadAttempts = 3;

class HomePage extends StatefulWidget {
...

Then, we need to add a variable that will keep track of how many ad load attempts were made. Add this variable inside the _HomePageState and initially set it to 0.

home_page.dart

  
class _HomePageState extends State<HomePage> {
...
int _interstitialLoadAttempts = 0;
...

To finish up this optimization let's make some changes to the listeners in the _createInterstitialAd function.

home_page.dart

  
...
adLoadCallback: InterstitialAdLoadCallback(
  onAdLoaded: (InterstitialAd ad) {
    _interstitialAd = ad;
    _interstitialLoadAttempts = 0;
  },
  onAdFailedToLoad: (LoadAdError error) {
    _interstitialLoadAttempts += 1;
    _interstitialAd = null;
    if (_interstitialLoadAttempts <= maxFailedLoadAttempts) {
      _createInterstitialAd();
    }
  },
),
...

Let's discuss what's happening here. Now, each time the ad fails to load, we increment the _interstitialLoadAttempts variable by 1. Then, we check to see if the number of attempts we made is less than or equal to the maximum load attempts we want to make. If that's the case, we attempt to load another ad. If the _interstitialLoadAttempts exceeds the maximum load attempts we want to make, then we won't try to load another ad. This will protect us from trying to load a new ad indefinitely in the case of an unresolvable failure.

One other thing we are doing here, is resetting the _interstitialLoadAttempts variable back to 0 when an ad loads successfully.

Now, we need to call the _createInterstitialAd function from within initState. We do this even before showing the ad because we want the ad to load and be immediately available when it's triggered to be shown. We also want to call dispose on the ad inside the dispose method of _HomePageState.

home_page.dart

  
@override
void initState() {
  super.initState();
...
  _createInterstitialAd();
}

@override
void dispose() {
  super.dispose();
...
  _interstitialAd?.dispose();
}

Displaying an Interstitial Ad

We are going to create another function for showing an interstitial ad . The code in this function will only run if the _interstitialAd variable is not null.

home_page.dart

  
void _showInterstitialAd() {
  if (_interstitialAd != null) {
    _interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
      onAdDismissedFullScreenContent: (InterstitialAd ad) {
         ad.dispose();
        _createInterstitialAd();
      },
      onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError error) {
        ad.dispose();
         _createInterstitialAd();
      },
    );
    _interstitialAd!.show();
  }
}

Here we are setting _interstitialAd!.fullScreenContent with a FullScreenContentCallback object. Using this object, we can listen to the ad’s lifecycle events and perform certain actions when they occur. You have access to more lifecycle events than we are using here. For example you can listen for when an impression occurs on an ad.

In our case, we only care about the onAdDismissedFullScreenContent and onAdFailedToShowFullScreenContent events. The first event occurs when an ad is dismissed. The onAdFailedToShowFullScreenContent event can occur in instances such as when you are trying to show an interstitial ad that has already been shown.

For both events we have access to the InterstitialAd object. As best practice you should always call dispose on the ad from both of these callbacks. That's exactly what we are doing here, using the InterstitialAd object we get from the callbacks. We're also calling _createInterstitialAd when either of these events occur. To reiterate, that is because an interstitial ad can only be shown once, so after we show an ad we need to generate a new one.

After setting up the callbacks we are calling the show method on our ad. This will display our ad to the user.

Now, let’s go ahead and trigger the _showInterstitialAd function from within our widget tree. Head over to the GestureDetector  widget within the itemBuilder  of the ListView.builder . Add the call to the _showInterstitialAd  right before Navigator.push .

home_page.dart

  
...
child: GestureDetector(
  onTap: () {
    _showInterstitialAd();
    Navigator.push(
...

This will ensure that when a user taps on an article tile they'll see the ad and also be routed to the article page. After 5 seconds the user will see a button they can press to dismiss the ad. When the ad is dismissed, the user will be able to see the article page.

Save your work, restart the app and tap on one of the articles. You should now see an interstitial video ad appear.

Want to display rewarded ads? Luckily, the rewarded ad implementation is nearly identical to that of interstitial ads. The main difference is one callback function that you need to set to specify what happens when a user earns the reward. Check out the official plugin example to see how your users can start earning ad rewards.

Conclusion

Amazing, you made it! You should now be able to start monetizing your Flutter apps through Google AdMob. Remember though, knowing how to place ads in your code is just one piece of the puzzle. If you are planning to use ads as a way to generate income from your apps, do your research on how to do it for maximum success.

You want your ad placement to be strategic and effective. You also should never jeopardize the overall user experience and bombard your users with ads. Make sure to use the metrics Google provides you with to see how your ads are performing and make educated decisions based on that data. Thanks for reading and happy coding!

About the author 

Ashley Novik

Ashley is a Flutter developer and tutor at Reso Coder with a passion for tech and an infinite drive to learn and teach others ?.
On her days off she enjoys exploring nature and powering through off-road trails on her mountain bike ?‍♀️.

You may also like

Flutter UI Testing with Patrol

Flutter UI Testing with Patrol
  • Hi Ashley,
    I know this question is unrelated but i’d like to know if getx is more advisable to use for state management

    • Hi Joshua,

      State management is a highly debated topic. For Flutter there are many options out there to choose from, so it can get overwhelming and confusing when trying to pick one. Getting familiar with several most popular options, such as Riverpod and Bloc/Cubit and then choosing whichever one you prefer and/or whichever one is most suitable for your particular project is likely the best way to go.

      So what I would suggest to you is to try building a small practice project using different state management options and seeing which one you’re most comfortable with and learning their benefits/drawbacks for different use cases.

      Hope this helps. 🙂

  • Thanks, Ashley Novik. It was a great help for me. Thanks for the clear documentation and the tutorial video. Thanks again.

  • your guide is excellent but I have a problem applying BannerAd to listview.separated. I have an error RangeError (index) Invalid Value> Not in inclusive range. Can you help me with this?

  • What i don’t understood is in reality how you’re now not really a lot more smartly-favored than you might be now. You’re very intelligent. You understand therefore significantly in terms of this topic, produced me personally believe it from a lot of numerous angles. Its like women and men are not interested except it is one thing to accomplish with Woman gaga! Your own stuffs outstanding. Always care for it up!

  • What i do not realize is in fact how you are no longer actually much more well-favored than you might be right now. You’re very intelligent. You recognize thus considerably in relation to this topic, made me in my view believe it from numerous numerous angles. Its like men and women are not fascinated until it is one thing to do with Lady gaga! Your own stuffs excellent. All the time handle it up!

  • Simply wish to say your article is as amazing. The clearness in your post is just nice and i could assume you’re an expert on this subject. Well with your permission let me to grab your feed to keep updated with forthcoming post. Thanks a million and please carry on the gratifying work.

  • Thanks, I have recently been looking for info about this subject for a while and yours is the greatest I have discovered so far. However, what in regards to the bottom line? Are you certain in regards to the supply?

  • of course like your website but you have to check the spelling on several of your posts. A number of them are rife with spelling issues and I in finding it very troublesome to inform the reality on the other hand I will certainly come back again.

  • Thank you I have just been searching for information approximately this topic for a while and yours is the best I have found out so far However what in regards to the bottom line Are you certain concerning the supply

  • you are truly a just right webmaster The site loading speed is incredible It kind of feels that youre doing any distinctive trick In addition The contents are masterwork you have done a great activity in this matter

  • Modern Talking был немецким дуэтом, сформированным в 1984 году. Он стал одним из самых ярких представителей евродиско и популярен благодаря своему неповторимому звучанию. Лучшие песни включают “You’re My Heart, You’re My Soul”, “Brother Louie”, “Cheri, Cheri Lady” и “Geronimo’s Cadillac”. Их музыка оставила неизгладимый след в истории поп-музыки, захватывая слушателей своими заразительными мелодиями и запоминающимися текстами. Modern Talking продолжает быть популярным и в наши дни, оставаясь одним из символов эпохи диско. Музыка 2024 года слушать онлайн и скачать бесплатно mp3.

  • Bwer Pipes: Your Key to Agricultural Success in Iraq: Count on Bwer Pipes to provide you with high-quality irrigation solutions designed to meet the demands of Iraqi farming. Our cutting-edge sprinkler systems and reliable pipes ensure precise water distribution, contributing to healthier crops and increased profitability. Visit Bwer Pipes

  • The level of my admiration for your work mirrors your own sentiment. The sketch is elegant, and the authored material is stylish. Nevertheless, you appear concerned about the prospect of embarking on something that may be seen as dubious. I agree that you’ll be able to address this issue promptly.

  • Somebody essentially lend a hand to make significantly posts I might state That is the very first time I frequented your web page and up to now I surprised with the research you made to create this particular put up amazing Excellent job

  • Your blog is a treasure trove of valuable insights and thought-provoking commentary. Your dedication to your craft is evident in every word you write. Keep up the fantastic work!

  • helloI really like your writing so a lot share we keep up a correspondence extra approximately your post on AOL I need an expert in this house to unravel my problem May be that is you Taking a look ahead to see you

  • Wow amazing blog layout How long have you been blogging for you made blogging look easy The overall look of your web site is magnificent as well as the content

  • Its like you read my mind You appear to know so much about this like you wrote the book in it or something I think that you can do with a few pics to drive the message home a little bit but other than that this is fantastic blog A great read Ill certainly be back

  • Hi i think that i saw you visited my web site thus i came to Return the favore I am attempting to find things to improve my web siteI suppose its ok to use some of your ideas

  • Your blog is a shining example of excellence in content creation. I’m continually impressed by the depth of your knowledge and the clarity of your writing. Thank you for all that you do.

  • Belo blog aqui Além disso, seu site carrega muito rápido Qual host você está usando Posso obter seu link de afiliado para seu host? Desejo que meu site carregue tão rápido quanto o seu haha

  • Simply desire to say your article is as surprising The clearness in your post is simply excellent and i could assume you are an expert on this subject Fine with your permission let me to grab your feed to keep up to date with forthcoming post Thanks a million and please carry on the gratifying work

  • obviously like your website but you need to test the spelling on quite a few of your posts Several of them are rife with spelling problems and I to find it very troublesome to inform the reality on the other hand Ill certainly come back again

  • Corrugated Metal Pipes in Iraq: At Elite Pipe Factory in Iraq, we also specialize in the production of Corrugated Metal Pipes, which are designed for strength and resilience in heavy-duty applications. Our corrugated metal pipes are constructed to handle high loads and resist environmental stresses, making them suitable for use in stormwater management, road construction, and culverts. With our commitment to quality and innovation, Elite Pipe Factory ensures that these pipes provide exceptional performance and durability. As one of the leading and most trusted factories in Iraq, we pride ourselves on offering products that exceed expectations. Learn more about our Corrugated Metal Pipes on our website elitepipeiraq.com.

  • I am not sure where youre getting your info but good topic I needs to spend some time learning much more or understanding more Thanks for magnificent info I was looking for this information for my mission

  • I loved as much as you will receive carried out right here The sketch is attractive your authored material stylish nonetheless you command get got an impatience over that you wish be delivering the following unwell unquestionably come more formerly again since exactly the same nearly a lot often inside case you shield this hike

  • Houzzmagazine naturally like your web site however you need to take a look at the spelling on several of your posts. A number of them are rife with spelling problems and I find it very bothersome to tell the truth on the other hand I will surely come again again.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
    >