1. 簡介
建構項目
本程式碼研究室會引導您將橫幅、插頁和獎勵廣告新增至名為「Awesome Drawing Quiz」的應用程式。這款遊戲可讓玩家猜測繪圖名稱。
|
|
進行本程式碼研究室時,如果你遇到任何問題 (例如程式碼錯誤、文法錯誤或用詞不明確),請點選程式碼研究室左下角的「回報錯誤」連結回報問題。
課程內容
- 如何設定 Google Mobile Ads AdMob 外掛程式
- 如何在 Flutter 應用程式中導入橫幅、插頁式和獎勵廣告
軟硬體需求
- Android Studio 4.1 以上版本
- Xcode 12 以上版本 (適用於 iOS 開發)
您對 AdMob 的使用經驗程度為何?
您對 Flutter 的經驗程度為何?
2. 設定 Flutter 開發環境
如要完成本實驗室,您需要兩項軟體:Flutter SDK 和編輯器。
您可以使用下列任一裝置執行程式碼研究室:
- 連線至電腦並設為開發人員模式的實體 Android 或 iOS 裝置。
- iOS 模擬器 (需要安裝 Xcode 工具)。
- Android Emulator (需在 Android Studio 中設定)。
- 瀏覽器 (偵錯時必須使用 Chrome)。
- 以 Windows、Linux 或 macOS 電腦版應用程式的形式提供。您必須在要部署的平台上進行開發。因此,如要開發 Windows 桌面應用程式,您必須在 Windows 上開發,才能存取適當的建構鏈。如需作業系統專屬需求,請參閱 docs.flutter.dev/desktop。
下載程式碼
下載 ZIP 檔案後,請解壓縮檔案內容。您會看到名為「admob-ads-in-flutter-master」的資料夾。
或者,您也可以從指令列複製 GitHub 存放區:
$ git clone https://github.com/googlecodelabs/admob-ads-in-flutter
存放區包含兩個資料夾:
starter:您將在本程式碼研究室中建構的起始程式碼。
complete:本程式碼研究室完成後的程式碼。
3. 設定 AdMob 應用程式和廣告單元
由於 Flutter 是跨平台 SDK,因此您需要在 AdMob 中為 Android 和 iOS 各自新增應用程式和廣告單元。
Android 設定
如要為 Android 進行設定,請新增 Android 應用程式並建立廣告單元。
新增 Android 應用程式
- 在 AdMob 控制台中,按一下「應用程式」選單中的「新增應用程式」。
- 系統詢問「您在 Google Play 或 App Store 發布過應用程式嗎?」時,請按一下「否」。
- 在應用程式名稱欄位中輸入
Awesome Drawing Quiz,然後選取「Android」Android做為平台。

- 啟用使用者指標並非完成本程式碼研究室的必要條件。不過,我們建議您這麼做,因為這樣才能更詳細地瞭解使用者行為。按一下「新增」即可完成程序。

建立廣告單元
如要開始在 AdMob 中新增廣告單元,請按照下列步驟操作:
- 在 AdMob 管理中心的「應用程式」選單中,選取「Awesome Drawing Quiz」。
- 按一下「廣告單元」選單。
橫幅
|
|
插頁式廣告
|
|
獎勵廣告
|
|
新的廣告單元通常要過幾小時後才會開始放送廣告。
如要立即測試廣告行為,請使用 Android 應用程式 ID/廣告單元 ID 和 iOS 應用程式 ID/廣告單元 ID 表格中列出的測試應用程式 ID 和廣告單元 ID。
在 iOS 裝置上設定
如要為 iOS 裝置設定,請新增 iOS 應用程式並建立廣告單元。
新增 iOS 應用程式
- 在 AdMob 控制台中,按一下「應用程式」選單中的「新增應用程式」。
- 系統詢問「您在 Google Play 或 App Store 發布過應用程式嗎?」時,請按一下「否」。
- 在應用程式名稱欄位中輸入
Awesome Drawing Quiz,然後選取「iOS」iOS做為平台。

- 啟用使用者指標並非完成本程式碼研究室的必要條件。不過,我們建議您這麼做,因為這樣才能更詳細地瞭解使用者行為。按一下「新增」即可完成程序。

建立廣告單元
如要新增廣告單元,請按照下列步驟操作:
- 在 AdMob 管理中心的「應用程式」選單中,選取「Awesome Drawing Quiz」應用程式。
- 按一下「廣告單元」選單。
橫幅
|
|
插頁式廣告
|
|
獎勵廣告
|
|
新的廣告單元通常要過幾小時後才會開始放送廣告。
如要立即測試廣告行為,請使用下表列出的測試應用程式 ID 和廣告單元 ID。
選用:使用測試 AdMob 應用程式和廣告單元
如果您想按照程式碼研究室的操作步驟進行,但還不想自行建立新的應用程式和廣告單元,請使用下表列出的測試 AdMob 應用程式 ID 和廣告單元 ID。
Android 應用程式 ID/廣告單元 ID
項目 | 應用程式 ID/廣告單元 ID |
AdMob 營利應用程式 ID |
|
橫幅廣告 |
|
插頁式廣告 |
|
已獲得獎勵 |
|
iOS 應用程式 ID/廣告單元 ID
項目 | 應用程式 ID/廣告單元 ID |
AdMob 營利應用程式 ID |
|
橫幅廣告 |
|
插頁式廣告 |
|
已獲得獎勵 |
|
如要進一步瞭解測試廣告,請參閱 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,請將 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」專案中安裝外掛程式。

