1. 소개
이 Codelab에서는 Flutter 앱에 AdMob 배너 및 AdMob 네이티브 인라인 광고를 구현합니다.
빌드할 항목
이 Codelab은 Flutter용 Google 모바일 광고 플러그인을 사용하여 Flutter 앱에 AdMob 인라인 배너 및 AdMob 네이티브 인라인 광고를 구현하는 방법을 안내합니다.
|
|
이 Codelab을 진행하는 동안 코드 버그, 문법 오류, 불명확한 문구 등의 문제가 발생하면 Codelab 왼쪽 하단에 있는 오류 신고 링크를 통해 신고해 주세요.
학습 내용
- Google 모바일 광고 Flutter 플러그인 구성 방법
- Flutter 앱의 인라인 배너 및 보상형 광고 구현 방법
필요한 항목
- Android 스튜디오 4.1 이상
- Xcode 12 이상(iOS 개발용)
AdMob 사용 경험 수준을 평가해 주세요.
Flutter 사용 경험 수준을 평가해 주세요.
<ph type="x-smartling-placeholder">2. Flutter 개발 환경 설정
이 실습을 완료하려면 Flutter SDK 및 편집기라는 두 가지 소프트웨어가 필요합니다.
다음 기기 중 하나를 사용하여 이 Codelab을 실행할 수 있습니다.
- 컴퓨터에 연결되어 있으며 개발자 모드로 설정된 실제 Android 또는 iOS 기기
- iOS 시뮬레이터(Xcode 도구 설치 필요)
- Android Emulator(Android 스튜디오 설정 필요)
- 브라우저(디버깅 시 Chrome 필요)
- Windows, Linux 또는 macOS 데스크톱 애플리케이션. 배포에 사용할 플랫폼에서 개발해야 합니다. 따라서 Windows 데스크톱 앱을 개발하려면 적절한 빌드 체인에 액세스할 수 있도록 Windows에서 개발해야 합니다. docs.flutter.dev/desktop에 운영체제별 요구사항이 자세히 설명되어 있습니다.
코드 다운로드
zip 파일을 다운로드한 후 콘텐츠의 압축을 풉니다. 이름이 admob-inline-ads-in-flutter-main인 폴더가 생성됩니다.
또는 명령줄에서 GitHub 저장소를 클론할 수 있습니다.
$ git clone https://github.com/googlecodelabs/admob-inline-ads-in-flutter
저장소에는 다음과 같은 폴더 세 개가 있습니다.
starter: 이 Codelab에서 빌드할 시작 코드입니다.
complete: 이 Codelab의 완성된 코드입니다. (네이티브 코드의 경우 자바 및 Objective-C)
complete_kotlin_swift: 이 Codelab의 완성된 코드입니다. (네이티브 코드의 경우 Kotlin 및 Swift)
3. AdMob 앱 및 광고 단위 설정
Flutter는 멀티 플랫폼 SDK이므로 AdMob에서 Android와 iOS에 모두 앱과 광고 단위를 추가해야 합니다.
Android 설정
Android에 맞춰 설정하려면 Android 앱을 추가하고 광고 단위를 만들어야 합니다.
Android 앱 추가
- AdMob 콘솔의 앱 메뉴에서 앱 추가를 클릭합니다.
- 앱을 Google Play 또는 App Store에 게시하셨나요?라는 메시지가 표시되면 아니요를 클릭합니다.
- 앱 이름 필드에
AdMob inline ads를 입력하고 플랫폼으로 Android를 선택합니다.

- 이 Codelab을 완료하기 위해 사용자 측정항목을 사용할 필요는 없습니다. 하지만 사용자 행동을 더 자세히 이해할 수 있으므로 사용하는 것이 좋습니다. 추가를 클릭하여 절차를 완료합니다.

