Adding AdMob ads to a Flutter app

1. Introduction

What you'll build

This codelab guides you through adding a banner, interstitial, and a rewarded ad to an app called Awesome Drawing Quiz, a game that lets players guess the name of the drawing.

If you run into any issues (code bugs, grammatical errors, unclear wording) as you work through this codelab, please report the issue by clicking the Report a mistake link in the lower, left corner of the codelab.

What you'll learn

  • How to configure the Google Mobile Ads AdMob plugin
  • How to implement a banner, interstitial and rewarded ads in a Flutter app

What you'll need

  • Android Studio 4.1 or later
  • Xcode 12 or later (for iOS development)

How would you rate your level of experience with AdMob?

Novice Intermediate Proficient

How would you rate your level of experience with Flutter?

Novice Intermediate Proficient

2. Set up your Flutter development environment

You need two pieces of software to complete this lab—the Flutter SDK and an editor.

You can run the codelab using any of these devices:

  • A physical Android or iOS device connected to your computer and set to Developer mode.
  • The iOS simulator (requires installing Xcode tools).
  • The Android Emulator (requires setup in Android Studio).
  • A browser (Chrome is required for debugging).
  • As a Windows, Linux, or macOS desktop application. You must develop on the platform where you plan to deploy. So, if you want to develop a Windows desktop app, you must develop on Windows to access the appropriate build chain. There are operating system-specific requirements that are covered in detail on docs.flutter.dev/desktop.

Download the code

After you download the zip file, extract its contents. You will have a folder named admob-ads-in-flutter-master.

Alternatively, you can clone the GitHub repository from the command line:

$ git clone https://github.com/googlecodelabs/admob-ads-in-flutter

The repository contains two folders:

  • android_studio_folder.pngstarter — Starting code that you will build in this codelab.
  • android_studio_folder.pngcomplete — Completed code for this codelab.

3. Set up the AdMob app and ad units

Because Flutter is a multi-platform SDK, you need to add an app and ad units for both Android and iOS in AdMob.

Set up for Android

To set up for Android, you need to add an Android app and create ad units.

Add an Android app

  1. In the AdMob console, click ADD APP from the Apps menu.
  2. When you're asked Have you published your app on Google Play or the App Store?, click NO.
  3. Enter Awesome Drawing Quiz in the app name field, and select Android as the platform.

ddafee37a6f92229.png

  1. Enabling user metrics is not necessary to complete this codelab. However, we recommend that you do because it allows you to understand user behavior in more detail. Click ADD to complete the process.

b918bf44362813a9.png

Create ad units

To start adding ad units to AdMob:

  1. Select Awesome Drawing Quiz from the Apps menu in the AdMob console.
  2. Click the Ad units menu.

Banner

  1. Click the ADD AD UNIT button.
  2. Select Banner as the format.
  3. Enter android-adq-banner in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

Interstitial

  1. Click the ADD AD UNIT button.
  2. Select Interstitial as the format.
  3. Enter android-adq-interstitial in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

Rewarded

  1. Click the ADD AD UNIT button.
  2. Select Rewarded as the format.
  3. Enter android-adq-rewarded in the Ad unit name field.
  4. Leave the default for Reward settings.
  5. Click CREATE AD UNIT to complete the process.

It usually takes a few hours for a new ad unit to be able to serve ads.

If you want to test the ad's behavior immediately, then use the test app ID and ad unit IDs listed in the Android app ID/ad unit ID and iOS app ID/ad unit ID tables.

Set up for iOS

To set up for iOS, you need to add an iOS app and create ad units.

Add an iOS app

  1. In the AdMob console, click ADD APP from the Apps menu.
  2. When you're asked Have you published your app on Google Play or the App Store?, click NO.
  3. Enter Awesome Drawing Quiz in the app name field, and select iOS as the platform.

93e7f9f114232402.png

  1. Enabling user metrics is not necessary to complete this codelab. However, we recommend that you do because it allows you to understand user behavior in more detail. Click ADD to complete the process.

