Flutter アプリに AdMob バナーとネイティブ インライン広告を追加する

この Codelab では、Flutter アプリに AdMob バナーと AdMob ネイティブ インライン広告を実装します。

作成するアプリの概要

この Codelab では、Flutter 用の Google Mobile Ads プラグインを使用して、AdMob インライン バナーと AdMob ネイティブ インライン広告を Flutter アプリに実装する方法について説明します。

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

学習内容

  • Flutter 用の Google Mobile Ads プラグインの設定方法
  • Flutter アプリにインライン バナーとリワード広告を実装する方法

必要なもの

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

AdMob の使用経験についてお答えください。

初心者 中級者 上級者

Flutter の使用経験についてお答えください。

初心者 中級者 上級者

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

  1. マシンに Flutter SDK をインストールします。
  2. Android Studio を開き、Android Studio 用の Flutter 拡張機能をインストールします。

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

ソースコードをダウンロード GitHub でリポジトリを確認

ZIP ファイルをダウンロードしたら、ファイルの内容を抽出します。admob-inline-ads-in-flutter-main という名前のフォルダが作成されます。

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

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

リポジトリには、次の 3 つのフォルダが含まれています。

  • android_studio_folder.png starter: この Codelab で作成するコードの基本となる開始用コード。
  • android_studio_folder.png complete: この Codelab の完全なコード(ネイティブ コードの場合は Java と Objective-C)。
  • android_studio_folder.png complete_kotlin_swift: この Codelab の完全なコード(ネイティブ コードの場合は Kotlin と Swift)。

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

Android 用に設定する

Android 用に設定するには、Android アプリを追加して広告ユニットを作成する必要があります。

Android アプリを追加する

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

e4d968797610c8c0.png

  1. ユーザーに関する指標を有効にしなくてもこの Codelab を完了できますが、ユーザー行動をより詳細に把握できるように、有効にすることをおすすめします。[追加] をクリックして処理を完了します。

5204925f5c652b41.png

広告ユニットを作成する

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

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

バナー

  1. [広告ユニットを追加] をクリックします。
  2. 形式として [バナー] を選択します。
  3. [広告ユニット名] に「android-inline-banner」と入力します。
  4. [広告ユニットを作成] をクリックして処理を完了します。

ネイティブ

  1. [広告ユニットを追加] をクリックします。
  2. 形式として [ネイティブ アドバンス] を選択します。
  3. [広告ユニット名] に「android-inline-native」と入力します。
  4. [広告ユニットを作成] をクリックして処理を完了します。

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

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

iOS 用に設定する

iOS 用に設定するには、iOS アプリを追加して広告ユニットを作成する必要があります。

iOS アプリを追加する

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

e00fc8ac930a251b.png

  1. ユーザーに関する指標を有効にしなくてもこの Codelab を完了できますが、ユーザー行動をより詳細に把握できるように、有効にすることをおすすめします。[追加] をクリックして処理を完了します。

5204925f5c652b41.png

広告ユニットを作成する

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

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

バナー

  1. [広告ユニットを追加] をクリックします。
  2. 形式として [バナー] を選択します。
  3. [広告ユニット名] に「ios-inline-banner」と入力します。
  4. [広告ユニットを作成] をクリックして処理を完了します。

ネイティブ

  1. [広告ユニットを追加] をクリックします。
  2. 形式として [ネイティブ アドバンス] を選択します。
  3. [広告ユニット名] に「ios-inline-native」と入力します。
  4. [広告ユニットを作成] をクリックして処理を完了します。

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

広告の動作をすぐにテストする場合は、次の表に示すテストアプリ 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/2247696110

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

項目

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

AdMob アプリ ID

ca-app-pub-3940256099942544~1458002511

バナー

ca-app-pub-3940256099942544/2934735716

ネイティブ

ca-app-pub-3940256099942544/3986624511

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

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.yaml ファイルに、google_mobile_ads を依存関係として追加します。

pubspec.yaml

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

dependencies:
  flutter:
    sdk: flutter
  google_fonts: ^0.3.9

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

...

[Pub get] をクリックして、AdMob インライン広告プロジェクトにプラグインをインストールします。

39e66c2a3b7f078b.png

AndroidManifest.xml を更新する(Android)

  1. Android Studio で android/app/src/main/AndroidManifest.xml ファイルを開きます。
  2. AdMob アプリ ID を追加するには、<meta-data> タグを追加して com.google.android.gms.ads.APPLICATION_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>