광고 단위 만들기
광고 단위를 추가하려면 다음 단계를 따릅니다.
- AdMob 콘솔의 앱 메뉴에서 AdMob 인라인 광고 앱을 선택합니다.
- 광고 단위 메뉴를 클릭합니다.
배너
|
|
네이티브
|
|
새 광고 단위에서 광고를 게재할 수 있으려면 보통 몇 시간이 걸립니다.
광고의 작동 방식을 즉시 테스트하려면 Android 앱 ID/광고 단위 ID 및 iOS 앱 ID/광고 단위 ID 표에 표시된 테스트 앱 ID와 광고 단위 ID를 사용하세요.
iOS용 설정
iOS에 맞춰 설정하려면 iOS 앱을 추가하고 광고 단위를 만들어야 합니다.
iOS 앱 추가
- AdMob 콘솔의 앱 메뉴에서 앱 추가를 클릭합니다.
- 앱을 Google Play 또는 App Store에 게시하셨나요?라는 메시지가 표시되면 아니요를 클릭합니다.
- 앱 이름 필드에
AdMob inline ads를 입력하고 플랫폼으로 iOS를 선택합니다.

- 이 Codelab을 완료하기 위해 사용자 측정항목을 사용할 필요는 없습니다. 하지만 사용자 행동을 더 자세히 이해할 수 있으므로 사용하는 것이 좋습니다. 추가를 클릭하여 절차를 완료합니다.

광고 단위 만들기
광고 단위를 추가하려면 다음 단계를 따릅니다.
- AdMob 콘솔의 앱 메뉴에서 AdMob 인라인 광고 앱을 선택합니다.
- 광고 단위 메뉴를 클릭합니다.
배너
|
|
네이티브
|
|
새 광고 단위에서 광고를 게재할 수 있으려면 보통 몇 시간이 걸립니다.
광고의 동작을 즉시 테스트하려면 다음 표에 나와 있는 테스트 앱 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
...
dependencies:
flutter:
sdk: flutter
google_fonts: ^0.3.9
# TODO: Add google_mobile_ads as a dependency
google_mobile_ads: ^1.2.0
...
Pub get(Pub 받기)을 클릭하여 AdMob 인라인 광고 프로젝트에 플러그인을 설치합니다.

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 앱 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라는 새 파일을 만듭니다. 그런 다음 AdMob 앱 ID와 Android 및 iOS용 광고 단위 ID를 제공하는 AdHelper 클래스를 구현합니다.
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 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 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 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 UnsupportedError("Unsupported platform");
}
}
6. Google 모바일 광고 SDK 초기화
광고를 로드하기 전에 Google 모바일 광고 SDK를 초기화해야 합니다. lib/home_page.dart 파일을 열고 _initGoogleMobileAds()를 수정하여 SDK를 초기화한 다음 홈페이지를 로드합니다.
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();
}
}
7. 배너 광고 추가
이 섹션에서는 다음 스크린샷과 같이 목록 중간에 배너 광고를 표시합니다.

lib/banner_inline_page.dart파일을 엽니다.- 다음 행을 추가하여
ad_helper.dart와google_mobile_ads.dart를 가져옵니다.
banner_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 BannerInlinePage extends StatefulWidget {
...
}
_BannerInlinePageState클래스에서 배너 광고에 다음 멤버와 메서드를 추가합니다.
_kAdIndex는 배너 광고가 표시될 인덱스를 나타내며 _getDestinationItemIndex() 메서드에서 항목 인덱스를 계산하는 데 사용됩니다.
banner_inline_page.dart
class _BannerInlinePageState extends State<BannerInlinePage> {
// TODO: Add _kAdIndex
static final _kAdIndex = 4;
// TODO: Add a banner ad instance
BannerAd? _ad;
...
// TODO: Add _getDestinationItemIndex()
int _getDestinationItemIndex(int rawIndex) {
if (rawIndex >= _kAdIndex && _ad != null) {
return rawIndex - 1;
}
return rawIndex;
}
...
}
initState()메서드에서 320x50 배너 (AdSize.banner)의BannerAd를 만들고 로드합니다. 광고 이벤트 리스너는 광고가 로드될 때 UI (setState())를 업데이트하도록 구성됩니다.
banner_inline_page.dart
@override
void initState() {
super.initState();
// TODO: Load a banner ad
BannerAd(
adUnitId: AdHelper.bannerAdUnitId,
size: AdSize.banner,
request: AdRequest(),
listener: BannerAdListener(
onAdLoaded: (ad) {
setState(() {
_ad = ad as BannerAd;
});
},
onAdFailedToLoad: (ad, error) {
// Releases an ad resource when it fails to load
ad.dispose();
print('Ad load failed (code=${error.code} message=${error.message})');
},
),
).load();
}
- 가능한 경우 배너 광고를 표시하도록
build()메서드를 수정합니다. itemCount,를 업데이트하여 배너 광고 항목을 계산하고itemBuilder,를 업데이트하여 광고가 로드될 때 광고 인덱스(_kAdIndex)에서 배너 광고를 렌더링합니다._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 + (_ad != null ? 1 : 0),
itemBuilder: (context, index) {
// TODO: Render a banner ad
if (_ad != null && index == _kAdIndex) {
return Container(
width: _ad!.size.width.toDouble(),
height: 72.0,
alignment: Alignment.center,
child: AdWidget(ad: _ad!),
);
} else {
// TODO: Get adjusted item index from _getDestinationItemIndex()
final item = widget.entries[_getDestinationItemIndex(index)];
return ListTile(
...
);
}
},
),
);
}
dispose()콜백 메서드에서BannerAd.dispose()메서드를 호출하여BannerAd객체와 연결된 리소스를 해제합니다.
banner_inline_page.dart
@override
void dispose() {
// TODO: Dispose a BannerAd object
_ad?.dispose();
super.dispose();
}
이제 완료됐습니다. 프로젝트를 실행하고 홈페이지에서 Banner inline ad(배너 인라인 광고) 버튼을 클릭합니다. 광고가 로드되면 목록 중간에 배너 광고가 표시됩니다.