b918bf44362813a9.png

Create ad units

To add ad units:

  1. Select Awesome Drawing Quiz app from Apps menu in the AdMob console.
  2. Click the Ad units menu.

Banner

  1. Click the ADD AD UNIT button.
  2. Select Banner as the format.
  3. Enter ios-adq-banner in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

Interstitial

  1. Click the ADD AD UNIT button.
  2. Select Interstitial as the format.
  3. Enter ios-adq-interstitial in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

Rewarded

  1. Click the ADD AD UNIT button.
  2. Select Rewarded as the format.
  3. Enter ios-adq-rewarded in the Ad unit name field.
  4. Leave the default for Reward settings.
  5. Click CREATE AD UNIT to complete the process.

It usually takes a few hours for a new ad unit to be able to serve ads.

If you want to test the ad's behavior immediately, then use the test app ID and ad unit IDs listed in the following table.

Optional: Use the test AdMob app and ad units

If you want to follow the codelab instead of creating a new application and ad units on your own, you can use the test AdMob app ID and ad unit IDs listed in the following tables.

Android app ID/ad unit ID

Item

app ID/ad unit ID

AdMob app ID

ca-app-pub-3940256099942544~3347511713

Banner

ca-app-pub-3940256099942544/6300978111

Interstitial

ca-app-pub-3940256099942544/1033173712

Rewarded

ca-app-pub-3940256099942544/5224354917

iOS app ID/ad unit ID

Item

app ID/ad unit ID

AdMob app ID

ca-app-pub-3940256099942544~1458002511

Banner

ca-app-pub-3940256099942544/2934735716

Interstitial

ca-app-pub-3940256099942544/4411468910

Rewarded

ca-app-pub-3940256099942544/1712485313

For more information about the test ads, see the Android test ads and the iOS test ads developer documentation.

4. Add the Google Mobile Ads Flutter plugin

Flutter uses plugins to provide access to a wide range of platform-specific services. Plugins enable you to access services and APIs on each platform.

The google_mobile_ads plugin supports loading and displaying banner, interstitial, rewarded, and native ads using the AdMob API.

Because Flutter is a multi-platform SDK, the google_mobile_ads plugin is applicable for both iOS and Android. So, if you add the plugin to your Flutter app, it's used by both Android and iOS versions of the AdMob inline ads app.

Add the Google Mobile Ads plugin as a dependency

To access the AdMob APIs from the AdMob inline ads project, add google_mobile_ads as a dependency to the pubspec.yaml file located at the root of the project.

pubspec.yaml

...
environment:
  # TODO: Update the minimum sdk version to 2.12.0 to support null safety.
  sdk: ">=2.17.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  google_fonts: ^3.0.1

  # TODO: Add google_mobile_ads as a dependency
  google_mobile_ads: ^1.2.0

...

Click Pub get to install the plugin in the Awesome Drawing Quiz project.

9ce73858eedbd8fc.png

Update AndroidManifest.xml (Android)

  1. Open the android/app/src/main/AndroidManifest.xml file in Android Studio.
  2. Add your AdMob app ID by adding a <meta-data> tag with the name com.google.android.gms.ads.APPLICATION_ID. For example, if your AdMob app ID is ca-app-pub-3940256099942544~3347511713, then you need to add the following lines to the AndroidManifest.xml file.

AndroidManifest.xml

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

</manifest>

Update Info.plist (iOS)

  1. Open the ios/Runner/Info.plist file in Android Studio.
  2. Add a GADApplicationIdentifier key with the string value of your AdMob app ID. For example, if your AdMob app ID is ca-app-pub-3940256099942544~1458002511, then you need to add the following lines to the Info.plist file.

ios/Runner/Info.plist

...
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
...

5. Add a helper class for ads

Create a new file named ad_helper.dart under the lib directory. Then, implement the AdHelper class, which provides an AdMob app ID and ad unit IDs for Android and iOS.