...

lib ディレクトリに ad_helper.dart という新しいファイルを作成します。次に、AdHelper クラスを実装します。このクラスは、Android および iOS 用の AdMob アプリ ID と広告ユニット ID を提供します。

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

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 new UnsupportedError("Unsupported platform");
    }
  }

  static String get nativeAdUnitId {
    if (Platform.isAndroid) {
      return "<YOUR_ANDROID_NATIVE_AD_UNIT_ID>";
    } else if (Platform.isIOS) {
      return "<YOUR_IOS_NATIVE_AD_UNIT_ID>";
    } else {
      throw new UnsupportedError("Unsupported platform");
    }
  }
}

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

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';
    }
    throw new UnsupportedError("Unsupported platform");
  }

  static String get nativeAdUnitId {
    if (Platform.isAndroid) {
      return 'ca-app-pub-3940256099942544/2247696110';
    } else if (Platform.isIOS) {
      return 'ca-app-pub-3940256099942544/3986624511';
    }
    throw new UnsupportedError("Unsupported platform");
  }
}

広告を読み込む前に、Google Mobile Ads SDK を初期化する必要があります。lib/home_page.dart ファイルを開き、ホームページが読み込まれる前に SDK を初期化するように _initGoogleMobileAds() を変更します。

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

home_page.dart

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

import 'package:flutter/material.dart';

...

class HomePage extends StatelessWidget {

  ...

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

このセクションでは、次のスクリーンショットに示すように、リストの中央にバナー広告を表示します。

a3cd508128793e41.png

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

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

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

class BannerInlinePage extends StatefulWidget {
  ...
}
  1. _BannerInlinePageState クラスに、次のメンバーとメソッドをバナー広告用に追加します。

_kAdIndex はバナー広告が表示されるインデックスを示し、_getDestinationItemIndex() メソッドでアイテム インデックスの計算に使用されます。

banner_inline_page.dart

class _BannerInlinePageState extends State<BannerInlinePage> {

  // TODO: Add _kAdIndex
  static final _kAdIndex = 4;

  // TODO: Add a BannerAd instance
  late BannerAd _ad;

  // TODO: Add _isAdLoaded
  bool _isAdLoaded = false;

  ...

  // TODO: Add _getDestinationItemIndex()
  int _getDestinationItemIndex(int rawIndex) {
    if (rawIndex >= _kAdIndex && _isAdLoaded) {
      return rawIndex - 1;
    }
    return rawIndex;
  }

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

banner_inline_page.dart

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

  // TODO: Create a BannerAd instance
  _ad = BannerAd(
    adUnitId: AdHelper.bannerAdUnitId,
    size: AdSize.banner,
    request: AdRequest(),
    listener: AdListener(
      onAdLoaded: (_) {
        setState(() {
          _isAdLoaded = true;
        });
      },
      onAdFailedToLoad: (ad, error) {
        // Releases an ad resource when it fails to load
        ad.dispose();

        print('Ad load failed (code=${error.code} message=${error.message})');
      },
    ),
  );

  // TODO: Load an ad
  _ad.load();
}
  1. 利用可能な場合はバナー広告を表示するように build() メソッドを変更します。
  2. バナー広告のエントリをカウントするように itemCount, を更新します。また、広告が読み込まれたときにバナー広告を広告インデックス(_kAdIndex)に表示するように itemBuilder, を更新します。
  3. _getDestinationItemIndex() メソッドを使用してコンテンツ アイテムのインデックスを取得するように、コードを更新します。

banner_inline_page.dart

@override
Widget build(BuildContext context) {
  return Scaffold(
    ...
    body: ListView.builder(
      // TODO: Adjust itemCount based on the ad load state
      itemCount: widget.entries.length + (_isAdLoaded ? 1 : 0),
      itemBuilder: (context, index) {
        // TODO: Render a banner ad
        if (_isAdLoaded && index == _kAdIndex) {
          return Container(
            child: AdWidget(ad: _ad),
            width: _ad.size.width.toDouble(),
            height: 72.0,
            alignment: Alignment.center,
          );
        } else {
          // TODO: Get adjusted item index from _getDestinationItemIndex()
          final item = widget.entries[_getDestinationItemIndex(index)];

          return ListTile(
            ...
          );
        }
      },
    ),
  );
}
  1. dispose() コールバック メソッドで BannerAd.dispose() メソッドを呼び出して、BannerAd オブジェクトに関連付けられたリソースを解放します。

banner_inline_page.dart

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