8. 네이티브 광고 추가
이 섹션에서는 다음 스크린샷과 같이 목록 중간에 네이티브 광고를 표시합니다.

네이티브 광고는 Android의 View 또는 iOS의 UIView와 같이 플랫폼의 네이티브인 UI 구성요소를 사용하여 사용자에게 표시됩니다.
그러나 Flutter 위젯을 사용하여 네이티브 UI 구성요소를 직접 생성할 수는 없습니다. 따라서 네이티브 광고 객체(Android의 NativeAd, iOS의 GADNativeAd)에서 플랫폼별 네이티브 광고 뷰(Android의 NativeAdView, iOS의 GADNativeAdView)를 빌드하는 데 사용되는 각 플랫폼의 NativeAdFactory를 구현해야 합니다.
Android용 NativeAdFactory 구현(자바)
android/build.gradle파일 또는 android 폴더의 파일을 열고 Open for Editing in Android Studio(편집을 위해 Android Studio에서 열기)를 클릭하여 Android 프로젝트를 엽니다.

- 새 프로젝트를 열 창을 선택하라는 메시지가 표시되면 New Window(새 창)를 클릭하여 Android 프로젝트에서 작업하는 동안 Flutter 프로젝트를 열어 둡니다.

네이티브 광고 레이아웃 만들기
- Android 프로젝트를 열고 Android 스튜디오의 프로젝트 창에서 앱을 마우스 오른쪽 버튼으로 클릭한 다음 컨텍스트 메뉴에서 New > Android Resource File을 선택합니다.

- New Resource File 대화상자에
list_tile_native_ad.xml을 파일 이름으로 입력합니다. - 리소스 유형으로 Layout을 선택하고
com.google.android.gms.ads.nativead.NativeAdView를 루트 요소로 입력합니다. - OK를 클릭하여 새 레이아웃 파일을 만듭니다.

- 다음과 같이 광고 레이아웃을 구현합니다. 레이아웃은 대상 플랫폼 사용자 환경의 시각적 디자인과 일치해야 합니다.
list_tile_native_ad.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView
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.nativead.NativeAdView>
ListTileNativeAdFactory 클래스 만들기
- 프로젝트 창에서 com.codelab.flutter.admobinlineads 패키지를 마우스 오른쪽 버튼으로 클릭하고 New > Java Class를 선택합니다.

ListTileNativeAdFactory를 이름으로 입력하고 목록에서 Class를 선택합니다.

- New Class 대화상자가 나타나면 모든 항목을 비워 두고 OK를 클릭합니다.
com.codelab.flutter.admobinlineads 패키지에 ListTileNativeAdFactory 클래스가 생성되었음을 확인할 수 있습니다.

