What you'll build

This codelab guides you through adding an AdMob banner, an interstitial ad, 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

What you'll need

How would you rate your level of experience with AdMob?

Novice Intermediate Proficient

What would you like to learn from this codelab?

I'm new to the topic, and I want a good overview. I know something about this topic, but I want a refresher. I'm looking for example code to use in my project. I'm looking for an explanation of something specific.

You need to set up a Firebase project to serve AdMob ads with the Firebase AdMob Plugin.

Create a Firebase project

  1. In the Firebase console, click Add project.
  2. Enter Awesome Drawing Quiz as the project name.
  3. Enable Google Analytics for your project and click Continue.


  4. Choose the analytics location and settings that apply to your project. Read and accept the terms, and then click Create project.


  5. After a minute or so, your Firebase project is ready.

Register the app with Firebase

In the Firebase console, select the Awesome Drawing Quiz project that you created in the previous step.

Register an Android app

  1. In the center of the project overview page, click the Android icon to launch the setup workflow.
  2. Enter com.codelab.awesomedrawingquiz in the Android package name field.
  3. Enter Awesome Drawing Quiz (Android) in the App nickname field.
  4. Click Register app.
  5. Download the google-services.json file for future use.

Register an iOS app

  1. In the center of the project overview page, click the iOS icon or Add app (+) icon to launch the setup workflow.
  2. Enter com.codelab.awesomedrawingquiz in the iOS bundle ID field.
  3. Enter Awesome Drawing Quiz (iOS) in the App nickname field.
  4. Click Register app.
  5. Download the GoogleService-Info.plist file for future use.

Add a Firebase configuration file

The following instructions tell you how to configure Firebase for both Android and iOS.

Configure for Android

  1. Open the starter project in Android Studio by referring Import the starter project section in Set up the development environment step in this codelab.
  2. Move the google-services.json file into the android/app directory of the Awesome Drawing Quiz Flutter project.


  3. In the root-level (project-level) Gradle file (android/build.gradle), add rules to include the Google Services Gradle plugin. Check that you have Google's Maven repository.

android/build.gradle

buildscript {

    repositories {
      // Check that you have the following line (if not, add it):
      google()  // Google's Maven repository
    }

    ...

    dependencies {
      ...

      // TODO: Add Google Services plugin
      classpath 'com.google.gms:google-services:4.3.3'
    }
}

allprojects {
    ...

    repositories {
      // Check that you have the following line (if not, add it):
      google()  // Google's Maven repository
      ...
    }
}
  1. In the module (app-level) Gradle file (android/app/build.gradle), apply the Google Services Gradle plugin.

android/app/build.gradle

...

// TODO: Apply google-services plugin
apply plugin: 'com.google.gms.google-services'

android {
  ...
}

...

Configure for iOS

  1. Open the starter project in Android Studio by referring Import the starter project section in Set up the development environment step in this codelab.
  2. Open any file under the ios directory. (for example, ios/Runner/AppDelegate.swift)
  3. Click Open iOS module in Xcode.


  4. In Xcode, drag the GoogleService-Info.plist file into the Runner directory, to import the configuration file into the Xcode project.

Use the following AdMob app ID and ad unit ID prepared for this codelab.

Android

Item

app ID/ad unit ID

AdMob app ID

ca-app-pub-3940256099942544~4354546703

Banner

ca-app-pub-3940256099942544/8865242552

Interstitial

ca-app-pub-3940256099942544/7049598008

Rewarded

ca-app-pub-3940256099942544/8673189370

iOS

Item

app ID/ad unit ID

AdMob app ID

ca-app-pub-3940256099942544~2594085930

Banner

ca-app-pub-3940256099942544/4339318960

Interstitial

ca-app-pub-3940256099942544/3964253750

Rewarded

ca-app-pub-3940256099942544/7552160883

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

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

Because Flutter is a multi-platform SDK, the firebase_admob plugin is applicable for both iOS and Android. So, if you add the plugin to your Flutter app, it is used by both the Android and iOS versions of the Awesome Drawing Quiz app.

Adding the Firebase AdMob plugin as a dependency

To access the AdMob APIs from the Awesome Drawing Quiz project, add the firebase_admob plugin as a dependency to the pubspec.yaml file located at the root of the project.