  super.dispose();
}

これで完了です。プロジェクトを実行し、ホームページで [Banner inline ad] ボタンをクリックします。広告が読み込まれると、リストの中央にバナー広告が表示されます。

f1372268878a80a2.png c32af50872514224.png

このセクションでは、次のスクリーンショットに示すように、リストの中央にネイティブ広告を表示します。

fbe594d5d9ce08ea.png

ネイティブ広告は、プラットフォームのネイティブ UI コンポーネント(例: Android では View、iOS では UIView)を使用してユーザーに表示されます。

ただし、Flutter ウィジェットを使用してネイティブ UI コンポーネントを直接作成することはできません。そのため、各プラットフォームに NativeAdFactory を実装する必要があります。これは、ネイティブ広告オブジェクト(Android では UnifiedNativeAd、iOS では GADUnifiedNativeAd)からプラットフォーム固有のネイティブ広告ビュー(Android では UnifiedNativeAdView、iOS では GADUnifiedNativeAdView)を作成するために使用されます。

Android(Java)用に NativeAdFactory を実装する

  1. android/build.gradle ファイル(または android フォルダ内の任意のファイル)を開き、[Open for Editing in Android Studio] をクリックして Android プロジェクトを開きます。

88d3e99426cd8d8c.png

  1. 新しいプロジェクトを開くウィンドウを選択するように求められた場合は、[New Window] をクリックして、Flutter プロジェクトを開いたまま Android プロジェクトの作業を進められるようにします。

5d554e50a83f2bd1.png

ネイティブ広告のレイアウトを作成する

  1. Android プロジェクトを開いた状態で、Android Studio のプロジェクト ペインで [app] を右クリックし、コンテキスト メニューから [New] > [Android Resource File] を選択します。

7b2b6d28d0fe80a9.png

  1. [New Resource File] ダイアログで、ファイル名として「list_tile_native_ad.xml」と入力します。
  2. リソースタイプとして [Layout] を選択し、ルート要素として「com.google.android.gms.ads.formats.UnifiedNativeAdView」と入力します。
  3. [OK] をクリックして、新しいレイアウト ファイルを作成します。

615bf550a2ce9c45.png

  1. 広告のレイアウトを次のように実装します。レイアウトは、対象となるプラットフォームのユーザー エクスペリエンスのビジュアル デザインに合わせる必要があります。

list_tile_native_ad.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.formats.UnifiedNativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_small"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#F19938"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:textSize="12sp" />

        <ImageView
            android:id="@+id/iv_list_tile_native_ad_icon"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:scaleType="fitXY"
            tools:background="#EDEDED" />

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_large"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:background="#F19938"
            android:gravity="center"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:visibility="invisible" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="80dp"
            android:layout_marginLeft="80dp"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_list_tile_native_ad_headline"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#000000"
                android:textSize="16sp"
                tools:text="Headline" />

            <TextView
                android:id="@+id/tv_list_tile_native_ad_body"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#828282"
                android:textSize="14sp"
                tools:text="body" />

        </LinearLayout>

    </FrameLayout>

</com.google.android.gms.ads.formats.UnifiedNativeAdView>

ListTileNativeAdFactory クラスを作成する

  1. [Project] ペインで com.codelab.flutter.admobinlineads パッケージを右クリックし、[New] > [Java Class] を選択します。

609df24b6a0b647e.png

  1. 名前として「ListTileNativeAdFactory」を入力し、リストから [Class] を選択します。

642050a1a83d5033.png

  1. [New Class] ダイアログが表示されたら、すべての欄を空のままにして [OK] をクリックします。

ListTileNativeAdFactory クラスがパッケージ com.codelab.flutter.admobinlineads に作成されていることを確認します。

3e7c27d864686efa.png

  1. ListTileNativeAdFactory クラスを次のように実装します。クラスが GoogleMobileAdsPlugin.NativeAdFactory インターフェースに createNativeAd() メソッドを実装していることに注意してください。