- 다음과 같이
ListTileNativeAdFactory클래스를 구현합니다. 이 클래스는GoogleMobileAdsPlugin.NativeAdFactory인터페이스에서createNativeAd()메서드를 구현합니다.
Factory 클래스는 네이티브 광고를 렌더링하기 위한 뷰 객체를 생성합니다. 코드에서 알 수 있듯이 Factory 클래스는 UnifiedNativeAdView를 생성하고 NativeAd 객체로 채웁니다.
ListTileNativeAdFactory.java
// TODO: Implement ListTileNativeAdFactory class
package com.codelab.flutter.admobinlineads;
import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;
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 NativeAdView createNativeAd(
NativeAd nativeAd, Map<String, Object> customOptions) {
NativeAdView nativeAdView = (NativeAdView) 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에 등록해야 합니다.
MainActivity.java파일을 열고configureFlutterEngine()메서드와cleanUpFlutterEngine()메서드를 재정의합니다.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()));
}
...
}
- 정리 프로세스 중에 모든
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");
}
}
이제 ListTileNativeAdFactory 클래스를 사용하여 Android에서 네이티브 광고를 렌더링할 준비가 되었습니다.
Android용 NativeAdFactory 구현(Kotlin)
android/build.gradle파일 또는 android 폴더의 파일을 열고 Open for Editing in Android Studio(편집을 위해 Android Studio에서 열기)를 클릭하여 Android 프로젝트를 엽니다.

- 새 프로젝트를 열 창을 선택하라는 메시지가 표시되면 New Window(새 창)를 클릭하여 Android 프로젝트에서 작업하는 동안 Flutter 프로젝트를 열어 둡니다.

네이티브 광고 레이아웃 만들기
- Android 프로젝트를 열고 Android 스튜디오의 프로젝트 창에서 앱을 마우스 오른쪽 버튼으로 클릭한 다음 컨텍스트 메뉴에서 New > Android Resource File을 선택합니다.

- New Resource File 대화상자에
list_tile_native_ad.xml을 파일 이름으로 입력합니다. - 리소스 유형으로 Layout을 선택하고
com.google.android.gms.ads.nativead.NativeAdView를 루트 요소로 입력합니다. - OK를 클릭하여 새 레이아웃 파일을 만듭니다.

- 다음과 같이 광고 레이아웃을 구현합니다. 레이아웃은 대상 플랫폼 사용자 환경의 시각적 디자인과 일치해야 합니다.
list_tile_native_ad.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView
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.nativead.NativeAdView>
ListTileNativeAdFactory 클래스 만들기
- 프로젝트 창에서 com.codelab.flutter.admobinlineads 패키지를 마우스 오른쪽 버튼으로 클릭하고 New > Kotlin File/Class를 선택합니다.

ListTileNativeAdFactory를 이름으로 입력하고 목록에서 Class를 선택합니다.

com.codelab.flutter.admobinlineads패키지에ListTileNativeAdFactory클래스가 생성되었음을 확인할 수 있습니다.- 다음과 같이
ListTileNativeAdFactory클래스를 구현합니다. 이 클래스는GoogleMobileAdsPlugin.NativeAdFactory인터페이스에서createNativeAd()메서드를 구현합니다.
Factory 클래스는 네이티브 광고를 렌더링하기 위한 뷰 객체를 생성합니다. 코드에서 알 수 있듯이 Factory 클래스는 NativeAdView를 생성하고 NativeAd 객체로 채웁니다.
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.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdView
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin
class ListTileNativeAdFactory(val context: Context) : GoogleMobileAdsPlugin.NativeAdFactory {
override fun createNativeAd(
nativeAd: NativeAd,
customOptions: MutableMap<String, Any>?
): NativeAdView {
val nativeAdView = LayoutInflater.from(context)
.inflate(R.layout.list_tile_native_ad, null) as NativeAdView
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에 등록해야 합니다.
MainActivity.kt파일을 열고configureFlutterEngine()메서드와cleanUpFlutterEngine()메서드를 재정의합니다.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))
}
...
}
- 정리 프로세스 중에 모든
NativeAdFactory인스턴스를 등록 취소해야 합니다.cleanUpFlutterEngine()메서드에서ListTileNativeAdFactory클래스를 등록 취소합니다.
MainActivity.kt
class MainActivity: FlutterActivity() {
...
override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
super.cleanUpFlutterEngine(flutterEngine)
// TODO: Unregister the ListTileNativeAdFactory
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile")
}
}
이제 ListTileNativeAdFactory 클래스를 사용하여 Android에서 네이티브 광고를 렌더링할 준비가 되었습니다.
iOS용 NativeAdFactory 구현(Objective-C)
ios/Podfile 파일 또는 iOS 폴더의 파일을 열고 Open iOS module in Xcode(Xcode에서 iOS 모듈 열기)를 클릭하여 iOS 프로젝트를 엽니다.

