FlutterでAdMobを表示(iOS/Android)

# はじめに
今回はAdMobの公式パッケージを使って広告を表示できるようにします。

# 更新履歴
2021.5.16 初回投稿
2021.7.31 google_mobile_adsのバージョン変更、google_mobile_adsのバージョン変更に合わせて、ad_banner.dartのメソッド名を変更
2021.8.26 adUnitIdの値を本番の時にどうするかを追加
2021.10.4 ATT周りが記載できていなかったため、追記
2021.10.4 Flutter2.5用に修正
2021.10.4 環境を再修正
2025.4.30 pubspec.yamlのsdk部分を削除,BannerAd.testAdUnitIdがなくなったので削除
2025.5.15 admobバージョン修正、minSdkVersionバージョン修正、ndkVersion修正、kAdMobAndroidID、kAdMobIOSIDを修正

# 環境
- Sequoia 15.3.2(Mac)
- Flutter (Channel stable, 3.29.3, on macOS 15.3.2 24D81 darwin-arm64, locale ja-JP)
- Android toolchain - develop for Android devices (Android SDK version 36.0.0-rc5)
- Xcode - develop for iOS and macOS (Xcode 16.2)
- Chrome - develop for the web
- Android Studio (version 2023.3)
- VS Code (version 1.99.3)

# 参考にしたサイト
- [flutterアプリでfirebase_admobからgoogle_mobile_adsに切り替えてみた - Qiita](https://qiita.com/kazutxt/items/8ea0eab5dfac2c59366d)


# package
https://pub.dev/packages/google_mobile_ads/install

# やりたいこと

- iOS/AndroidでAdMobの広告を表示させたい。
- WebではAdMob表示できないので一旦、無視

## AdMobテスト用ID

*   アプリID
    *   Android: ca-app-pub-3940256099942544~3347511713
    *   iOS: ca-app-pub-3940256099942544~1458002511
*   広告ユニットID
    *   Android: ca-app-pub-3940256099942544/6300978111
    *   iOS: ca-app-pub-3940256099942544/2934735716
    
なお、admobのプラグインにて、定数定義がありますので、  
`FirebaseAdMob.testAppId`や`BannerAd.testAdUnitId`のように利用することも可能なようです。(試してません)


# 実装手順


1. パッケージをpubspec.yamlに追加してインストール
    ```pubspec.yaml
    google_mobile_ads: ^6.0.0
    ```

2. iOSの設定
   iOS/Runner/info.plistに以下を追加
    ```info.plist
    <key>GADApplicationIdentifier</key>
         <string>ca-app-pub-3940256099942544~1458002511</string>
    ```


   「ca-app-pub-3940256099942544~1458002511」はテスト用アプリIDとなりますので、本番の際はこちらを自分のアプリのアプリIDに変更してください。
   
3. Androidの設定
    最小SDKバージョンの変更

    ```android/app/build.gradle.kts
     ~略~
    ndkVersion = "27.0.12077973"
    ~略~
    minSdk = 23
    ~略~
    ```

    android/app/src/main/AndroidManifest.xmlに以下を追加

    ```AndroidManifest.xml
    <meta-data
                android:name="flutterEmbedding"
                android:value="2" />
            <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3940256099942544~3347511713" />
    ```
   「ca-app-pub-3940256099942544~3347511713」はテスト用アプリIDとなりますので、本番の際はこちらを自分のアプリのアプリIDに変更してください。


4.管理クラスの作成(参考サイトのソースコードのままですthx)

- AdListener→BannerAdListenerに変更(2021.7.31)
- onApplicationExit: (Ad ad) => print('Left application.')を削除(2021.7.31)

```ad_banner.dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'dart:io';

class AdBanner extends StatelessWidget {
  const AdBanner({
    required this.size,
    Key? key,
  }) : super(key: key);

  final AdSize size;
  @override
  Widget build(BuildContext context) {
    final banner = BannerAd(
        size: size,
        adUnitId: bannerAdUnitId,
        listener: BannerAdListener(
          onAdLoaded: (Ad ad) => debugPrint('Ad loaded.'),
          onAdFailedToLoad: (Ad ad, LoadAdError error) {
            debugPrint('Ad failed to load: $error');
          },
          onAdOpened: (Ad ad) => debugPrint('Ad opened.'),
          onAdClosed: (Ad ad) => debugPrint('Ad closed.'),
        ),
        request: const AdRequest())
      ..load();

    return SizedBox(
        width: banner.size.width.toDouble(),
        height: banner.size.height.toDouble(),
        child: AdWidget(ad: banner));
  }

  // 広告ID
  static String get bannerAdUnitId {
    if (Platform.isAndroid) {
      return "ca-app-pub-3940256099942544/6300978111";
    } else {
      return "ca-app-pub-3940256099942544/2934735716";
    }
  }
}

```

6.実装

```main.dart
import 'package:flutter/material.dart';
import 'ad_banner.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Admob Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AdMob Demo'),
      ),
      body: Center(
        child: AdBanner(size: AdSize.banner),
      ),
    );
  }
}

```

7.動作確認
![スクリーンショット 2021-05-16 11.25.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9961/dcce2265-caef-da36-c7c9-20d19ec7da01.png)

# 広告のサイズ

| AdSize | width | height |
|:---------------|:--:|:--:|
| banner         | 320|  50|
| largeBanner    | 320| 100|
| mediumRectangle| 300| 250|
| fullBanner     | 468|  60|
| leaderboard    | 728|  90|


# ATT対応

1.iOS設定

 ①SKAdNetworkの追加
    以下のxmlの設定をInfo.plistに追加する。

   ```info.plist
   <key>SKAdNetworkItems</key>
   <array>
    <dict>
      <key>SKAdNetworkIdentifier</key>
      <string>cstr6suwn9.skadnetwork</string>
    </dict>
  </array>
   ```

 ②IDFA利用ポップアップの文言設定

```info.plist
   <key>NSUserTrackingUsageDescription</key>
   <string>「許可」すると、あなたに合った広告が表示されやすくなります。これによる個人情報へのアクセスはありません。また、許可しなくても、アプリの全ての機能をご利用いただけます。</string>

```

2.app_tracking_transparencyパッケージを追加

https://pub.dev/packages/app_tracking_transparency/install

3.att_helperを作成

```att_helper.dart

import 'package:app_tracking_transparency/app_tracking_transparency.dart';
import 'package:flutter/material.dart';

class ATTHelper {
  Future<void> attCheck() async {
    final status = await AppTrackingTransparency.trackingAuthorizationStatus;
    //ATTが設定されていない場合実行
    if (status == TrackingStatus.notDetermined) {
      debugPrint('ATT未設定');
      await Future.delayed(const Duration(milliseconds: 200));
      //ダイアログ表示
      await AppTrackingTransparency.requestTrackingAuthorization();
    } else {
      debugPrint('ATT設定済');
    }
  }
}

```

4.ATTHelperを呼び出す


```main.dart
import 'package:flutter/material.dart';
import 'ad_banner.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:<package名>/services/att_helper.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {

  //WidgetsBindigを追加
  WidgetsBinding.instance?.addPostFrameCallback(
      (_) => ATTHelper().attCheck(),
    );

    return MaterialApp(
      title: 'Admob Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AdMob Demo'),
      ),
      body: Center(
        child: AdBanner(size: AdSize.banner),
      ),
    );
  }
}

```

以上