ファクトリ クラスは、ネイティブ広告を表示するためのビュー オブジェクトを作成します。コードからわかるように、ファクトリ クラスは UnitifedNativeAdView を作成し、これに UnifiedNativeAd オブジェクトを入力します。

ListTileNativeAdFactory.java

// TODO: Implement ListTileNativeAdFactory class

package com.codelab.flutter.admobinlineads;

import com.google.android.gms.ads.formats.NativeAd;
import com.google.android.gms.ads.formats.UnifiedNativeAd;
import com.google.android.gms.ads.formats.UnifiedNativeAdView;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.Map;

import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;

class ListTileNativeAdFactory implements GoogleMobileAdsPlugin.NativeAdFactory {

    private final Context context;

    ListTileNativeAdFactory(Context context) {
        this.context = context;
    }

    @Override
    public UnifiedNativeAdView createNativeAd(
            UnifiedNativeAd nativeAd, Map<String, Object> customOptions) {
        UnifiedNativeAdView nativeAdView = (UnifiedNativeAdView) LayoutInflater.from(context)
                .inflate(R.layout.list_tile_native_ad, null);

        TextView attributionViewSmall = nativeAdView
                .findViewById(R.id.tv_list_tile_native_ad_attribution_small);
        TextView attributionViewLarge = nativeAdView
                .findViewById(R.id.tv_list_tile_native_ad_attribution_large);

        ImageView iconView = nativeAdView.findViewById(R.id.iv_list_tile_native_ad_icon);
        NativeAd.Image icon = nativeAd.getIcon();
        if (icon != null) {
            attributionViewSmall.setVisibility(View.VISIBLE);
            attributionViewLarge.setVisibility(View.INVISIBLE);
            iconView.setImageDrawable(icon.getDrawable());
        } else {
            attributionViewSmall.setVisibility(View.INVISIBLE);
            attributionViewLarge.setVisibility(View.VISIBLE);
        }
        nativeAdView.setIconView(iconView);

        TextView headlineView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_headline);
        headlineView.setText(nativeAd.getHeadline());
        nativeAdView.setHeadlineView(headlineView);

        TextView bodyView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_body);
        bodyView.setText(nativeAd.getBody());
        bodyView.setVisibility(nativeAd.getBody() != null ? View.VISIBLE : View.INVISIBLE);
        nativeAdView.setBodyView(bodyView);

        nativeAdView.setNativeAd(nativeAd);

        return nativeAdView;
    }
}

ListTileNativeAdFactory クラスを登録する

NativeAdFactory のインスタンスを Flutter 側で使用するには、事前に GoogleMobileAdsPlugin に登録しておく必要があります。

  1. MainActivity.java ファイルを開き、configureFlutterEngine() メソッドと cleanUpFlutterEngine() メソッドをオーバーライドします。
  2. configureFlutterEngine() メソッドで、一意の文字列 ID(listTile)を指定して ListTileNativeAdFactory クラスを登録します。

MainActivity.java

public class MainActivity extends FlutterActivity {

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);

        // TODO: Register the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTile",
                new ListTileNativeAdFactory(getContext()));
    }

    ...
}
  1. クリーンアップ プロセス中は、すべての NativeAdFactory インスタンスを登録解除する必要があります。cleanUpFlutterEngine() メソッドで ListTileNativeAdFactory クラスの登録を解除します。

MainActivity.java

public class MainActivity extends FlutterActivity {

    ...

    @Override
    public void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine);

        // TODO: Unregister the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile");
    }
}

これで、Android で ListTileNativeAdFactory クラスを使用してネイティブ広告を表示する準備が整いました。

Android(Kotlin)用に NativeAdFactory を実装する

  1. android/build.gradle ファイル(または android フォルダ内の任意のファイル)を開き、[Open for Editing in Android Studio] をクリックして Android プロジェクトを開きます。

88d3e99426cd8d8c.png

  1. 新しいプロジェクトを開くウィンドウを選択するように求められた場合は、[New Window] をクリックして、Flutter プロジェクトを開いたまま Android プロジェクトの作業を進められるようにします。

5d554e50a83f2bd1.png

ネイティブ広告のレイアウトを作成する

  1. Android プロジェクトを開いた状態で、Android Studio のプロジェクト ペインで [app] を右クリックし、コンテキスト メニューから [New] > [Android Resource File] を選択します。

