[Flutter] Admob

2023-03-18 hit count image

이번 블로그 포스트에서는 Flutter로 생성한 앱에 google_mobile_ads 패키지를 사용해서 Admob 광고를 표시하는 방법에 대해서 살펴봅시다.

개요

이번 블로그 포스트에서는 google_mobile_ads 패키지를 사용해서 Admob 광고를 표시하는 방법에 대해서 소개합니다.

이 블로그 포스트에서 Admob의 배너 광고를 표시하는 방법에 대해서 알아볼 예정이며, 소스 코드는 아래에 링크에서 확인할 수 있습니다.

Admob 설정

Flutter 프로젝트에서 Admob을 사용하기 위해서는, Admob 서비스를 이용할 필요가 있습니다.

구글 애드몹 가입

구글 애드몹(Google Admob) 사이트로 이동하여 회원가입을 합니다. 일반적인 회원가입/로그인 절차임으로 설명을 생략합니다.

Admob 생성

구글 애드몹(Google Admob) 사용법에 대해서 알아봅니다. 구글 애드몹(Google Admob)을 사용하기 위해 구글 애드몹(Google Admob) 사이트에 회원가입을 하고 로그인을 하면 아래와 같은 화면을 볼 수 있습니다.

signin google admob

하단에 있는 GET STARTED 버튼을 눌러 구글 애드몹(Google Admob) 사용을 시작합니다.

configure admob

이미 앱이 마켓에 등록되어있는지 여부를 선택합니다. 우리는 아직 앱을 등록하지 않은 상태이므로 NO를 선택합니다.

configure app name on admob

구글 애드몹(Google Admob)을 사용하기 위해 앱 이름을 작성하고 사용할 플랫폼을 선택합니다. 우리는 우선 iOS를 선택하여 진행하겠습니다.

completed to configure

구글 애드몹(Google Admob) 등록이 완료되었습니다. 친절하게 하단에 다음 단계에 대한 설명이 잘 나와있습니다.

  1. Flutter에 Admob을 설정할때 필요한 App ID를 복사해둡니다.
  2. 광고 타입(ad unit)을 구글 애드몹(Google Admob)에서 설정합니다.
  3. 앱을 앱스토어에 등록하면 구글 애드몹(Google Admob)에서 연결해줘야합니다.

하단에 있는 NEXT: CREATE AD UNIT을 눌러 광고 타입 설정화면으로 이동합니다.

select advertisement type

우리는 일단 배너 광고 사용해 보겠습니다. Banner의 하단에 SELECT버튼을 선택합니다.

input banner name

해당 배너의 이름을 설정합니다. 구글 애드몹(Google Admob) 서비스에서 해당 배너를 쉽게 찾기 위한 이름이므로 자신이 쉽게 인식할 수 있는 이름을 설정합니다. 입력을 완료했으면 CREATE AD UNIT 버튼을 눌러 설정을 끝냅니다.

finished configuration

구글 애드몹(Google Admob)의 배너 설정을 완료했습니다. 다시 나온 App ID와 배너의 Ad Unit ID를 잘 복사해 둡니다.

안드로이드도 위와 같은 방식으로 배너 광고를 생성하여 App ID와 Ad Unit ID를 생성합니다.

프로젝트 생성

그럼 google_mobile_ads 패키지를 사용해서 Admob 광고를 표시하기 위해서, Flutter 프로젝트를 새로 만들어 봅시다. 다음 명령어를 사용하여 Flutter 프로젝트를 생성합니다.

flutter create admob_example
cd admob_example

google_mobile_ads 패키지 설치

Flutter 프로젝트에서 Admob 광고를 표시하기 위해서는 google_mobile_ads 패키지를 설치할 필요가 있습니다. 다음 명령어를 실행하여 google_mobile_ads 설치합니다.

flutter pub add google_mobile_ads

App ID 설정

이제 google_mobile_ads 사용하여 Admob 광고를 표시하기 위해서, iOS/Android 에 App ID를 설정할 필요가 있습니다.

Android에 App ID 설정

안드로이드에 Admob의 App ID를 설정하기 위해, android/app/src/main/AndroidManifest.xml 파일을 열고 다음과 같이 수정합니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.admob_example">
   <application
        ...>
        <meta-data
              android:name="com.google.android.gms.ads.APPLICATION_ID"
              android:value="[YOUR ANDROID APP ID]"/>
        ...
    </application>
</manifest>

