Framework/Flutter

[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. 테스트

이제 앱을 실행하고 아래와 같이 테스트 광고가 나온다면 정상입니다.

(좌)Android / (우)iOS

 

 

참고문서
 

시작하기  |  Flutter  |  Google for Developers

Flutter 앱을 제작 중인 AdMob 게시자를 위한 모바일 광고 SDK입니다.

developers.google.com

 

google_mobile_ads | Flutter Package

Flutter plugin for Google Mobile Ads, supporting banner, interstitial (full-screen), rewarded and native ads

pub.dev

 

시작하기  |  Mobile Ads SDK for iOS  |  Google for Developers

iOS 앱을 제작 중인 게시자를 위한 모바일 광고 SDK입니다.

developers.google.com


전체 코드는 GitHub에서 확인하실 수 있습니다.

반응형
Contents

포스팅 주소를 복사했습니다.

이 글이 도움이 되었다면 공감 부탁드립니다.