pubspec.yaml

...

dependencies:
  flutter:
    sdk: flutter
  google_fonts: ^0.3.9

  # Add the following line
  firebase_admob: ^0.9.3

...

Click Packages get to install the plugin into the Awesome Drawing Quiz project.

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 and entering com.google.android.gms.ads.APPLICATION_ID. If your AdMob app ID is ca-app-pub-3940256099942544~3347511713, then you need to add the following lines to the AndroidManifest.xml file.

android/app/src/main/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>
...

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

lib/ad_manager.dart

import 'dart:io';

class AdManager {

  static String get appId {
    if (Platform.isAndroid) {
      return "ca-app-pub-3940256099942544~4354546703";
    } else if (Platform.isIOS) {
      return "ca-app-pub-3940256099942544~2594085930";
    } else {
      throw new UnsupportedError("Unsupported platform");
    }
  }

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

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

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

Before loading ads, you need to initialize the AdMob SDK. Open the lib/home_route.dart file, and modify _initAdMob() to initialize the SDK before the game starts.

lib/home_route.dart

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

import 'package:awesome_drawing_quiz/app_theme.dart';

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

import 'package:flutter/material.dart';

...

class _HomeRouteState extends State<HomeRoute> {

  ...

  Future<void> _initAdMob() {
    // TODO: Initialize AdMob SDK
    return FirebaseAdMob.instance.initialize(appId: AdManager.appId);
  }
}

In this section, you add a banner ad at the top of the game screen, as shown.

Open the lib/game_route.dart file, and import ad_manager.dart and firebase_admob.dart by adding the following lines:

lib/game_route.dart

...

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

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

class GameRoute extends StatefulWidget {
  ...
}

Next, in the _GameRouteState class, add the following member and methods for the banner ad.

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {
  
  ...

  // TODO: Add _bannerAd
  BannerAd _bannerAd;

  ...

  // TODO: Implement _loadBannerAd()
  void _loadBannerAd() {
    _bannerAd
      ..load()
      ..show(anchorType: AnchorType.top);
  }

  ...
}

In the initState() method, create a BannerAd object, and load the banner ad. Note that the banner displays a 320x50 banner (AdSize.banner).

lib/game_route.dart

@override
void initState() {
  ...
 
  // TODO: Initialize _bannerAd
  _bannerAd = BannerAd(
      adUnitId: AdManager.bannerAdUnitId,
      size: AdSize.banner,
  );

  // TODO: Load a Banner Ad
  _loadBannerAd();
}

Finally, 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 BannerAd object
  _bannerAd?.dispose();

  ...

  super.dispose();
}

That's it! Run the project, to see a banner ad shown at the top of the game screen.

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

First, add the following members and methods for the interstitial ad in the _GameRouteState class.

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {
  
  ...

  // TODO: Add _interstitialAd
  InterstitialAd _interstitialAd;

  // TODO: Add _isInterstitialAdReady
  bool _isInterstitialAdReady;

  ...

  // TODO: Implement _loadInterstitialAd()
  void _loadInterstitialAd() {
    _interstitialAd.load();
  }

  // TODO: Implement _onInterstitialAdEvent()
  void _onInterstitialAdEvent(MobileAdEvent event) {
    switch (event) {
      case MobileAdEvent.loaded:
        _isInterstitialAdReady = true;
        break;
      case MobileAdEvent.failedToLoad:
        _isInterstitialAdReady = false;
        print('Failed to load an interstitial ad');
        break;
      case MobileAdEvent.closed:
        _moveToHome();
        break;
      default:
      // do nothing
    }
  }

  ...
}

Next, initialize _isInterstitialAdReady and _interstitialAd in the initState() method. Because _onInterstitialAdEvent is configured as an ad event listener for _interstitialAd, every ad event from _interstitialAd is delivered to the _onInterstitialAdEvent method.

lib/game_route.dart

@override
void initState() {
  ...

  // TODO: Initialize _isInterstitialAdReady
  _isInterstitialAdReady = false;
 
  // TODO: Initialize _interstitialAd
  _interstitialAd = InterstitialAd(
    adUnitId: AdManager.interstitialAdUnitId,
    listener: _onInterstitialAdEvent,
  );
}

