가을기 Workspace

[플러터] 17일차 - 앱 내 광고 구현하기 +배너광고 본문

개발/개인앱

[플러터] 17일차 - 앱 내 광고 구현하기 +배너광고

가을기_ 2021. 7. 17. 01:58

 

 

앱에 애드몹 패키지를 추가하자.

  • pubspec.yml
dependencies:
  flutter:
    sdk: flutter
  google_mobile_ads: ^0.13.0
  sqflite: ^2.0.0+3
  path: ^1.7.0

google mobile_ads를 추가한다.

 

Android

  • android/app/src/main/AndroidManifest.xml
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="{admob_appId}"
            />
    </application>
</manifest>

앱에서 admob광고를 보여주려면 manifest에서 admob app id를 입력해야한다.

끝자락에 위와같이 넣어주자.

 

 

  • android/build.gradle
buildscript {
    ext.kotlin_version = '1.3.50'
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

gradle의 버젼이 4.1.2 이상이어야 한다.

 

  • android/app/build.gradle
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.actumn.stickynotes"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

sdkversion이 19 이상이어야 한다.

 

iOS

  • ios/Runner/info.plist
   <key>GADApplicationIdentifier</key>
   <string>{admob_app_id></string>
</dict>
</plist>

android와 마찬가지로 admob app id를 넣어줘야 한다.

 

 

 

 

배너 광고 추가하기

  • ad_helper.dart
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

class AdHelper {
  bool _isInitialized = false;

  BannerAd? _banner;

  void loadBanner(Function(BannerAd) onBannerAdLoaded) async {
    await _initialize();

    if (_banner != null) {
      await _banner!.load();
      onBannerAdLoaded(_banner!);
      return;
    }

    _banner = BannerAd(
        size: AdSize.banner,
        adUnitId: _getBannerAdUnitId(),
        listener: BannerAdListener(
            onAdLoaded: (ad) {
              onBannerAdLoaded(ad as BannerAd);
            }
        ),
        request: AdRequest()
    );

    await _banner!.load();
  }

  EdgeInsets getFabPadding(BuildContext context) {
    double bannerHeight = 50.0;
    return EdgeInsets.only(bottom: bannerHeight);
  }

  void dispose() {
    _banner?.dispose();
  }

  Future<void> _initialize() async {
    if (!_isInitialized) {
      await MobileAds.instance.initialize();
      _isInitialized = true;
    }
  }

  String _getBannerAdUnitId() {
    if (Platform.isAndroid) {
      return 'ca-app-pub-3940256099942544/6300978111'; // android 테스트 광고 id
    } else if (Platform.isIOS) {
      return 'ca-app-pub-3940256099942544/2934735716'; // iOS 테스트 광고 id
    }
    throw StateError('Unsupported platform');
  }
}

광고 SDK 초기화도 필요하고, FloatingActionButton padding도 필요하고, 배너 광고 로딩도 필요하다.

 

  • providers.dart
import 'package:sticky_notes/ad_helper.dart';

import 'data/note_manager.dart';

AdHelper _adHelper = new AdHelper();

NoteManager _noteManager = new NoteManager();

AdHelper adHelper() {
  return _adHelper;
}

NoteManager noteManager() {
  return _noteManager;
}

 

 

  • pages/note_list_page.dart
class _NoteListPageState extends State<NoteListPage> {
  BannerAd? _bannerAd; // 로드할 광고정보를 저장할 변수

  @override
  void initState() {
    super.initState();
    adHelper().loadBanner((ad) => {
          if (_bannerAd == null)
            {
              setState(() {
                // 화면 갱신
                _bannerAd = ad;
              })
            }
        });
  }

...

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sticky Notes'),
      ),
      // body: GridView(
      //   children: _buildCards(),
      //   gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
      //     crossAxisCount: 2,
      //     childAspectRatio: 1,
      //   ),
      //   padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 16.0),
      // ),
      body: FutureBuilder(
        future: NoteManager().listNotes(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(
              child: CircularProgressIndicator(),
            );
          }

          if (snapshot.hasData) {
            List<Note> notes = snapshot.data as List<Note>;
            GridView noteGrid = GridView.builder(
                padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 16.0),
                itemCount: notes.length,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  childAspectRatio: 1,
                ),
                itemBuilder: (context, index) {
                  return _buildCard(notes[index]);
                });

            if (_bannerAd != null) {
              return SafeArea(
                child: Column(
                  children: [
                    Expanded(child: noteGrid), // gridView의 높이가 무한히 길어지면 좀 그렇다
                    Container(
                      width: _bannerAd!.size.width.toDouble(),
                      height: _bannerAd!.size.height.toDouble(),
                      child: AdWidget(
                        ad: _bannerAd!,
                      ),
                    ),
                  ],
                ),
              );
            } else {
              return noteGrid;
            }
          }

          return Center(
            child: Text('오류가 발생했습니다'),
          );
        },
      ),
      floatingActionButton: Padding(
        padding: _bannerAd != null
            ? adHelper().getFabPadding(context)
            : EdgeInsets.zero,
        child: FloatingActionButton(
          child: Icon(Icons.add),
          tooltip: '새 노트',
          onPressed: () {
            Navigator.pushNamed(context, NoteEditPage.rootName).then((value) {
              setState(() {});
            });
          },
        ),
      ),
    );
  }


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

하단 배너를 달기 위해 변수도 저장해야하고 gridView를 Expanded로 감싸고, floatingActionButton에 padding도 넣는다.

배너가 하단 navigator하고 겹치면 안되니까 또 safearea 써야한다..

 

 

ad unit 에 실제 id를 넣었다면, 실수로라도 광고 클릭시 정책위반 사유가 되어 계정이 정지될 수 있다.. 따라서 테스트 기기를 등록해서 테스트 모드로 사용하는 것이 좋다.

그런데 어차피 simulator 쓰면 테스트기기다. 걱정 안해도 될듯.

 

 

Comments