Make sure that you replace the AdMob app ID (ca-app-pub-xxxxxx~yyyyy) and the ad unit ID (ca-app-pub-xxxxxxx/yyyyyyyy) with the IDs you created in the previous step.

lib/ad_helper.dart

import 'dart:io';

class AdHelper {

  static String get bannerAdUnitId {
    if (Platform.isAndroid) {
      return '<YOUR_ANDROID_BANNER_AD_UNIT_ID>';
    } else if (Platform.isIOS) {
      return '<YOUR_IOS_BANNER_AD_UNIT_ID>';
    } else {
      throw UnsupportedError('Unsupported platform');
    }
  }

  static String get interstitialAdUnitId {
    if (Platform.isAndroid) {
      return '<YOUR_ANDROID_INTERSTITIAL_AD_UNIT_ID>';
    } else if (Platform.isIOS) {
      return '<YOUR_IOS_INTERSTITIAL_AD_UNIT_ID>';
    } else {
      throw UnsupportedError('Unsupported platform');
    }
  }

  static String get rewardedAdUnitId {
    if (Platform.isAndroid) {
      return '<YOUR_ANDROID_REWARDED_AD_UNIT_ID>';
    } else if (Platform.isIOS) {
      return '<YOUR_IOS_REWARDED_AD_UNIT_ID>';
    } else {
      throw UnsupportedError('Unsupported platform');
    }
  }
}

Use the following code snippet if you want to use the test AdMob app ID and test ad unit IDs.

lib/ad_helper.dart

import 'dart:io';

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/1033173712";
    } else if (Platform.isIOS) {
      return "ca-app-pub-3940256099942544/4411468910";
    } else {
      throw new UnsupportedError("Unsupported platform");
    }
  }

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

6. Initialize the Google Mobile Ads SDK

Before loading ads, you need to initialize the Google Mobile Ads SDK. Open the lib/home_route.dart file, and modify _initGoogleMobileAds() to initialize the SDK before the home page is loaded.

Note that you need to change the return type of the _initGoogleMobileAds() method from Future<dynamic> to Future<InitializationStatus> to get the SDK initialization result after it completes.

home_route.dart

// TODO: Import google_mobile_ads.dart
import 'package:google_mobile_ads/google_mobile_ads.dart';

import 'package:flutter/material.dart';

...

class HomeRoute extends StatelessWidget {

  ...

  Future<InitializationStatus> _initGoogleMobileAds() {
    // TODO: Initialize Google Mobile Ads SDK
    return MobileAds.instance.initialize();
  }
}

7. Add a banner ad

In this section, you display a banner ad at the top of the game screen, as shown in the following screenshot.

276b4cfa283ea6c7.png

  1. Open the lib/game_route.dart file, and import ad_manager.dart
  2. Import the ad_helper.dart and google_mobile_ads.dart by adding the following lines:

lib/game_route.dart

...

// TODO: Import ad_helper.dart
import 'package:awesome_drawing_quiz/ad_helper.dart';

// TODO: Import google_mobile_ads.dart
import 'package:google_mobile_ads/google_mobile_ads.dart';

class GameRoute extends StatefulWidget {
  ...
}
  1. In the _GameRouteState class, add the following members for a banner ad.

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  // TODO: Add _bannerAd
  BannerAd? _bannerAd;

  ...
}
  1. In the initState() method, create and load a BannerAd for the 320x50 banner (AdSize.banner). Note that an ad event listener is configured to update the UI (setState()) when an ad is loaded .

lib/game_route.dart

@override
void initState() {
  ...

  // TODO: Load a banner ad
  BannerAd(
    adUnitId: AdHelper.bannerAdUnitId,
    request: AdRequest(),
    size: AdSize.banner,
    listener: BannerAdListener(
      onAdLoaded: (ad) {
        setState(() {
          _bannerAd = ad as BannerAd;
        });
      },
      onAdFailedToLoad: (ad, err) {
        print('Failed to load a banner ad: ${err.message}');
        ad.dispose();
      },
    ),
  ).load();
}
  1. Modify the build() method to display a banner ad when available.