In this codelab, an interstitial ad is displayed after a user completes 5 levels. To minimize unnecessary ad requests, we start loading 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 && !_isInterstitialAdReady) {
    _loadInterstitialAd();
  }
}

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: <Widget>[
          FlatButton(
            child: Text('close'.toUpperCase()),
            onPressed: () {
              
              // TODO: Display an Interstitial Ad
              if (_isInterstitialAdReady) {
                _interstitialAd.show();
              }

              _moveToHome();
            },
          ),
        ],
      );
    },
  );
}

Finally, 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 InterstitialAd object
  _interstitialAd?.dispose();

  ...

  super.dispose();
}

That's it! Run the project to see an interstitial ad displayed after the game finishes.

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

First, add the members and methods for the rewarded ad in the _GameRouteState class. Note that RewardedVideoAd is a singleton object, so you don't need to have a member for managing the instance of the RewardedVideoAd class.

RewardedVideoAdEvent.rewarded 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, RewardedVideoAdEvent.rewarded calls the QuizManager.instance.useHint() method which reveals one more character in the hint string.

Also, according to the ad event, RewardedVideoAdEvent.rewarded updates the UI by changing the value of _isRewardedAdReady. Note that _isRewardedAdReady reloads the ad when a user closes the ad, to make sure the ad is ready as early as possible.

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  // TODO: Add _isRewardedAdReady
  bool _isRewardedAdReady;

  ...

  // TODO: Implement _loadRewardedAd()
  void _loadRewardedAd() {
    RewardedVideoAd.instance.load(
      targetingInfo: MobileAdTargetingInfo(),
      adUnitId: AdManager.rewardedAdUnitId,
    );
  }

  // TODO: Implement _onRewardedAdEvent()
  void _onRewardedAdEvent(RewardedVideoAdEvent event,
      {String rewardType, int rewardAmount}) {
    switch (event) {
      case RewardedVideoAdEvent.loaded:
        setState(() {
          _isRewardedAdReady = true;
        });
        break;
      case RewardedVideoAdEvent.closed:
        setState(() {
          _isRewardedAdReady = false;
        });
        _loadRewardedAd();
        break;
      case RewardedVideoAdEvent.failedToLoad:
        setState(() {
          _isRewardedAdReady = false;
        });
        print('Failed to load a rewarded ad');
        break;
      case RewardedVideoAdEvent.rewarded:
        QuizManager.instance.useHint();
        break;
      default:
      // do nothing
    }
  }

  ...
}

Next, initialize _isRewardedAdReady and set _onRewardedAdEvent as an ad event listener. Then, call _loadRewardedAd() to request a rewarded ad.

lib/game_route.dart

@override
void initState() {
  ...

  // TODO: Initialize _isRewardedAdReady
  _isRewardedAdReady = false;
 
  // TODO: Set Rewarded Ad event listener
  RewardedVideoAd.instance.listener = _onRewardedAdEvent;

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

Next, 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.

lib/game_route.dart

Widget _buildFloatingActionButton() {
  // TODO: Return a FloatingActionButton if a Rewarded Ad is available
  return (!QuizManager.instance.isHintUsed && _isRewardedAdReady)
      ? 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: <Widget>[
                    FlatButton(
                      child: Text('cancel'.toUpperCase()),
                      onPressed: () {
                        Navigator.pop(context);
                      },
                    ),
                    FlatButton(
                      child: Text('ok'.toUpperCase()),
                      onPressed: () {
                        Navigator.pop(context);
                        RewardedVideoAd.instance.show();
                      },
                    ),
                  ],
                );
              },
            );
          },
          label: Text('Hint'),
          icon: Icon(Icons.card_giftcard),
        )
      : null;
}

Finally, remove the rewarded ad event listener in the dispose() callback method.

lib/game_route.dart

@override
void dispose() {
  ...

  // TODO: Remove Rewarded Ad event listener
  RewardedVideoAd.instance.listener = null;

  ...

  super.dispose();
}

That's it! Run the project and watch a rewarded ad, to get an additional hint.


You've found something special!

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

To learn more, try the other Flutter codelabs.