1. 소개
빌드할 내용
이 Codelab에서는 플레이어가 그림의 이름을 추측할 수 있는 게임인 Awesome Drawing Quiz라고 하는 앱에 배너 광고, 전면 광고 및 보상형 광고를 추가하는 방법을 안내합니다.
이 Codelab을 진행하는 동안 문제(코드 버그, 문법 오류, 불분명한 문구)가 발생하는 경우 Codelab 왼쪽 하단에 있는 Report a mistake 링크를 통해 문제를 신고해 주세요.
과정 내용
- Google 모바일 광고 AdMob 플러그인을 구성하는 방법
- Flutter 앱에서 배너 광고, 전면 광고 및 보상형 광고를 구현하는 방법
필요한 사항
- Android 스튜디오 4.1 이상
- Xcode 12 이상(iOS 개발용)
고객님의 AdMob 이용 경험 수준을 어떻게 평가하시겠어요?
고객님의 Flutter 이용 경험 수준을 어떻게 평가하시겠어요?
2. Flutter 개발 환경 설정
이 실습을 완료하려면 Flutter SDK 및 편집기라는 두 가지 소프트웨어가 필요합니다.
다음 기기 중 하나를 사용하여 이 Codelab을 실행할 수 있습니다.
- 컴퓨터에 연결되어 있으며 개발자 모드로 설정된 실제 Android 또는 iOS 기기
- iOS 시뮬레이터(Xcode 도구 설치 필요)
- Android Emulator(Android 스튜디오 설정 필요)
- 브라우저(디버깅 시 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 — 이 Codelab에서 빌드할 시작 코드
- complete — 이 Codelab을 위해 완료된 코드
3. AdMob 앱 및 광고 단위 설정
Flutter는 멀티 플랫폼 SDK이므로 AdMob에서 Android 및 iOS 모두를 위한 앱과 광고 단위를 추가해야 합니다.
Android용으로 설정
Android용으로 설정하려면 Android 앱을 추가하고 광고 단위를 만들어야 합니다.
Android 앱 추가
- AdMob 콘솔의 앱 메뉴에서 앱 추가를 클릭합니다.
- 앱을 Google Play 또는 App Store에 게시하셨나요?라는 질문이 표시되면 아니요를 클릭합니다.
- 앱 이름 입력란에
Awesome Drawing Quiz
를 입력하고 Android를 플랫폼으로 선택합니다.
- 이 Codelab을 완료하기 위해 사용자 측정항목을 사용 설정하지 않아도 됩니다. 하지만 그렇게 하면 사용자 행동을 더 자세히 파악할 수 있습니다. 추가를 클릭하여 절차를 완료합니다.
광고 단위 만들기
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를 플랫폼으로 선택합니다.
- 이 Codelab을 완료하기 위해 사용자 측정항목을 사용 설정하지 않아도 됩니다. 하지만 그렇게 하면 사용자 행동을 더 자세히 파악할 수 있습니다. 추가를 클릭하여 절차를 완료합니다.
광고 단위 만들기
광고 단위를 추가하는 방법은 다음과 같습니다.
- AdMob 콘솔의 앱 메뉴에서 Awesome Drawing Quiz 앱을 선택합니다.
- 광고 단위 메뉴를 클릭합니다.
배너 광고
|
전면 광고
|
보상형 광고
|
일반적으로 새 광고 단위에서 광고를 게재하는 데는 몇 시간이 소요됩니다.
광고의 작동 방식을 즉시 테스트하려면 다음 표에 표시된 테스트 앱 ID 및 광고 단위 ID를 사용하세요.
선택사항: 테스트 AdMob 앱 및 광고 단위 사용
새 애플리케이션과 광고 단위를 직접 만드는 대신 Codelab을 따르려면 다음 표에 나와 있는 테스트 AdMob 앱 ID와 광고 단위 ID를 사용하면 됩니다.
Android 앱 ID/광고 단위 ID
항목 | 앱 ID/광고 단위 ID |
AdMob 앱 ID |
|
배너 광고 |
|
전면 광고 |
|
보상형 광고 |
|
iOS 앱 ID/광고 단위 ID
항목 | 앱 ID/광고 단위 ID |
AdMob 앱 ID |
|
배너 광고 |
|
전면 광고 |
|
보상형 광고 |
|
테스트 광고에 대한 자세한 내용은 Android 테스트 광고 및 iOS 테스트 광고 개발자 문서를 참고하세요.
4. Google 모바일 광고 Flutter 플러그인 추가
Flutter에서는 플러그인을 사용하여 광범위한 플랫폼별 서비스에 대한 액세스를 제공합니다. 플러그인을 사용하면 각 플랫폼의 서비스와 API에 액세스할 수 있습니다.
google_mobile_ads 플러그인은 AdMob API을 사용하여 배너 광고, 전면 광고, 보상형 광고 및 네이티브 광고의 로드 및 표시를 지원합니다.
Flutter는 멀티 플랫폼 SDK이므로 google_mobile_ads 플러그인은 iOS와 Android 모두에 적용할 수 있습니다. 따라서 Flutter 앱에 플러그인을 추가하면 AdMob 인라인 광고 앱의 Android 및 iOS 버전 모두에서 사용됩니다.
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 프로젝트에 플러그인을 설치합니다.
AndroidManifest.xml 업데이트(Android)
- Android 스튜디오에서
android/app/src/main/AndroidManifest.xml
파일을 엽니다. - 이름이
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)
- Android 스튜디오에서
ios/Runner/Info.plist
파일을 엽니다. - AdMob 앱의 문자열 값이 포함된
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
인 새 파일을 엽니다. 그런 다음 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 모바일 광고 SDK 초기화
광고를 로드하기 전에 Google 모바일 광고 SDK를 초기화해야 합니다. lib/home_route.dart
파일을 열고 홈페이지가 로드되기 전에 SDK가 초기화되도록 _initGoogleMobileAds()
를 수정합니다.
초기화가 완료된 후 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. 배너 광고 추가
이 섹션에서는 다음 스크린샷에 표시된 대로 게임 화면의 상단에 배너 광고를 표시합니다.
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 배너(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();
}
- 사용 가능한 경우 배너 광고를 표시하도록
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}');
},
),
);
}
...
}
- 이 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();
}
}
- 게임이 완료되면 게임 점수 대화상자가 표시됩니다. 사용자가 대화상자를 닫으면 사용자를 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
가 보상형 광고에서 가장 중요한 광고 이벤트입니다. 이 이벤트는 사용자가 리워드를 받을 수 있게 될 때(예를 들어 동영상 시청을 완료할 때) 트리거됩니다.
이 Codelab에서 QuizManager.instance.useHint()
메서드는 콜백에서 호출되어 힌트 문자열에서 1자를 더 표시합니다. 앱에서는 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. 모두 완료했습니다.
Codelab을 완료했습니다. 이 Codelab의 완료된 코드는 complete 폴더에서 확인할 수 있습니다.
배너 광고와 네이티브 인라인 광고를 구현하는 방법을 알아보려면 Flutter 앱에 AdMob 배너 광고 및 네이티브 인라인 광고 추가 Codelab을 확인하세요.
자세한 내용은 다른 Flutter Codelab을 참고하세요.