lib/game_route.dart

@override
Widget build(BuildContext context) {
  return Scaffold(
    ...
    body: SafeArea(
      child: Stack(
        children: [
          Center(
            ...
          ),
          // TODO: Display a banner when ready
          if (_bannerAd != null)
            Align(
              alignment: Alignment.topCenter,
              child: Container(
                width: _bannerAd!.size.width.toDouble(),
                height: _bannerAd!.size.height.toDouble(),
                child: AdWidget(ad: _bannerAd!),
              ),
            ),
        ],
      ),
    ),
    ...
  );
}
  1. Release the resource associated with the BannerAd object by calling the BannerAd.dispose() method in the dispose() callback method.

lib/game_route.dart

@override
void dispose() {
  // TODO: Dispose a BannerAd object
  _bannerAd?.dispose();

  ...

  super.dispose();
}

That's it! Run the project, and start a new game. After an ad is loaded, you'll see a banner ad at the top of the screen.

276b4cfa283ea6c7.png

8. Add an interstitial ad

In this section, you display an interstitial ad after the game (5 levels in total) finishes.

  1. Open the lib/game_route.dart file
  2. In the _GameRouteState class, add the following members and methods for an interstitial ad.

Note that an ad event listener is configured to check whether the ad is ready (onAdLoaded() and onAdFailedToLoad()) and to display the app's home screen when the ad is closed (onAdDismissedFullScreenContent())

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  // TODO: Add _interstitialAd
 InterstitialAd? _interstitialAd;

  // TODO: Implement _loadInterstitialAd()
  void _loadInterstitialAd() {
    InterstitialAd.load(
      adUnitId: AdHelper.interstitialAdUnitId,
      request: AdRequest(),
      adLoadCallback: InterstitialAdLoadCallback(
        onAdLoaded: (ad) {
          ad.fullScreenContentCallback = FullScreenContentCallback(
            onAdDismissedFullScreenContent: (ad) {
              _moveToHome();
            },
          );

          setState(() {
            _interstitialAd = ad;
          });
        },
        onAdFailedToLoad: (err) {
          print('Failed to load an interstitial ad: ${err.message}');
        },
      ),
    );
  }

  ...
}
  1. In this codelab, an interstitial ad is displayed after a user completes 5 levels. To minimize unnecessary ad requests, request an ad when a user reaches level 3.

In the onNewLevel() method, add the following lines.

lib/game_route.dart

@override
void onNewLevel(int level, Drawing drawing, String clue) {
  ...

  // TODO: Load an Interstitial Ad
  if (level >= 3 && _interstitialAd == null) {
    _loadInterstitialAd();
  }
}
  1. When a game finishes, the game score dialog is displayed. When a user closes the dialog, it routes a user to the home screen of the Awesome Drawing Quiz.

Because interstitial ads should be displayed between screen transitions, we show the interstitial ad when a user clicks the CLOSE button.

Modify the onGameOver() method as follows.

lib/game_route.dart

@override
void onGameOver(int correctAnswers) {
  showDialog(
    context: _scaffoldKey.currentContext,
    builder: (context) {
      return AlertDialog(
        title: Text('Game over!'),
        content: Text('Score: $correctAnswers/5'),
        actions: [
          FlatButton(
            child: Text('close'.toUpperCase()),
            onPressed: () {

              // TODO: Display an Interstitial Ad
              if (_interstitialAd != null) {
                _interstitialAd?.show();
              } else {
                _moveToHome();
              }
            },
          ),
        ],
      );
    },
  );
}
  1. Release the resource associated with the InterstitialAd object by calling the InterstitialAd.dispose() method in the dispose() callback method.

lib/game_route.dart

@override
void dispose() {
  ...

  // TODO: Dispose an InterstitialAd object
  _interstitialAd?.dispose();

  ...

  super.dispose();
}

That's it! Run the project and complete the game. If an interstitial ad is loaded, you'll see an interstitial ad once you click CLOSE button from the score dialog.

