Flutter アプリに AdMob 広告を追加する

1. 概要

作成する内容

この Codelab では、バナー広告、インタースティシャル広告、リワード広告を、ユーザーが描画の名前を推測するゲームの Awesome Drawing Quiz というアプリに追加する手順について説明します。

この Codelab で何か問題(コードのバグ、文法的な誤り、不明確な表現など)が見つかりましたら、Codelab の左下にある [誤りを報告] をクリックして報告してください。

学習する内容

  • Google Mobile Ads AdMob プラグインを設定する方法
  • バナー広告、インタースティシャル広告、リワード広告を Flutter アプリに実装する方法

必要なもの

  • Android Studio 4.1 以降
  • Xcode 12 以降(iOS 開発用)

ご自身の AdMob 使用経験をどのように評価されますか。

初心者 中級者 上級者

ご自身の Flutter 使用経験をどのように評価されますか。

初心者 中級者 上級者

2. Flutter の開発環境をセットアップする

このラボを完了するには、Flutter SDKエディタの 2 つのソフトウェアが必要です。

この Codelab は、次のいずれかのデバイスを使って実行できます。

  • パソコンに接続され、デベロッパー モードに設定された物理デバイス(Android または iOS
  • iOS シミュレータ(Xcode ツールのインストールが必要)
  • Android Emulator(Android Studio でセットアップが必要)
  • ブラウザ(デバッグには Chrome が必要)
  • WindowsLinuxmacOS のデスクトップ アプリケーション。開発はデプロイする予定のプラットフォームで行う必要があります。たとえば、Windows のデスクトップ アプリを開発する場合は、適切なビルドチェーンにアクセスできるように Windows で開発する必要があります。オペレーティング システム固有の要件については、docs.flutter.dev/desktop に詳しい説明があります。

コードをダウンロードする

zip ファイルをダウンロードしたら、そのコンテンツを展開すると、admob-ads-in-flutter-master という名前のフォルダが作成されます。

または、以下のように、コマンドラインから GitHub リポジトリのクローンを作成することもできます。

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

リポジトリには以下の 2 つのフォルダが含まれています。

  • android_studio_folder.pngstarter — この Codelab で作成する開始コード。
  • android_studio_folder.pngcomplete — この Codelab の最終的なコード。

3. AdMob アプリと広告ユニットを設定する

Flutter はマルチプラットフォーム SDK であるため、Android と iOS 両方のアプリと広告ユニットを AdMob に追加する必要があります。

Android 用の設定

Android 用の設定を行うには、Android アプリを追加して広告ユニットを作成します。

Android アプリを追加する

  1. AdMob コンソールで、[アプリ] メニューから [アプリを追加] をクリックします。
  2. 「Google Play や App Store でアプリを公開していますか?」という質問が表示されたら、「いいえ」をクリックします。
  3. アプリ名の欄に「Awesome Drawing Quiz」と入力し、プラットフォームとして [Android] を選択します。

ddafee37a6f92229.png

  1. この Codelab の手順を完了するうえで、ユーザーに関する指標を有効にする必要はありませんが、ユーザー行動をより詳しく把握できるため、有効にすることをおすすめします。[追加] をクリックして手順を完了します。

b918bf44362813a9.png

広告ユニットを作成する

AdMob への広告ユニットの追加を開始するには:

  1. AdMob コンソールで、[アプリ] メニューから [Awesome Drawing Quiz] をクリックします。
  2. [広告ユニット] メニューをクリックします。

バナー

  1. [広告ユニットを追加] ボタンをクリックします。
  2. フォーマットとして [バナー] を選択します。
  3. [広告ユニット名] 欄に「android-adq-banner」と入力します。
  4. [広告ユニットの作成] をクリックして手順を完了します。

インタースティシャル

  1. [広告ユニットを追加] ボタンをクリックします。
  2. フォーマットとして[インタースティシャル] を選択します。
  3. [広告ユニット名] 欄に「android-adq-interstitial」と入力します。
  4. [広告ユニットの作成] をクリックして手順を完了します。

リワード

  1. [広告ユニットを追加] ボタンをクリックします。
  2. [リワード] を選択します。
  3. [広告ユニット名] 欄に「android-adq-rewarded」と入力します。
  4. [報酬の設定] はデフォルトのままにします。
  5. [広告ユニットの作成] をクリックして手順を完了します。

通常、新しい広告ユニットで広告を配信できるようになるまでには数時間かかります。

広告の動作をすぐにテストする場合は、Android アプリ ID / 広告ユニット ID と iOS アプリ ID / 広告ユニット ID の表に記載されているテストアプリ ID とテスト広告ユニット ID を使用してください。

iOS 用の設定

iOS 用の設定を行うには、iOS アプリを追加して広告ユニットを作成します。

iOS アプリを追加する

  1. AdMob コンソールで、[アプリ] メニューから [アプリを追加] をクリックします。
  2. 「Google Play や App Store でアプリを公開していますか?」という質問が表示されたら、「いいえ」をクリックします。
  3. アプリ名の欄に「Awesome Drawing Quiz」と入力し、プラットフォームとして [iOS] を選択します。

93e7f9f114232402.png

  1. この Codelab の手順を完了するうえで、ユーザーに関する指標を有効にする必要はありませんが、ユーザー行動をより詳しく把握できるため、有効にすることをおすすめします。[追加] をクリックして手順を完了します。

b918bf44362813a9.png

広告ユニットを作成する

広告ユニットを追加するには:

  1. AdMob コンソールの [アプリ] メニューから [Awesome Drawing Quiz] アプリを選択します。
  2. [広告ユニット] メニューをクリックします。

バナー

  1. [広告ユニットを追加] ボタンをクリックします。
  2. フォーマットとして [バナー] を選択します。
  3. [広告ユニット名] 欄に「ios-adq-banner」と入力します。
  4. [広告ユニットの作成] をクリックして手順を完了します。

インタースティシャル

  1. [広告ユニットを追加] ボタンをクリックします。
  2. フォーマットとして[インタースティシャル] を選択します。
  3. [広告ユニット名] 欄に「ios-adq-interstitial」と入力します。
  4. [広告ユニットの作成] をクリックして手順を完了します。

リワード

  1. [広告ユニットを追加] ボタンをクリックします。
  2. [リワード] を選択します。
  3. [広告ユニット名] 欄に「ios-adq-rewarded」と入力します。
  4. [報酬の設定] はデフォルトのままにします。
  5. [広告ユニットの作成] をクリックして手順を完了します。

通常、新しい広告ユニットで広告を配信できるようになるまでには数時間かかります。

広告の動作をすぐにテストする場合は、次の表に記載されているテストアプリ ID とテスト広告ユニット ID を使用してください。

省略可: AdMob のテストアプリとテスト広告ユニットを使用する

新しいアプリや広告ユニットを独自に作成せずにこの Codelab の手順を行う場合は、次の表に記載されているテスト用の AdMob アプリ ID と広告ユニット ID を使用できます。

Android アプリ ID / 広告ユニット ID

項目

アプリ ID / 広告ユニット ID

AdMob アプリ ID

ca-app-pub-3940256099942544~3347511713

バナー

ca-app-pub-3940256099942544/6300978111

インタースティシャル

ca-app-pub-3940256099942544/1033173712

リワード

ca-app-pub-3940256099942544/5224354917

iOS アプリ ID / 広告ユニット ID

項目

アプリ ID / 広告ユニット ID

AdMob アプリ ID

ca-app-pub-3940256099942544~1458002511

バナー

ca-app-pub-3940256099942544/2934735716

インタースティシャル

ca-app-pub-3940256099942544/4411468910

リワード

ca-app-pub-3940256099942544/1712485313

テスト広告について詳しくは、Android テスト広告iOS テスト広告に関するデベロッパー向けドキュメントをご覧ください。

4. Google Mobile Ads Flutter プラグインを追加する

Flutter では、プラグインを使用して、プラットフォーム固有の幅広いサービスへのアクセスを提供します。プラグインを使用すると、各プラットフォームのサービスと API にアクセスできます。

google_mobile_ads プラグインでは、AdMob API を使用したバナー広告、インタースティシャル広告、リワード広告、ネイティブ広告の読み込みと表示がサポートされています。

Flutter はマルチプラットフォーム SDK であるため、google_mobile_ads プラグインは iOS と Android の両方に適用できます。このため、プラグインを Flutter アプリに追加すると、AdMob インライン広告アプリの Android 版と iOS 版の両方で使用されます。

Google Mobile Ads プラグインを依存関係として追加する

AdMob インライン広告のプロジェクトから AdMob API にアクセスするには、プロジェクトのルートにある pubspec.yamlgoogle_mobile_ads を依存関係として追加します。

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

...

Awesome Drawing Quiz プロジェクトにプラグインをインストールするには、[Pub get] をクリックします。

9ce73858eedbd8fc.png

AndroidManifest.xml(Android)を更新する

  1. Android Studio で android/app/src/main/AndroidManifest.xml ファイルを開きます。
  2. com.google.android.gms.ads.APPLICATION_ID という名前の <meta-data> タグを追加して、AdMob アプリ ID を追加します。たとえば、AdMob アプリ ID が ca-app-pub-3940256099942544~3347511713 の場合、AndroidManifest.xml ファイルに以下の行を追加します。

AndroidManifest.xml

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

</manifest>

Info.plist(iOS)を更新する

  1. Android Studio で ios/Runner/Info.plist ファイルを開きます。
  2. GADApplicationIdentifier キーと AdMob アプリ ID の文字列値を追加します。たとえば、AdMob アプリ ID が ca-app-pub-3940256099942544~1458002511 の場合、Info.plist ファイルに以下の行を追加します。

ios/Runner/Info.plist

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

5. 広告のヘルパークラスを追加する

lib ディレクトリに ad_helper.dart という名前の新しいファイルを作成します。次に、Android と iOS 向けの AdMob アプリ ID と広告ユニット ID を指定する AdHelper クラスを実装します。

AdMob アプリ ID(ca-app-pub-xxxxxx~yyyyy)と広告ユニット ID(ca-app-pub-xxxxxxx/yyyyyyyy)は、上記の手順で作成した ID に置き換えてください。

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');
    }
  }
}