更新 AndroidManifest.xml (Android)
- 在 Android Studio 中開啟
android/app/src/main/AndroidManifest.xml檔案。 - 新增
<meta-data>標記,並將名稱設為com.google.android.gms.ads.APPLICATION_ID,即可加入 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)
- 在 Android Studio 中開啟
ios/Runner/Info.plist檔案。 - 新增
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 的新檔案。接著導入 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 初始化完成後取得結果。
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. 新增橫幅廣告
在本節中,您會在遊戲畫面頂端顯示橫幅廣告,如下方螢幕截圖所示。

- 開啟
lib/game_route.dart檔案,然後匯入ad_manager.dart - 新增下列程式碼行,匯入
ad_helper.dart和google_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 {
...
}
- 在
_GameRouteState類別中,新增下列橫幅廣告成員。
lib/game_route.dart
class _GameRouteState extends State<GameRoute> implements QuizEventListener {
...
// TODO: Add _bannerAd
BannerAd? _bannerAd;
...
}
- 在
initState()方法中,建立並載入 320x50 橫幅的BannerAd(AdSize.banner)。請注意,廣告事件監聽器已設定為在載入廣告時更新 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();
}
- 修改
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!),
),
),
],
),
),
...
);
}
- 在
dispose()回呼方法中呼叫BannerAd.dispose()方法,釋放與BannerAd物件相關聯的資源。
lib/game_route.dart
@override
void dispose() {
// TODO: Dispose a BannerAd object
_bannerAd?.dispose();
...
super.dispose();
}
大功告成!執行專案,然後開始新遊戲。廣告載入後,畫面頂端會顯示橫幅廣告。

8. 新增插頁式廣告
在本節中,您會在遊戲結束後 (共 5 個關卡) 顯示插頁式廣告。
- 開啟
lib/game_route.dart檔案。 - 在
_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}');
},
),
);
}
...
}
- 在本程式碼研究室中,使用者完成 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();
}
}
- 遊戲結束時,系統會顯示遊戲分數對話方塊。使用者關閉對話方塊後,系統會將使用者導向「Awesome Drawing Quiz」的主畫面。
插頁式廣告應在畫面轉換期間顯示,因此當使用者點按「關閉」按鈕時,我們會顯示插頁式廣告。
按照下列方式修改 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();
}
},
),
],
);
},
);
}
- 在
dispose()回呼方法中呼叫InterstitialAd.dispose()方法,釋放與InterstitialAd物件相關聯的資源。
lib/game_route.dart
@override
void dispose() {
...
// TODO: Dispose an InterstitialAd object
_interstitialAd?.dispose();
...
super.dispose();
}
大功告成!執行專案並完成遊戲。如果載入的是插頁式廣告,點選評分對話方塊中的「關閉」按鈕後,就會看到插頁式廣告。

9. 新增獎勵廣告
在本節中,您將新增獎勵廣告,讓使用者觀看廣告來換取額外提示。
- 開啟
lib/game_route.dart檔案。 - 在
_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}');
},
),
);
}
...
}
- 遊戲開始時,請從
initState()方法呼叫_loadRewardedAd(),請求放送獎勵廣告。
lib/game_route.dart
class _GameRouteState extends State<GameRoute> implements QuizEventListener {
...
@override
void initState() {
...
// COMPLETE: Load a Rewarded Ad
_loadRewardedAd();
}
...
}
- 使用者點按懸浮動作按鈕後,即可觀看獎勵廣告。只有在使用者尚未在目前關卡使用提示,且系統已載入獎勵廣告時,才會顯示按鈕。
修改 _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;
}
- 在
dispose()回呼方法中呼叫RewardedAd.dispose()方法,釋放與RewardedAd物件相關聯的資源。
lib/game_route.dart
@override
void dispose() {
...
// TODO: Dispose a RewardedAd object
_rewardedAd?.dispose();
...
super.dispose();
}
大功告成!執行專案並玩遊戲。載入獎勵廣告後,畫面底部會顯示提示按鈕。按一下「提示」按鈕,取得額外提示。

10. 大功告成!
您已完成程式碼研究室。您可以在
complete 資料夾中找到本程式碼研究室完成後的程式碼。
如要瞭解如何導入橫幅和原生內嵌廣告,請參閱「在 Flutter 應用程式中加入 AdMob 橫幅和原生內嵌廣告」程式碼研究室。
如要瞭解詳情,請嘗試其他 Flutter 程式碼研究室。