7b2b6d28d0fe80a9.png

  1. [New Resource File] ダイアログで、ファイル名として「list_tile_native_ad.xml」と入力します。
  2. リソースタイプとして [Layout] を選択し、ルート要素として「com.google.android.gms.ads.formats.UnifiedNativeAdView」と入力します。
  3. [OK] をクリックして、新しいレイアウト ファイルを作成します。

615bf550a2ce9c45.png

  1. 広告のレイアウトを次のように実装します。レイアウトは、対象となるプラットフォームのユーザー エクスペリエンスのビジュアル デザインに合わせる必要があります。

list_tile_native_ad.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.formats.UnifiedNativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_small"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#F19938"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:textSize="12sp" />

        <ImageView
            android:id="@+id/iv_list_tile_native_ad_icon"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:scaleType="fitXY"
            tools:background="#EDEDED" />

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_large"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:background="#F19938"
            android:gravity="center"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:visibility="invisible" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="80dp"
            android:layout_marginLeft="80dp"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_list_tile_native_ad_headline"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#000000"
                android:textSize="16sp"
                tools:text="Headline" />

            <TextView
                android:id="@+id/tv_list_tile_native_ad_body"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#828282"
                android:textSize="14sp"
                tools:text="body" />

        </LinearLayout>

    </FrameLayout>

</com.google.android.gms.ads.formats.UnifiedNativeAdView>

ListTileNativeAdFactory クラスを作成する

  1. [Project] ペインで com.codelab.flutter.admobinlineads パッケージを右クリックし、[New] > [Kotlin File/Class] を選択します。

7311744cb97cad75.png

  1. 名前として「ListTileNativeAdFactory」を入力し、リストから [Class] を選択します。

43a6ac7728826d8.png

  1. ListTileNativeAdFactory クラスがパッケージ com.codelab.flutter.admobinlineads に作成されていることを確認します。
  2. ListTileNativeAdFactory クラスを次のように実装します。クラスが GoogleMobileAdsPlugin.NativeAdFactory インターフェースに createNativeAd() メソッドを実装していることに注意してください。

ファクトリ クラスは、ネイティブ広告を表示するためのビュー オブジェクトを作成します。コードからわかるように、ファクトリ クラスは UnitifedNativeAdView を作成し、これに UnifiedNativeAd オブジェクトを入力します。

ListTileNativeAdFactory.kt

// TODO: Implement ListTileNativeAdFactory class

package com.codelab.flutter.admobinlineads

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.google.android.gms.ads.formats.UnifiedNativeAd
import com.google.android.gms.ads.formats.UnifiedNativeAdView
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin

class ListTileNativeAdFactory(val context: Context) : GoogleMobileAdsPlugin.NativeAdFactory {

    override fun createNativeAd(
            nativeAd: UnifiedNativeAd,
            customOptions: MutableMap<String, Any>?
    ): UnifiedNativeAdView {
        val nativeAdView = LayoutInflater.from(context)
                .inflate(R.layout.list_tile_native_ad, null) as UnifiedNativeAdView

        with(nativeAdView) {
            val attributionViewSmall =
                    findViewById<TextView>(R.id.tv_list_tile_native_ad_attribution_small)
            val attributionViewLarge =
                    findViewById<TextView>(R.id.tv_list_tile_native_ad_attribution_large)

            val iconView = findViewById<ImageView>(R.id.iv_list_tile_native_ad_icon)
            val icon = nativeAd.icon
            if (icon != null) {
                attributionViewSmall.visibility = View.VISIBLE
                attributionViewLarge.visibility = View.INVISIBLE
                iconView.setImageDrawable(icon.drawable)
            } else {
                attributionViewSmall.visibility = View.INVISIBLE
                attributionViewLarge.visibility = View.VISIBLE
            }
            this.iconView = iconView

            val headlineView = findViewById<TextView>(R.id.tv_list_tile_native_ad_headline)
            headlineView.text = nativeAd.headline
            this.headlineView = headlineView

            val bodyView = findViewById<TextView>(R.id.tv_list_tile_native_ad_body)
            with(bodyView) {
                text = nativeAd.body
                visibility = if (nativeAd.body.isNotEmpty()) View.VISIBLE else View.INVISIBLE
            }
            this.bodyView = bodyView

            setNativeAd(nativeAd)
        }

        return nativeAdView
    }
}

ListTileNativeAdFactory クラスを登録する