テスト用の AdMob アプリ ID と広告ユニット ID を使用する場合は、以下のコード スニペットを使用します。

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. Google Mobile Ads SDK を初期化する

広告を読み込む前に、Google Mobile Ads SDK を初期化する必要があります。lib/home_route.dart ファイルを開き、_initGoogleMobileAds() を修正して、SDK を初期化してから、ホームページを読み込みます。

なお、SDK 初期化の完了前に結果を取得するには、_initGoogleMobileAds() メソッドの戻り値の型を Future<dynamic> から Future<InitializationStatus> に変更する必要があります。

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. バナー広告を追加する

このセクションでは、以下のスクリーンショットに示すように、ゲーム画面の上部にバナー広告を表示します。

276b4cfa283ea6c7.png

  1. lib/game_route.dart ファイルを開き、ad_manager.dart をインポートします。
  2. 以下の行を追加して、ad_helper.dartgoogle_mobile_ads.dart をインポートします。

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. _GameRouteState クラスで、バナー広告向けに以下のメンバーを追加します。

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  // TODO: Add _bannerAd
  BannerAd? _bannerAd;

  ...
}
  1. initState() メソッドで 320×50 バナー(AdSize.banner)向けに BannerAd を作成して読み込みます。なお、イベント リスナーは、広告の読み込み時に UI(setState())を更新するように構成されています。

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. 可能な場合にバナー広告を表示するように build() メソッドを変更します。

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. dispose() コールバック メソッドの BannerAd.dispose() メソッドを呼び出して、BannerAd オブジェクトに関連付けられているリソースをリリースします。