c546e438c405e941.gif

9. Add a rewarded ad

In this section, you add a rewarded ad which gives a user an additional hint as a reward.

  1. Open the lib/game_route.dart file
  2. In the _GameRouteState class, add members for a rewarded ad, and implement _loadRewardedAd() method. Note that it loads another rewarded ad when the ad is closed (onAdDismissedFullScreenContent) to cache the ad as early as possible.

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  // TODO: Add _rewardedAd
  RewardedAd? _rewardedAd;

  // TODO: Implement _loadRewardedAd()
  void _loadRewardedAd() {
    RewardedAd.load(
      adUnitId: AdHelper.rewardedAdUnitId,
      request: AdRequest(),
      rewardedAdLoadCallback: RewardedAdLoadCallback(
        onAdLoaded: (ad) {
          ad.fullScreenContentCallback = FullScreenContentCallback(
            onAdDismissedFullScreenContent: (ad) {
              setState(() {
                ad.dispose();
                _rewardedAd = null;
              });
              _loadRewardedAd();
            },
          );

          setState(() {
            _rewardedAd = ad;
          });
        },
        onAdFailedToLoad: (err) {
          print('Failed to load a rewarded ad: ${err.message}');
        },
      ),
    );
  }

  ...
}
  1. Call _loadRewardedAd() from initState() method to request a rewarded ad when the game starts.

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  @override
  void initState() {
    ...

    // COMPLETE: Load a Rewarded Ad
    _loadRewardedAd();
  }


  ...
}
  1. Allow users to watch a rewarded ad by clicking the floating action button. The button shows only if a user hasn't used a hint at the current level and a rewarded ad is loaded.

Modify the _buildFloatingActionButton() method, as follows, to display the floating action button. Note that returning null hides the button from the screen.

Note that onUserEarnedReward is the most important ad event in a rewarded ad. It's triggered when a user becomes eligible to receive a reward (for example., finished watching a video).

In this codelab, the QuizManager.instance.useHint() method is called from the callback, which reveals one more character in the hint string. The app reloads a rewarded ad in the onAdClosed callback to make sure the ad is ready as early as possible.

lib/game_route.dart

Widget? _buildFloatingActionButton() {
  // TODO: Return a FloatingActionButton if a rewarded ad is available
  return (!QuizManager.instance.isHintUsed && _rewardedAd != null)
      ? FloatingActionButton.extended(
          onPressed: () {
            showDialog(
              context: context,
              builder: (context) {
                return AlertDialog(
                  title: Text('Need a hint?'),
                  content: Text('Watch an Ad to get a hint!'),
                  actions: [
                    TextButton(
                      child: Text('cancel'.toUpperCase()),
                      onPressed: () {
                        Navigator.pop(context);
                      },
                    ),
                    TextButton(
                      child: Text('ok'.toUpperCase()),
                      onPressed: () {
                        Navigator.pop(context);
                        _rewardedAd?.show(
                          onUserEarnedReward: (_, reward) {
                            QuizManager.instance.useHint();
                          },
                        );
                      },
                    ),
                  ],
                );
              },
            );
          },
          label: Text('Hint'),
          icon: Icon(Icons.card_giftcard),
        )
      : null;
}
  1. Release the resource associated with the RewardedAd object by calling the RewardedAd.dispose() method in the dispose() callback method.

lib/game_route.dart

@override
void dispose() {
  ...

  // TODO: Dispose a RewardedAd object
  _rewardedAd?.dispose();

  ...

  super.dispose();
}

That's it! Run the project and play the game. Once a rewarded ad is loaded, you'll see a hint button at the bottom of the screen. Click Hint button to get an additional hint.

4a114d243ae3e71d.gif

10. All done!

You have completed the codelab. You can find the completed code for this codelab in the android_studio_folder.pngcomplete folder.

To learn how to implement a banner and native inline ads, check out the Adding an AdMob banner and native inline ads to a Flutter app codelab.

To learn more, try the other Flutter codelabs.