NativeAdFactory のインスタンスを Flutter 側で使用するには、事前に GoogleMobileAdsPlugin に登録しておく必要があります。

  1. MainActivity.kt ファイルを開き、configureFlutterEngine() メソッドと cleanUpFlutterEngine() メソッドをオーバーライドします。
  2. configureFlutterEngine() メソッドで、一意の文字列 ID(listTile)を指定して ListTileNativeAdFactory クラスを登録します。

MainActivity.kt

class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        // TODO: Register the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.registerNativeAdFactory(
                flutterEngine, "listTile", ListTileNativeAdFactory(context))
    }

    ...
}
  1. クリーンアップ プロセス中は、すべての NativeAdFactory インスタンスを登録解除する必要があります。cleanUpFlutterEngine() メソッドで ListTileNativeAdFactory クラスの登録を解除します。

MainActivity.kt

class MainActivity: FlutterActivity() {
    ...

    override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine)

        // TODO: Unregister the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile")
    }
}

これで、Android で ListTileNativeAdFactory クラスを使用してネイティブ広告を表示する準備が整いました。

iOS(Objective-C)用に NativeAdFactory を実装する

ios/Podfile ファイル(または ios フォルダ内の任意のファイル)を開き、[Open iOS module in Xcode] をクリックして iOS プロジェクトを開きます。

8f8b417705df6741.png

ネイティブ広告のレイアウトを準備する

ネイティブ広告アセットのレイアウトには、カスタムビュー(*.xib)が必要です。この Codelab では、作業を最小限に抑えるために事前構成されたビューを使用します。

Xcode で iOS プロジェクトを開いた状態で、ListTileNativeAdView.xibRunner プロジェクトに存在することを確認します。

8551d919ccc41818.png

ListTileNativeAdFactory クラスを作成する

  1. プロジェクト ナビゲータで [Runner] グループを右クリックし、[New File] を選択して新しいクラスのヘッダー ファイルを作成します。

249c43a7a1eac87.png

  1. テンプレート ダイアログで [Header File] を選択し、ListTileNativeAdFactory という名前を付けます。
  2. ListTileNativeAdFactory.h ファイルを作成したら、ListNativeAdFactory クラスを次のように定義します。

ListTileNativeAdFactory.h

#ifndef ListTileNativeAdFactory_h
#define ListTileNativeAdFactory_h

// TODO: Import FLTGoogleMobileAdsPlugin.h
#import "FLTGoogleMobileAdsPlugin.h"

// TODO: Declare ListTileNativeAdFactory
@interface ListTileNativeAdFactory : NSObject<FLTNativeAdFactory>

@end

#endif /* ListTileNativeAdFactory_h */
  1. [Runner] グループから [New File] を選択して、Objective-C ファイルを作成します。
  2. 次のダイアログで、[File] フィールドに「ListTileNativeAdFactory」と入力し、ファイル形式として [Empty File] を選択します。

26f03ec58f26d1d2.png

  1. [Next] をクリックすると、新しいファイルの作成先フォルダを選択するよう求められます。何も変更せずに [Create] をクリックします。

c40f7080bdf513ff.png

  1. ListTileNativeFactory クラスを次のように実装します。クラスが FLTNativeAdFactory プロトコルに createNativeAd() メソッドを実装していることに注意してください。

ファクトリ クラスは、ネイティブ広告を表示するためのビュー オブジェクトを作成します。コードからわかるように、ファクトリ クラスは GADUnitifedNativeAdView を作成し、これに GADUnifiedNativeAd オブジェクトを入力します。

ListTileNativeAdFactory.m

// TODO: Import ListTileNativeAdFactory.h
#import "ListTileNativeAdFactory.h"

// TODO: Implement ListTileNativeAdFactory
@implementation ListTileNativeAdFactory

- (GADUnifiedNativeAdView *)createNativeAd:(GADUnifiedNativeAd *)nativeAd
                             customOptions:(NSDictionary *)customOptions {
  GADUnifiedNativeAdView *nativeAdView =
    [[NSBundle mainBundle] loadNibNamed:@"ListTileNativeAdView" owner:nil options:nil].firstObject;

  ((UILabel *)nativeAdView.headlineView).text = nativeAd.headline;

  ((UILabel *)nativeAdView.bodyView).text = nativeAd.body;
  nativeAdView.bodyView.hidden = nativeAd.body ? NO : YES;

  ((UIImageView *)nativeAdView.iconView).image = nativeAd.icon.image;
  nativeAdView.iconView.hidden = nativeAd.icon ? NO : YES;

  nativeAdView.callToActionView.userInteractionEnabled = NO;

  nativeAdView.nativeAd = nativeAd;

  return nativeAdView;
}