lib/game_route.dart

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

  ...

  super.dispose();
}

最後に、プロジェクトを実行し、新しいゲームを開始しましょう。広告が読み込まれた後、画面の上部にバナー広告が表示されます。

276b4cfa283ea6c7.png

8. インタースティシャル広告を追加する

このセクションでは、ゲーム(合計 5 レベル)の終了後にインタースティシャル広告を表示します。

  1. lib/game_route.dart ファイルを開きます。
  2. _GameRouteState クラスで、インタースティシャル広告向けに以下のメンバーとメソッドを追加します。

なお、イベント リスナーは、広告の準備ができている(onAdLoaded() および onAdFailedToLoad())かどうかを確認し、広告が閉じられた際(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. この Codelab では、ユーザーが 5 つのレベルを完了した後でインタースティシャル広告を表示します。不要な広告リクエストを最小限に抑えるため、ユーザーがレベル 3 に達した際に広告をリクエストします。

onNewLevel() メソッドに以下の行を追加します。

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. ゲームが終了すると、ゲームスコア ダイアログが表示されます。ユーザーがダイアログを終了すると、ユーザーは Awesome Drawing Quiz のホーム画面に転送されます。

インタースティシャル広告は、画面の切り替え時に表示する必要があるため、ユーザーが [CLOSE] ボタンをクリックした際に表示されます。

onGameOver() メソッドを次のように変更します。

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. dispose() コールバック メソッドの InterstitialAd.dispose() メソッドを呼び出して、InterstitialAd オブジェクトに関連付けられているリソースをリリースします。

lib/game_route.dart

@override
void dispose() {
  ...

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

  ...

  super.dispose();
}

最後に、プロジェクトを実行し、ゲームを完了しましょう。インタースティシャル広告が読み込まれた場合、スコア ダイアログで [CLOSE] ボタンをクリックするとインタースティシャル広告が表示されます。

c546e438c405e941.gif

9. リワード広告を追加する

このセクションでは、特典として追加のヒントをユーザーに提供するリワード広告を追加します。

  1. lib/game_route.dart ファイルを開きます。
  2. _GameRouteState クラスでリワード広告向けにメンバーを追加し、_loadRewardedAd() メソッドを実装します。なお、このメソッドは、できる限り早い段階で広告をキャッシュするため、広告が閉じられた(onAdDismissedFullScreenContent)際に別のリワード広告を読み込みます。

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. initState() メソッドから _loadRewardedAd() を呼び出して、ゲームの開始時にリワード広告をリクエストします。

lib/game_route.dart

class _GameRouteState extends State<GameRoute> implements QuizEventListener {

  ...

  @override
  void initState() {
    ...

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

  ...
}
  1. フローティング アクション ボタンをクリックすることで、リワード広告を表示できるようにします。ボタンは、ユーザーが現在のレベルでヒントを使用しておらず、リワード広告が読み込まれている場合にのみ表示されます。

フローティング アクション ボタンを表示するには、以下のように _buildFloatingActionButton() メソッドを変更します。なお、null が返された場合、画面からボタンが非表示になります。

onUserEarnedReward はリワード広告の最も重要な広告イベントで、ユーザーが特典を受け取るための要件を満たした際(動画の視聴を完了するなど)にトリガーされます。

この Codelab では、コールバックから QuizManager.instance.useHint() メソッドを呼び出し、ヒントの文字列に別の文字を表示します。アプリは、できる限り早い段階で広告の準備が完了するように、onAdClosed コールバックでリワード広告を再読み込みします。

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. dispose() コールバック メソッドの RewardedAd.dispose() メソッドを呼び出して、RewardedAd オブジェクトに関連付けられているリソースをリリースします。

lib/game_route.dart

@override
void dispose() {
  ...

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

  ...

  super.dispose();
}

最後に、プロジェクトを実行し、ゲームをプレイしましょう。リワード広告が読み込まれると、画面の下部に [Hint] ボタンが表示されます。[Hint] ボタンをクリックすると、追加のヒントが表示されます。

4a114d243ae3e71d.gif

10. 完了

この Codelab を完了しました。この Codelab の最終的なコードは、android_studio_folder.pngcomplete フォルダで確認できます。

バナー広告とネイティブ インライン広告を実装する方法について詳しくは、AdMob のバナー広告とネイティブ インライン広告の Flutter アプリへの追加に関する Codelab をご覧ください。

詳細については、別の Flutter の Codelab をご覧ください。