iOS에 App ID 설정

iOS에 Admob의 App ID를 설정하기 위해, ios/Runner/Info.plist 파일을 열고 다음과 같이 수정합니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  ...
  <key>GADApplicationIdentifier</key>
  <string>[YOUR iOS APP ID]</string>
  <key>LSRequiresIPhoneOS</key>
  <true/>
  <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>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>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>3sh42y64q3.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>prcb7njmu6.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>9rd848q2bz.skadnetwork</string>
      </dict>
      <dict>
        <key>SKAdNetworkIdentifier</key>
        <string>n6fk4nfna4.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>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>av6w8kgt66.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>424m5254lk.skadnetwork</string>
      </dict>
      <dict>
        <key>SKAdNetworkIdentifier</key>
        <string>uw77j35x4d.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>3qcr597p9d.skadnetwork</string>
      </dict>
    </array>
</dict>
</plist>

google_mobile_ads 사용방법

그럼 이제 google_mobile_ads을 사용해서 Admob 광고를 표시하기 위해, main.dart 파일을 열고 다음과 같이 수정합니다.

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

const Map<String, String> UNIT_ID = kReleaseMode
    ? {
        'ios': '[YOUR iOS AD UNIT ID]',
        'android': '[YOUR ANDROID AD UNIT ID]',
      }
    : {
        'ios': 'ca-app-pub-3940256099942544/2934735716',
        'android': 'ca-app-pub-3940256099942544/6300978111',
      };

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  MobileAds.instance.initialize();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    TargetPlatform os = Theme.of(context).platform;

    BannerAd banner = BannerAd(
      listener: BannerAdListener(
        onAdFailedToLoad: (Ad ad, LoadAdError error) {},
        onAdLoaded: (_) {},
      ),
      size: AdSize.banner,
      adUnitId: UNIT_ID[os == TargetPlatform.iOS ? 'ios' : 'android']!,
      request: AdRequest(),
    )..load();

    return Scaffold(
      appBar: AppBar(
        title: Text('Admob'),
      ),
      body: Center(
        child: Container(
          height: 50,
          child: AdWidget(
            ad: banner,
          ),
        ),
      ),
    );
  }
}

소스 코드를 하나하나 자세히 살펴봅시다.

import 'package:flutter/foundation.dart';

Admob 광고는 개발 환경일 때, 자신의 AD UNIT ID를 사용하면 안됩니다. 자신의 개발 환경에서 자신의 AD UNIT ID를 사용할 경우, 실제 광고 트래픽이 아닌 부정 트래픽으로 간주될 수 있으며, 자주 사용되면 광고 게제를 차단 당할 수 있습니다. 따라서 이번 예제에서는 kReleaseMode을 사용해서 현재 실행중인 상태가 debug인지 release인지 구별할 예정입니다. kReleaseMode를 사용하기 위해서는 foundation.dart를 추가해야합니다.

import 'package:google_mobile_ads/google_mobile_ads.dart';

google_mobile_ads을 사용하기 위해 추가하였습니다.

const Map<String, String> UNIT_ID = kReleaseMode
    ? {
        'ios': '[YOUR iOS AD UNIT ID]',
        'android': '[YOUR ANDROID AD UNIT ID]',
      }
    : {
        'ios': 'ca-app-pub-3940256099942544/2934735716',
        'android': 'ca-app-pub-3940256099942544/6300978111',
      };

kReleaseMode을 사용해서 현재 환경이 release인 경우, 우리가 만든 AD UNIT ID를 사용하도록 설정하였습니다. 그렇지 않은 경우, Admob에서 제공하는 테스트용 AD UNIT ID를 사용하도록 하였습니다.

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  MobileAds.instance.initialize();

  runApp(MyApp());
}

이제 google_mobile_ads을 사용하여 Admob 광고를 표시하기 위해 MobileAds을 초기화할 필요가 있습니다. WidgetsFlutterBinding.ensureInitialized();을 사용하여 Flutter가 초기화가 잘 되었는지 확인한 후, MobileAds.instance.initialize();을 호출하여 MobileAds를 초기화 합니다.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
}

간단한 샘플 코드를 작성하기 위해 Stateless 위젯을 생성하였습니다.

이제 실제 배너 광고를 표시하는 소스 코드를 자세히 살펴봅시다.