@end

ListTileNativeAdFacotry クラスを登録する

FLTNativeAdFactory の実装を Flutter 側で使用するには、事前に FLTGoogleMobileAdsPlugin に登録する必要があります。

AppDelegate.m ファイルを開き、[FLTGoogleMobileAdsPlugin registerNativeAdFactory] メソッドを呼び出して、一意の文字列 ID(listTile)を指定して ListTileNativeAdFactory を登録します。

AppDelegate.m

#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"

// TODO: Import ListTileNativeAdFactory.h
#import "ListTileNativeAdFactory.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

  // TODO: Register ListTileNativeAdFactory
  ListTileNativeAdFactory *listTileFactory = [[ListTileNativeAdFactory alloc] init];
  [FLTGoogleMobileAdsPlugin registerNativeAdFactory:self
                                        factoryId:@"listTile"
                                  nativeAdFactory:listTileFactory];

  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

これで、iOS で ListTileNativeAdFactory を使用してネイティブ広告を表示する準備が整いました。

iOS(Swift)用に NativeAdFactory を実装する

ios/Podfile ファイル(または ios フォルダ内の任意のファイル)を開き、[Open iOS module in Xcode] をクリックして iOS プロジェクトを開きます。

8f8b417705df6741.png

ネイティブ広告のレイアウトを準備する

ネイティブ広告アセットのレイアウトには、カスタムビュー(*.xib)が必要です。この Codelab では、作業を最小限に抑えるために事前構成されたビューを使用します。

Xcode で iOS プロジェクトを開いた状態で、ListTileNativeAdView.xibRunner プロジェクトに存在することを確認します。

8551d919ccc41818.png

ListTileNativeAdFactory クラスを作成する

  1. プロジェクト ナビゲータで [Runner] グループを右クリックし、[New File] を選択して新しいクラスのヘッダー ファイルを作成します。

90bdca063c491134.png

  1. テンプレート ダイアログで [Swift File] を選択し、ListTileNativeAdFactory という名前を付けます。
  2. ListTileNativeAdFactory.swift ファイルを作成したら、ListNativeAdFactory クラスを実装します。

クラスが FLTNativeAdFactory プロトコルに createNativeAd() メソッドを実装していることに注意してください。

ファクトリ クラスは、ネイティブ広告を表示するためのビュー オブジェクトを作成します。コードからわかるように、ファクトリ クラスは GADUnitifedNativeAdView を作成し、これに GADUnifiedNativeAd オブジェクトを入力します。

ListTileNativeAdFactory.swift

// TODO: Import google_mobile_ads
import google_mobile_ads

// TODO: Implement ListTileNativeAdFactory
class ListTileNativeAdFactory : FLTNativeAdFactory {

    func createNativeAd(_ nativeAd: GADUnifiedNativeAd,
                        customOptions: [AnyHashable : Any]? = nil) -> GADUnifiedNativeAdView? {
        let nibView = Bundle.main.loadNibNamed("ListTileNativeAdView", owner: nil, options: nil)!.first
        let nativeAdView = nibView as! GADUnifiedNativeAdView

        (nativeAdView.headlineView as! UILabel).text = nativeAd.headline

        (nativeAdView.bodyView as! UILabel).text = nativeAd.body
        nativeAdView.bodyView!.isHidden = nativeAd.body == nil

        (nativeAdView.iconView as! UIImageView).image = nativeAd.icon?.image
        nativeAdView.iconView!.isHidden = nativeAd.icon == nil

        nativeAdView.callToActionView?.isUserInteractionEnabled = false

        nativeAdView.nativeAd = nativeAd

        return nativeAdView
    }
}

ListTileNativeAdFacotry クラスを登録する

FLTNativeAdFactory の実装を Flutter 側で使用するには、事前に FLTGoogleMobileAdsPlugin に登録する必要があります。

AppDelegate.m ファイルを開き、FLTGoogleMobileAdsPlugin.registerNativeAdFactory() メソッドを呼び出して、一意の文字列 ID(listTile)を指定して ListTileNativeAdFactory を登録します。

