[Flutter]Admob 연동하기
- -
최근 플러터를 이용해 앱을 개발했는데 광고를 추가하는 과정을 포스팅하려고 합니다. 아마 앱 개발을 해보려고 하시는 분들 중 많은 분들이 광고를 넣을 것이라 예상됩니다.
광고를 넣기 전 앱 배포를 먼저 하시는 것을 추천합니다.
※ 테스트 환경
- Flutter 3.10.5
- Dart 3.0.5
- Android Studio 2022
- Xcode 14.3
1. Admob 관리
광고는 Google Admob을 이용합니다. 먼저 Android, iOS 환경에 맞는 광고단위를 생성해야 합니다.
애드몹에 접속해 Android, iOS 앱을 각각 생성합니다.
1-1) Android 앱 생성
앱 배포가 되어 있는 시점이라면 화면과 같이 클릭, 이후 추가 정보를 입력하고 단계를 마무리합니다. 배포되어 있지 않다면 아래와 같이 추가되며 완료됩니다.
1-2) Android 광고 단위 생성
왼쪽 상단에 광고 단위 - 광고 단위 추가를클릭합니다. 여기서는 배너 타입을 만들어보도록 하겠습니다.
1-3) Android 광고 아이디 저장
생성된 광고 단위에는 고유로 부여되는 아이디값이 존재합니다. 위에서부터 순서대로 첫번째에 위치한 아이디는 AndroidManifest.xml 저장될 값이고 두번째에 위치한 아이디는 Flutter에서 사용될 아이디값입니다.
1-4) iOS 앱 및 광고 단위 생성
위에서 진행한 과정대로 iOS 앱과 광고 단위를 생성합니다.
첫번째 위치한 아이디값은 Xcode에 입력될 아이디값이고 두번째 위치한 값은 Flutter에서 사용될 아이디값입니다.
2. Android 설정
2-1) AndroidManifest.xml 설정
Android Studio를 실행해 AndroidManifest.xml 파일을 수정합니다.
<application> 태그 안에 1-3) 에서 얻은 광고 아이디를 입력합니다. (아래 입력된 광고 아이디는 실제 사용되는 앱이 아닌 예제용 테스트 앱의 광고 아이디입니다)
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3752177131465533~4937708002"/>
2-2) build.gradle(app 수준) 설정
sdk 버전 수정
Admob 을 사용하기 위해서는 최소 SDK 버전을 맞춰야합니다.
현재(2023.11.01 기준) 최소 SDK 버전은 19고 컴파일 최소 버전은 28입니다. => 참고
defaultConfig {
applicationId "com.example.admob_example"
minSdkVersion 21
targetSdkVersion 32
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
dependencie 추가
dependencies {
implementation 'com.google.android.gms:play-services-ads:22.5.0'
}
3. iOS 설정
3-1) Info.plist 설정
Xcode를 실행해 먼저 아래와 같이 Info - Open As - Source Code로 보기 형태를 바꿔줍니다.
중간쯤에 1-4) 에서 얻은 광고 아이디를 입력합니다. (아래 입력된 광고 아이디는 실제 사용되는 앱이 아닌 예제용 테스트 앱의 광고 아이디입니다)
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3752177131465533~6358045312</string>
추가로 SKAdNetworkItems 키도 입력합니다.
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4fzdc2evr5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4pfyvq9l8r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2fnua5tdw4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ydx93a7ass.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>5a6flpkh64.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>p78axxw29g.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v72qych5uu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ludvb6z3bs.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cp8zw746q7.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3sh42y64q3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>c6k4g5qg8m.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>s39g8k73mm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qy4746246.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f38h382jlk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>hs6bdukanm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v4nxqhlyqp.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>wzmmz9fp6w.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>yclnxrl5pm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>t38b2kh725.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7ug5zh24hu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>gta9lk7p23.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>vutu7akeur.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>y5ghdn5j9k.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n6fk4nfna4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v9wttpbfk9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n38lu8286q.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>47vhws6wlr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>kbd757ywx3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9t245vhmpl.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>eh6m2bh4zr.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>a2p9lx4jpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>22mmun2rn5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4468km3ulz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2u9pt9hc89.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8s468mfl3y.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>klf5c3l5u5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ppxm28t8ap.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ecpz2srf59.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>uw77j35x4d.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>pwa73g5rt2.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>mlmmfzh3r3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>578prtvx9j.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4dzt52r2t5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>e5fvkxwrpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8c4e2ghe7u.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>zq492l623r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3rd42ekr43.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qcr597p9d.skadnetwork</string>
</dict>
</array>
최종 입력된 키 값은 아래와 같습니다.
4. Flutter 설정
4-1) 플러그인 설치
Flutter에서는 google_mobile_ads 플러그인을 이용해 애드몹을 실행하게 됩니다.
pubspec.yaml에 플러그인을 추가합니다. (logger는 애드몹 실행시 작동 여부를 확인하기 위해 추가해줍니다)
logger: ^1.4.0
google_mobile_ads: ^3.0.0
또는
flutter pub add google_mobile_ads
4-2) Admob 초기화
main이 실행되는 함수 안에 아래와 같이 초기화를 해줍니다.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 애드몹 초기화
await MobileAds.instance.initialize();
runApp(const MyApp());
}
4-3) Admob 실행
광고 아이디는 따로 상수 파일로 관리합니다.
디버그(테스트) 환경에서 반드시 테스트 광고 아이디를 사용해 출력합니다. 실제 아이디값을 사용해 광고를 출력하게 되면 해당 광고 아이디를 사용하지 못할 수도 있습니다.
광고 단위별로 테스트 광고 아이디값이 존재합니다. 테스트 아이디는 여기서 확인하실 수 있습니다.
/// Admob Id
/// Android
const String admobAndBottomBannerId = 'ca-app-pub-3752177131465533/8735978402';
const String admobAndBottomTestBannerId =
'ca-app-pub-3940256099942544/6300978111';
/// iOS
const String admobIosBottomBannerId = 'ca-app-pub-3752177131465533/8544406719';
const String admobIosBottomTestBannerId =
'ca-app-pub-3940256099942544/2934735716';
4-4) logger 유틸 추가
import 'package:logger/logger.dart';
var logger = Logger(
printer: PrettyPrinter(
methodCount: 2,
),
);
4-5) Admob 위젯 추가
Admob은 위젯으로 분리해 관리합니다. 실행 디바이스에 따라 Android/iOS 키 값을 사용하도록 하고 디버그모드를 체크해 테스트 광고 아이디를 사용할 수 있도록 합니다.
import 'dart:io';
import 'package:admob_example/constants/constants.dart';
import 'package:admob_example/utils/logger_util.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
class Admob extends StatelessWidget {
final int width;
final int height;
Admob({
super.key,
required this.width,
required this.height,
});
@override
Widget build(BuildContext context) {
final AdSize adSize = AdSize(width: width, height: height);
final BannerAdListener adListener = BannerAdListener(
onAdLoaded: (Ad ad) => logger.i('Ad loaded.'),
onAdFailedToLoad: (Ad ad, LoadAdError error) {
ad.dispose();
logger.i('Ad failed to load: $error');
},
onAdOpened: (Ad ad) => logger.i('Ad opened.'),
onAdClosed: (Ad ad) => logger.i('Ad closed.'),
onAdImpression: (Ad ad) => logger.i('Ad impression.'),
);
BannerAd banner = BannerAd(
size: adSize,
adUnitId: Platform.isIOS
? kDebugMode
? admobIosBottomTestBannerId
: admobIosBottomBannerId
: kDebugMode
? admobAndBottomTestBannerId
: admobAndBottomBannerId,
listener: adListener,
request: const AdRequest(),
)..load();
return AdWidget(
ad: banner,
);
}
}
4-6) MyApp 클래스 추가
main 함수에서 실행되는 MyApp클래스를 작성합니다.
광고 배너별로 사이즈가 정해져있는데 너비와 높이 설정이 가능합니다. 실제 사용중인 앱에서는 화면 사이즈를 구해 width에 값 셋팅을 하고 높이는 고정으로 해서 사용하고 있습니다.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Admob Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 8,
child: Container(),
),
Expanded(
flex: 2,
child: Admob(
width: 320,
height: 50,
)),
],
),
));
}
}
5. 테스트
이제 앱을 실행하고 아래와 같이 테스트 광고가 나온다면 정상입니다.
참고문서
전체 코드는 GitHub에서 확인하실 수 있습니다.
'Framework > Flutter' 카테고리의 다른 글
[Flutter]아이콘 변경하기 (0) | 2023.11.16 |
---|---|
[Error]onRequestPermissionsResult is called without results. This is probably caused by interfering request codes. (0) | 2023.11.16 |
[Error]The file couldn't be opened (0) | 2023.09.06 |
[Flutter]TestFlight 설정 (0) | 2023.07.29 |
[Flutter]FVM 설정 (0) | 2023.07.21 |
소중한 공감 감사합니다.