네이티브 광고 레이아웃 준비
네이티브 광고 애셋을 배치하려면 맞춤 뷰(*.xib)가 있어야 합니다. 이 Codelab에서는 사전 구성된 뷰를 사용하여 노력을 최소화할 수 있습니다.
Xcode에서 iOS 프로젝트가 열리면 Runner(러너) 프로젝트에 ListTileNativeAdView.xib가 있는지 확인합니다.

ListTileNativeAdFactory 클래스 만들기
- 프로젝트 탐색기에서 Runner(러너) 그룹을 마우스 오른쪽 버튼으로 클릭하고 New File(새 파일)을 선택하여 새 클래스의 헤더 파일을 만듭니다.

- 템플릿 대화상자에서 Header File(헤더 파일)을 선택하고 이름을
ListTileNativeAdFactory로 지정합니다. 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 */
- Runner(러너) 그룹에서 New File(새 파일)을 선택하여 Objective-C 파일을 만듭니다.
- 다음 대화상자의 File(파일) 필드에
ListTileNativeAdFactory를 입력하고 파일 형식으로 Empty File(빈 파일)을 선택합니다.

- Next(다음)를 클릭하면 새 파일을 만들 폴더를 선택하라는 메시지가 표시됩니다. 아무 것도 변경하지 않고 Create(생성)를 클릭합니다.

