Love them or hate them, ads are a common way for indie app developers to make money from their apps. So, how can you display a banner ad in your Flutter app?

If you search Flutter packages for “ad”, there are currently two relevant results, both for AdMob. One is admob and the other is firebase_admob. As of writing this, the former only supports interstitial ads and hasn’t been updated for 7 months; as for the latter, it supports interstitial, banner and rewarded video ads as of version 0.3.0, and was updated last week.

This code tutorial will show you how to display a banner ad using firebase_admob plugin. It includes a trick to make sure the ad doesn’t hide the bottom of your screen content, so, for example, your Snackbars aren’t hidden behind the banner ad.

Set up the app

We will create a simple app with one screen containing a list. At the bottom of the screen, we display a Firebase AdMob ad.

To follow the code tutorial, create a new app as follows.

Create app flutter create firebaseadmobexample 1 flutter create firebaseadmobexample

If you’re unsure how to set up a Flutter app, check out Getting started with Flutter official tutorial.

Firstly, we create a Material app in main.dart, which will launch the ListPage widget.

main.dart import 'package:flutter/material.dart'; import 'list_page.dart'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return new MaterialApp( title: 'Firebase AdMob Example', theme: new ThemeData( primaryColor: const Color(0xFF43a047), accentColor: const Color(0xFFffcc00), primaryColorBrightness: Brightness.dark, ), home: new ListPage(), ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import 'package:flutter/material.dart' ; import 'list_page.dart' ; void main ( ) { runApp ( new MyApp ( ) ) ; } class MyApp extends StatelessWidget { // This widget is the root of your application. @ override Widget build ( BuildContext context ) { return new MaterialApp ( title : 'Firebase AdMob Example' , theme : new ThemeData ( primaryColor : const Color ( 0xFF43a047 ) , accentColor : const Color ( 0xFFffcc00 ) , primaryColorBrightness : Brightness . dark , ) , home : new ListPage ( ) , ) ; } }

Secondly, we create list_page.dart. This displays a list (with hardcoded items for this example).

list_page.dart import 'package:flutter/material.dart'; class ListPage extends StatefulWidget { ListPage({Key key}) : super(key: key); @override _ListPageState createState() => new _ListPageState(); } class _ListPageState extends State<ListPage> { List<Item> _items; @override void initState() { super.initState(); // TODO - this is shortcut to specify items. // In a real app, you would get them // from your data repository or similar. _items = new List<Item>(); _items.add(new Item("Apples")); _items.add(new Item("Oranges")); _items.add(new Item("Rosemary")); _items.add(new Item("Carrots")); _items.add(new Item("Potatoes")); _items.add(new Item("Mushrooms")); _items.add(new Item("Thyme")); _items.add(new Item("Tomatoes")); _items.add(new Item("Peppers")); _items.add(new Item("Salt")); _items.add(new Item("Ground ginger")); _items.add(new Item("Cucumber")); } @override Widget build(BuildContext context) { Widget itemsWidget = new ListView( scrollDirection: Axis.vertical, shrinkWrap: true, children: _items.map((Item item) { return _singleItemDisplay(item); }).toList()); return new Scaffold( appBar: new AppBar( title: new Text("List of items"), ), body: new Padding( padding: new EdgeInsets.symmetric(vertical: 0.0, horizontal: 4.0), child: itemsWidget, ), ); } Widget _singleItemDisplay(Item item) { return new ListTile( title: new Text(item.displayName), ); } } class Item { final String displayName; const Item(this.displayName); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 import 'package:flutter/material.dart' ; class ListPage extends StatefulWidget { ListPage ( { Key key } ) : super ( key : key ) ; @ override _ListPageState createState ( ) = > new _ListPageState ( ) ; } class _ListPageState extends State < ListPage > { List < Item > _items ; @ override void initState ( ) { super . initState ( ) ; // TODO - this is shortcut to specify items. // In a real app, you would get them // from your data repository or similar. _items = new List < Item > ( ) ; _items . add ( new Item ( "Apples" ) ) ; _items . add ( new Item ( "Oranges" ) ) ; _items . add ( new Item ( "Rosemary" ) ) ; _items . add ( new Item ( "Carrots" ) ) ; _items . add ( new Item ( "Potatoes" ) ) ; _items . add ( new Item ( "Mushrooms" ) ) ; _items . add ( new Item ( "Thyme" ) ) ; _items . add ( new Item ( "Tomatoes" ) ) ; _items . add ( new Item ( "Peppers" ) ) ; _items . add ( new Item ( "Salt" ) ) ; _items . add ( new Item ( "Ground ginger" ) ) ; _items . add ( new Item ( "Cucumber" ) ) ; } @ override Widget build ( BuildContext context ) { Widget itemsWidget = new ListView ( scrollDirection : Axis . vertical , shrinkWrap : true , children : _items . map ( ( Item item ) { return _singleItemDisplay ( item ) ; } ) . toList ( ) ) ; return new Scaffold ( appBar : new AppBar ( title : new Text ( "List of items" ) , ) , body : new Padding ( padding : new EdgeInsets . symmetric ( vertical : 0.0 , horizontal : 4.0 ) , child : itemsWidget , ) , ) ; } Widget _singleItemDisplay ( Item item ) { return new ListTile ( title : new Text ( item . displayName ) , ) ; } } class Item { final String displayName ; const Item ( this . displayName ) ; }

Thirdly, we need to amend pubspec.yaml to include the plugin.

pubspec.yaml dependencies: flutter: sdk: flutter firebase_admob: 0.3.0 1 2 3 4 dependencies : flutter : sdk : flutter firebase_admob : 0.3.0

Don’t forget to check the plugin page for the latest version number, and make sure you run flutter packages upgrade .

Note: the plugin needs Gradle plugin 4.1. So if you’re on a previous version, make sure you follow those steps to upgrade. If you don’t, you will see the following error message A problem occurred evaluating project ':firebase_admob'. > Could not find method google() for arguments [] on repository container. .

Finally, you will need to set up Firebase in iOS and/or Android as required. Check out the official Firebase for Flutter codelab: step 5 – set up Firebase integration, but ignore the changes to pubspec.yaml (we’ve done the required changes in the step above).

Looking for a Flutter job? Check out my job board dedicated to Flutter at flutterjobs.info

Set up Firebase AdMob

There are 5 steps:

Show a banner ad

To show a banner ad using the plugin, we first need to initialise the plugin with the app id. Then we ask the plugin to create, load and show the banner ad. We do this in ListPage as below.

list_page.dart import 'package:flutter/material.dart'; import 'package:firebase_admob/firebase_admob.dart'; const String AD_MOB_APP_ID = 'app_id'; const String AD_MOB_TEST_DEVICE = 'test_device_id - run ad then check device logs for value'; const String AD_MOB_AD_ID = 'ad unit ad'; [...] class _ListPageState extends State<ListPage> { List<Item> _items; BannerAd _bannerAd; static final MobileAdTargetingInfo targetingInfo = new MobileAdTargetingInfo( testDevices: <String>[AD_MOB_TEST_DEVICE], ); BannerAd createBannerAd() { return new BannerAd( adUnitId: AD_MOB_AD_ID, targetingInfo: targetingInfo, ); } @override void initState() { super.initState(); [...] FirebaseAdMob.instance.initialize(appId: AD_MOB_APP_ID); _bannerAd = createBannerAd()..load()..show(); } @override void dispose() { _bannerAd?.dispose(); super.dispose(); } [...] } [...] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import 'package:flutter/material.dart' ; import 'package:firebase_admob/firebase_admob.dart' ; const String AD_MOB_APP_ID = 'app_id' ; const String AD_MOB_TEST_DEVICE = 'test_device_id - run ad then check device logs for value' ; const String AD_MOB_AD_ID = 'ad unit ad' ; [ . . . ] class _ListPageState extends State < ListPage > { List < Item > _items ; BannerAd _bannerAd ; static final MobileAdTargetingInfo targetingInfo = new MobileAdTargetingInfo ( testDevices : < String > [ AD_MOB_TEST_DEVICE ] , ) ; BannerAd createBannerAd ( ) { return new BannerAd ( adUnitId : AD_MOB_AD_ID , targetingInfo : targetingInfo , ) ; } @ override void initState ( ) { super . initState ( ) ; [ . . . ] FirebaseAdMob . instance . initialize ( appId : AD_MOB_APP_ID ) ; _bannerAd = createBannerAd ( ) . . load ( ) . . show ( ) ; } @ override void dispose ( ) { _bannerAd ? . dispose ( ) ; super . dispose ( ) ; } [ . . . ] } [ . . . ]

Let’s run the app… List showing… Ad loading and showing… Oh oh, there is a problem. The bottom of the list is hidden behind the ad!

Likewise, if you try to show a snackbar, it is hidden behind the ad.

Make sure the banner doesn’t hide the bottom of the screen

Looking at the documentation, Scaffold comes with an option for persistentFooterButtons. So let’s use this, by amending ListPage as below.

list_page.dart @override Widget build(BuildContext context) { Widget itemsWidget = new ListView( scrollDirection: Axis.vertical, shrinkWrap: true, children: _items.map((Item item) { return _singleItemDisplay(item); }).toList()); List<Widget> fakeBottomButtons = new List<Widget>(); fakeBottomButtons.add(new Container( height: 50.0, )); return new Scaffold( appBar: new AppBar( title: new Text("List of items"), ), body: new Padding( padding: new EdgeInsets.symmetric(vertical: 0.0, horizontal: 4.0), child: itemsWidget, ), persistentFooterButtons: fakeBottomButtons, ); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @ override Widget build ( BuildContext context ) { Widget itemsWidget = new ListView ( scrollDirection : Axis . vertical , shrinkWrap : true , children : _items . map ( ( Item item ) { return _singleItemDisplay ( item ) ; } ) . toList ( ) ) ; List < Widget > fakeBottomButtons = new List < Widget > ( ) ; fakeBottomButtons . add ( new Container ( height : 50.0 , ) ) ; return new Scaffold ( appBar : new AppBar ( title : new Text ( "List of items" ) , ) , body : new Padding ( padding : new EdgeInsets . symmetric ( vertical : 0.0 , horizontal : 4.0 ) , child : itemsWidget , ) , persistentFooterButtons : fakeBottomButtons , ) ; }

If we run the app again, you will see a new divider a few pixels above the top of the ad. The value is determined by the height of the Container used for fakeBottomButtons. You may want to play around with that height, but I recommend a value close to 50.0; this will ensure the ad isn’t tapped on because it is too close to a list element. This divider is essentially the bottom of the screen as far as the list is concerned.

However, if we have no ad to show (eg no network connection), the screen looks silly with this divider. So we need to add some logic to work out if an ad is shown, and only add fakeBottomButtons if it is.

list_page.dart [...] BannerAd _bannerAd; bool _adShown; static final MobileAdTargetingInfo targetingInfo = new MobileAdTargetingInfo( testDevices: <String>[AD_MOB_TEST_DEVICE], ); BannerAd createBannerAd() { return new BannerAd( adUnitId: AD_MOB_AD_ID, targetingInfo: targetingInfo, listener: (MobileAdEvent event) { if (event == MobileAdEvent.loaded) { _adShown = true; setState((){ }); } else if (event == MobileAdEvent.failedToLoad) { _adShown = false; setState((){ }); } }, ); } @override void initState() { super.initState(); [...] FirebaseAdMob.instance.initialize(appId: AD_MOB_APP_ID); _adShown = false; _bannerAd = createBannerAd()..load()..show(); } [...] @override Widget build(BuildContext context) { [...] return new Scaffold( appBar: new AppBar( title: new Text("List of items"), ), body: new Padding( padding: new EdgeInsets.symmetric(vertical: 0.0, horizontal: 4.0), child: itemsWidget, ), persistentFooterButtons: _adShown? fakeBottomButtons:null, ); } [...] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 [ . . . ] BannerAd _bannerAd ; bool _adShown ; static final MobileAdTargetingInfo targetingInfo = new MobileAdTargetingInfo ( testDevices : < String > [ AD_MOB_TEST_DEVICE ] , ) ; BannerAd createBannerAd ( ) { return new BannerAd ( adUnitId : AD_MOB_AD_ID , targetingInfo : targetingInfo , listener : ( MobileAdEvent event ) { if ( event == MobileAdEvent . loaded ) { _adShown = true ; setState ( ( ) { } ) ; } else if ( event == MobileAdEvent . failedToLoad ) { _adShown = false ; setState ( ( ) { } ) ; } } , ) ; } @ override void initState ( ) { super . initState ( ) ; [ . . . ] FirebaseAdMob . instance . initialize ( appId : AD_MOB_APP_ID ) ; _adShown = false ; _bannerAd = createBannerAd ( ) . . load ( ) . . show ( ) ; } [ . . . ] @ override Widget build ( BuildContext context ) { [ . . . ] return new Scaffold ( appBar : new AppBar ( title : new Text ( "List of items" ) , ) , body : new Padding ( padding : new EdgeInsets . symmetric ( vertical : 0.0 , horizontal : 4.0 ) , child : itemsWidget , ) , persistentFooterButtons : _adShown ? fakeBottomButtons : null , ) ; } [ . . . ]

Voila!

What next?

The firebase_admob plugin is still under development. For example, support for rewarded video ads was added last week. Therefore, keep an eye on it for further improvements.

Related