AppDelegate.swift

import UIKit
import Flutter

// TODO: Import google_mobile_ads
import google_mobile_ads

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    // TODO: Register ListTileNativeAdFactory
    let listTileFactory = ListTileNativeAdFactory()
    FLTGoogleMobileAdsPlugin.registerNativeAdFactory(
        self, factoryId: "listTile", nativeAdFactory: listTileFactory)

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

これで、iOS で ListTileNativeAdFactory を使用してネイティブ広告を表示する準備が整いました。

ネイティブ広告を Flutter ウィジェットと統合する

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

native_inline_page.dart

...

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

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

class NativeInlinePage extends StatefulWidget {
  ...
}
  1. _NativeInlinePageState クラスで、ネイティブ広告に次のメンバーとメソッドを追加します。

_kAdIndex はバナー広告が表示されるインデックスを示し、_getDestinationItemIndex() メソッドでアイテム インデックスの計算に使用されます。

native_inline_page.dart

class _NativeInlinePageState extends State<NativeInlinePage> {

  // TODO: Add _kAdIndex
  static final _kAdIndex = 4;

  // TODO: Add a NativeAd instance
  late NativeAd _ad;

  // TODO: Add _isAdLoaded
  bool _isAdLoaded = false;

  ...

  // TODO: Add _getDestinationItemIndex()
  int _getDestinationItemIndex(int rawIndex) {
    if (rawIndex >= _kAdIndex && _isAdLoaded) {
      return rawIndex - 1;
    }
    return rawIndex;
  }

  ...
}
  1. initState() メソッドで、ListTileNativeAdFactory を使用してネイティブ広告ビューを生成する NativeAd を作成し、読み込みます。

ファクトリをプラグインに登録するときに使用したのと同じファクトリ ID(listTile)が使用されていることに注意してください。

native_inline_page.dart

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

  // TODO: Create a NativeAd instance
  _ad = NativeAd(
    adUnitId: AdHelper.nativeAdUnitId,
    factoryId: 'listTile',
    request: AdRequest(),
    listener: AdListener(
      onAdLoaded: (_) {
        setState(() {
          _isAdLoaded = true;
        });
      },
      onAdFailedToLoad: (ad, error) {
        // Releases an ad resource when it fails to load
        ad.dispose();

        print('Ad load failed (code=${error.code} message=${error.message})');       },
    ),
  );

  _ad.load();
}
  1. 利用可能な場合はバナー広告を表示するように build() メソッドを変更します。
  2. バナー広告エントリをカウントするように itemCount, を更新します。また、広告が読み込まれたときに広告インデックス(_kAdIndex)でバナー広告を表示するように itemBuilder, を更新します。
  3. _getDestinationItemIndex() メソッドを使用してコンテンツ アイテムのインデックスを取得するように、コードを更新します。

native_inline_page.dart

@override
Widget build(BuildContext context) {
  return Scaffold(
    ...
    body: ListView.builder(
      // TODO: Adjust itemCount based on the ad load state
      itemCount: widget.entries.length + (_isAdLoaded ? 1 : 0),
      itemBuilder: (context, index) {
        // TODO: Render a banner ad
        if (_isAdLoaded && index == _kAdIndex) {
          return Container(
            child: AdWidget(ad: _ad),
            height: 72.0,
            alignment: Alignment.center,
          );
        } else {
          // TODO: Get adjusted item index from _getDestinationItemIndex()
          final item = widget.entries[_getDestinationItemIndex(index)];

          return ListTile(
            ...
          );
        }
      },
    ),
  );
}
  1. dispose() コールバック メソッドで NativeAd.dispose() メソッドを呼び出して、NativeAd オブジェクトに関連付けられたリソースを解放します。

native_inline_page.dart

@override
void dispose() {
  // TODO: Dispose a NativeAd object
  _ad.dispose();

  super.dispose();
}

これで完了です。プロジェクトを実行し、ホームページで [Native inline ad] ボタンをクリックします。広告が読み込まれると、リストの中央にネイティブ広告が表示されます。

fbe594d5d9ce08ea.png 5ead873222c800eb.png

Codelab を完了しました。この Codelab の完全なコードは、android_studio_folder.png complete または android_studio_folder.png complete_kotlin_swift フォルダにあります。