- 다음과 같이
ListTileNativeFactory클래스를 구현합니다. 이 클래스는FLTNativeAdFactory프로토콜에서createNativeAd()메서드를 구현합니다.
Factory 클래스는 네이티브 광고를 렌더링하기 위한 뷰 객체를 생성합니다. 코드에서 알 수 있듯이 Factory 클래스는 GADNativeAdView를 생성하고 GADNativeAd 객체로 채웁니다.
ListTileNativeAdFactory.m
// TODO: Import ListTileNativeAdFactory.h
#import "ListTileNativeAdFactory.h"
// TODO: Implement ListTileNativeAdFactory
@implementation ListTileNativeAdFactory
- (GADNativeAdView *)createNativeAd:(GADNativeAd *)nativeAd
customOptions:(NSDictionary *)customOptions {
GADNativeAdView *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
ListTileNativeAdFactory 클래스 등록
FLTNativeAdFactory의 구현을 Flutter 측에서 사용하려면 FLTGoogleMobileAdsPlugin에 등록해야 합니다.
AppDelegate.m 파일을 열고 [FLTGoogleMobileAdsPlugin registerNativeAdFactory] 메서드를 호출하여 ListTileNativeAdFactory를 고유 문자열 ID(listTile)로 등록합니다.
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
이제 ListTileNativeAdFactory를 사용하여 iOS에서 네이티브 광고를 렌더링할 수 있습니다.
iOS용 NativeAdFactory 구현(Swift)
ios/Podfile 파일 또는 iOS 폴더의 파일을 열고 Open iOS module in Xcode(Xcode에서 iOS 모듈 열기)를 클릭하여 iOS 프로젝트를 엽니다.

네이티브 광고 레이아웃 준비
네이티브 광고 애셋을 배치하려면 맞춤 뷰(*.xib)가 있어야 합니다. 이 Codelab에서는 사전 구성된 뷰를 사용하여 노력을 최소화할 수 있습니다.
Xcode에서 iOS 프로젝트가 열리면 Runner(러너) 프로젝트에 ListTileNativeAdView.xib가 있는지 확인합니다.

ListTileNativeAdFactory 클래스 만들기
- 프로젝트 탐색기에서 Runner(러너) 그룹을 마우스 오른쪽 버튼으로 클릭하고 New File(새 파일)을 선택하여 새 클래스의 헤더 파일을 만듭니다.

- 템플릿 대화상자에서 Swift File(Swift 파일)을 선택하고 이름을
ListTileNativeAdFactory로 지정합니다. ListTileNativeAdFactory.swift파일이 생성되면ListNativeAdFactory클래스를 구현합니다.
이 클래스는 FLTNativeAdFactory 프로토콜에서 createNativeAd() 메서드를 구현합니다.
Factory 클래스는 네이티브 광고를 렌더링하기 위한 뷰 객체를 생성합니다. 코드에서 알 수 있듯이 Factory 클래스는 GADNativeAdView를 생성하고 GADNativeAd 객체로 채웁니다.
ListTileNativeAdFactory.swift
// TODO: Import google_mobile_ads
import google_mobile_ads
// TODO: Implement ListTileNativeAdFactory
class ListTileNativeAdFactory : FLTNativeAdFactory {
func createNativeAd(_ nativeAd: GADNativeAd,
customOptions: [AnyHashable : Any]? = nil) -> GADNativeAdView? {
let nibView = Bundle.main.loadNibNamed("ListTileNativeAdView", owner: nil, options: nil)!.first
let nativeAdView = nibView as! GADNativeAdView
(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
}
}
ListTileNativeAdFactory 클래스 등록
FLTNativeAdFactory의 구현을 Flutter 측에서 사용하려면 FLTGoogleMobileAdsPlugin에 등록해야 합니다.
AppDelegate.m 파일을 열고 FLTGoogleMobileAdsPlugin.registerNativeAdFactory() 메서드를 호출하여 ListTileNativeAdFactory를 고유 문자열 ID(listTile)로 등록합니다.
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)
}
}
이제 ListTileNativeAdFactory를 사용하여 iOS에서 네이티브 광고를 렌더링할 수 있습니다.
Flutter 위젯과 네이티브 광고 통합
lib/native_inline_page.dart파일을 엽니다. 다음 행을 추가하여ad_helper.dart와google_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 {
...
}
_NativeInlinePageState클래스에서 네이티브 광고에 다음 멤버와 메서드를 추가합니다.
_kAdIndex는 배너 광고가 표시될 인덱스를 나타내며 _getDestinationItemIndex() 메서드에서 항목 인덱스를 계산하는 데 사용됩니다.
native_inline_page.dart
class _NativeInlinePageState extends State<NativeInlinePage> {
// TODO: Add _kAdIndex
static final _kAdIndex = 4;
// TODO: Add a native ad instance
NativeAd? _ad;
...
// TODO: Add _getDestinationItemIndex()
int _getDestinationItemIndex(int rawIndex) {
if (rawIndex >= _kAdIndex && _ad != null) {
return rawIndex - 1;
}
return rawIndex;
}
...
}
initState()메서드에서ListTileNativeAdFactory를 사용하여NativeAd를 만들고 로드하여 네이티브 광고 뷰를 생성합니다.
플러그인에 Factory를 등록하는 데 사용된 것과 동일한 Factory 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: NativeAdListener(
onAdLoaded: (ad) {
setState(() {
_ad = ad as NativeAd;
});
},
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();
}
- 가능한 경우 배너 광고를 표시하도록
build()메서드를 수정합니다. itemCount,를 업데이트하여 배너 광고 항목을 계산하고itemBuilder,를 업데이트하여 광고가 로드되면 광고 인덱스(_kAdIndex)에서 배너 광고를 렌더링합니다._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 + (_ad != null ? 1 : 0),
itemBuilder: (context, index) {
// TODO: Render a banner ad
if (_ad != null && index == _kAdIndex) {
return Container(
height: 72.0,
alignment: Alignment.center,
child: AdWidget(ad: _ad!),
);
} else {
// TODO: Get adjusted item index from _getDestinationItemIndex()
final item = widget.entries[_getDestinationItemIndex(index)];
return ListTile(
...
);
}
},
),
);
}
dispose()콜백 메서드에서NativeAd.dispose()메서드를 호출하여NativeAd객체와 연결된 리소스를 해제합니다.
native_inline_page.dart
@override
void dispose() {
// TODO: Dispose a NativeAd object
_ad?.dispose();
super.dispose();
}
이제 완료됐습니다. 프로젝트를 실행하고 홈페이지에서 Native inline ad(네이티브 인라인 광고) 버튼을 클릭합니다. 광고가 로드되면 목록 중간에 네이티브 광고가 표시됩니다.

9. 완료
Codelab을 완료했습니다. 이 Codelab의 완성된 코드는
complete 또는
complete_kotlin_swift 폴더에서 찾을 수 있습니다.

