在 Flutter 應用程式中加入 AdMob 廣告

在 Flutter 應用程式中加入 AdMob 廣告

程式碼研究室簡介

subject上次更新時間:8月 27, 2022
account_circle作者:Taeho Kim

1. 簡介

建構項目

本程式碼研究室會引導您在名為「Awesome Drawing Quiz」的應用程式中加入橫幅廣告、插頁式廣告和獎勵廣告,這款遊戲可讓玩家猜出繪圖名稱。

在進行程式碼研究室各項步驟的過程中,如果您遇到任何問題 (例如程式碼錯誤、文法錯誤或用詞不明確),請按一下程式碼研究室左下角的「回報錯誤」連結來回報問題。

課程內容

  • 如何設定 Google Mobile Ads AdMob 外掛程式
  • 如何在 Flutter 應用程式中導入橫幅廣告、插頁式廣告和獎勵廣告

軟硬體需求

  • Android Studio 4.1 以上版本
  • Xcode 12 以上版本 (適用於 iOS 開發作業)

您對 AdMob 使用體驗的評價如何?

針對使用 Flutter 的經驗,您會給予什麼評價?

2. 設定 Flutter 開發環境

您需要使用兩項軟體:Flutter SDK編輯器

您可以使用下列任一裝置執行程式碼研究室:

  • 將實體 AndroidiOS 裝置接上電腦,並設為開發人員模式。
  • 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

存放區包含兩個資料夾:

  • android_studio_folder.pngstarter:您將在這個程式碼研究室中建構的程式碼。
  • android_studio_folder.pngcomplete:完成這個程式碼研究室的程式碼。

3. 設定 AdMob 應用程式和廣告單元

由於 Flutter 是多平台 SDK,您需要在 AdMob 中新增 Android 和 iOS 的應用程式和廣告單元。

設定 Android 裝置

如要設定 Android,您必須新增 Android 應用程式並建立廣告單元。

新增 Android 應用程式

  1. AdMob 控制台中,按一下「應用程式」選單中的「新增應用程式」
  2. 系統詢問「是否已在 Google Play 或 App Store 發布應用程式?」時,按一下「否」
  3. 請在應用程式名稱欄位中輸入 Awesome Drawing Quiz,然後選取「Android」做為平台。

ddafee37a6f92229.png

  1. 完成本程式碼研究室不需要啟用使用者指標。不過我們建議您這麼做,因為可以幫助您深入瞭解使用者行為。按一下「新增」完成程序。

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」iOS做為平台。

93e7f9f114232402.png

  1. 完成本程式碼研究室不需要啟用使用者指標。不過我們建議您這麼做,因為可以幫助您深入瞭解使用者行為。按一下「新增」完成程序。

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 應用程式和廣告單元

如想按照程式碼研究室的說明操作,而非自行建立新的應用程式和廣告單元,您可以使用下表所列的測試 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 應用程式中加入這個外掛程式,Android 和 iOS 版 AdMob 內嵌廣告應用程式都會使用這個外掛程式。

將 Google 行動廣告外掛程式新增為依附元件

如要從 AdMob 內嵌廣告專案存取 AdMob API,請將 google_mobile_ads 新增為專案根目錄中 pubspec.yaml 檔案的依附元件。

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

...

按一下「Pub get」,即可在 Awesome Drawing Quiz 專案中安裝外掛程式。

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. 加入包含 AdMob 應用程式 ID 字串值的 GADApplicationIdentifier 鍵。舉例來說,如果您的 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 的新檔案。接著,導入 AdHelper 類別,藉此提供 Android 和 iOS 的 AdMob 應用程式 ID 和廣告單元 ID。

請務必將 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。

請注意,您需要將 _initGoogleMobileAds() 方法的傳回類型從 Future<dynamic> 變更為 Future<InitializationStatus>,才能在完成 SDK 初始化結果後取得 SDK 初始化結果。

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() 方法中,建立並載入 320x50 橫幅廣告 (AdSize.banner) 的 BannerAd。請注意,廣告事件監聽器已設為在載入廣告時更新使用者介面 (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. 在本程式碼研究室中,使用者完成 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. 遊戲結束後,系統會顯示遊戲分數對話方塊。使用者關閉對話方塊後,就會導向「超級繪圖測驗」的主畫面。

由於插頁式廣告應會在使用者切換畫面切換時顯示,因此系統會在使用者點選 [關閉] 按鈕時顯示插頁式廣告。

請按照下列方式修改 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();
}

大功告成!執行專案,然後完成遊戲。載入插頁式廣告後,您按下分數對話方塊中的「關閉」按鈕後,就會看到插頁式廣告。

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 是獎勵廣告中最重要的廣告事件。只要使用者符合獎勵資格 (例如看完影片),就會觸發這個事件。

在本程式碼研究室中,是從回呼呼叫 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();
}

大功告成!執行專案,然後進行遊戲。載入獎勵廣告後,畫面底部會顯示提示按鈕。按一下「提示」按鈕,即可查看其他提示。

(4a114d243ae3e71d.gif)

10. 大功告成!

您已完成程式碼研究室。您可以在 android_studio_folder.png「complete」資料夾中找到本程式碼研究室完成後的程式碼。

若要瞭解如何導入橫幅廣告和原生內嵌廣告,請參閱「在 Flutter 應用程式中加入 AdMob 橫幅廣告和原生內嵌廣告」程式碼研究室。

詳情請參閱其他 Flutter 程式碼研究室