@override
Widget build(BuildContext context) {
  TargetPlatform os = Theme.of(context).platform;

  BannerAd banner = BannerAd(
    listener: BannerAdListener(
      onAdFailedToLoad: (Ad ad, LoadAdError error) {},
      onAdLoaded: (_) {},
    ),
    size: AdSize.banner,
    adUnitId: UNIT_ID[os == TargetPlatform.iOS ? 'ios' : 'android']!,
    request: AdRequest(),
  )..load();

  return Scaffold(
    appBar: AppBar(
      title: Text('Admob'),
    ),
    body: Center(
      child: Container(
        height: 50,
        child: AdWidget(
          ad: banner,
        ),
      ),
    ),
  );
}

각 플랫폼별 AD UNIT ID가 다르므로, 현재 Flutter가 실행중인 플랫폼을 구별할 필요가 있습니다. 이를 위해 TargetPlatform을 사용했습니다.

TargetPlatform os = Theme.of(context).platform;

그리고 google_mobile_ads에서 제공하는 BannerAd 클래스를 사용하여 배너 광고를 생성하였으며, Cascade operator를 사용하여, 생성과 동시에 load() 함수를 실행하여, 광고를 불러왔습니다.

BannerAd banner = BannerAd(
  listener: BannerAdListener(
    onAdFailedToLoad: (Ad ad, LoadAdError error) {},
    onAdLoaded: (_) {},
  ),
  size: AdSize.banner,
  adUnitId: UNIT_ID[os == TargetPlatform.iOS ? 'ios' : 'android']!,
  request: AdRequest(),
)..load();

이때, AdListener를 사용하여 광고 관련 이벤트에 콜백 함수를 등록할 수 있으며, AdRequest의 여러 파라메터들을 통해 좀 더 효율적으로 광고를 표시할 수 있습니다.

이렇게 생성한 광고를 AdWidget를 통해 화면에 표시할 수 있습니다.

AdWidget(
  ad: banner,
)

현재 예제는 간단히 광고를 표시하기 위한 방법을 Stateless 위젯을 사용하여 살펴보았습니다. 만약, Stateful 위젯을 사용한다면, 다음과 같이 위젯이 사라질 때, 광고를 제거해 줘야합니다.

@override
void dispose() {
  super.dispose();
  _banner.dispose();
}

이슈

google_mobile_ads으로 광고를 표시하면서 겪은 이슈를 공유합니다.

await MobileAds.instance.initialize()

저는 google_mobile_ads의 버전을 0.13.4로 설정하여 사용하고 있습니다. 이 버전 이후에서는 안드로이드의 일부 단말기에서 await MobileAds.instance.initialize() 부분이 끝나지 않고 계속 실행되어 앱이 강제 종료되는 문제가 발생하고 있습니다.

따라서 저는 아직도 0.13.4 버전을 고정해서 사용하고 있습니다.

dependencies:
  ...
  google_mobile_ads: 0.13.4

Ad failed to load : 3

개발중인 앱을 에뮬레이터에서 test unit id를 사용하여 배너 광고 표시를 시도하면 Ad failed to load : 3 에러 메시지와 함께 광고가 표시되지 않는 문제가 있습니다.

저는 이 문제를 해결하기 위해, 개발중인 앱에서도 test unit id가 아닌 실제 unit id를 사용고 있습니다. 실제 unit id를 사용해도 에뮬레이터에서는 Test mode와 함께 문제없이 광고가 표시되는 것을 확인하였습니다.

Test mode가 표시되고 있으므로 부정 광고 트래픽으로 잡히고 있지 않다고 판단하고 개발할 때에도 실제 unit id를 사용하고 있습니다.

만약 실제 unit id를 사용해도 동일한 에러 메시지가 나온다면, 해당 앱을 실제 디바이스에 올려서, 실제 트래픽을 발생시켜 봅니다. Ad failed to load : 3 메시지는 에러가 아닌 광고가 준비가 되지 않았다는 의미입니다. 그러므로 설정은 제대로 된게 맞습니다. 다만 여러 이유에서 화면에 표시할 광고가 준비가 되지 않았다는 의미입니다. 실제 트래픽도 광고를 준비하는데 영향을 주므로, 실제 디바이스에서 앱을 동작시켜 실제 트래픽을 발생시켜 봅니다.

완료

이것으로 google_mobile_ads 패키지를 사용하여 Admob 광고를 표시하는 방법에 대해서 알아보았습니다. 이제 여러분도, 여러분의 앱에 광고를 추가하여 수익을 발생시켜 보시기 바랍니다!

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts