4

This article is for those who have difficulty migrating from the firebase_admob plugin to google_mobile_ads. for convenience I will abbreviate the name firebase_admob as FA, and google_mobile_ads as GMA.

As we know that the FA plugin has been discontinued and replaced with the GMA plugin. One of the advantages of FA over GMA is, the FA banners will appear all over the page without having to rewrite code on other pages. However in GMA, the banner only appear on the page containing GMA code.

There are many disadvantages of GMA compared to FA, including:

  • the app blingking when switching pages
  • every page always initialize banner and this causes high performance
  • each page must be assigned a GMA code

Then how can we implement GMA in our app so that problem does not occur? the way is very easy, which is to become a page as a tab. and this is just a way to show banner ads at the bottom (bottomNavigation). not rewarded or interstitial ad. Check out my method below..

My pages:

  • main.dart
  • home_tab.dart
  • home_page.dart (is First Tab)
  • page two.dart
  • page three.dart

I will display all banners on the page above.

on pubspec.yaml

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  google_mobile_ads: ^1.0.1

on android\app\build.gradle

...
apply plugin: 'com.google.gms.google-services'

...
android {
    compileSdkVersion 32
...

...
defaultConfig {
...
        minSdkVersion 21
        targetSdkVersion 32
...
        multiDexEnabled true
    }
...

dependencies {
...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation platform('com.google.firebase:firebase-bom:29.0.4')
    implementation 'com.google.firebase:firebase-analytics'
    implementation 'com.android.support:multidex:1.0.3'
...
}

on ...\android\gradle\wrapper\gradle-wrapper.properties change to gradle 7.0.2

..
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
..

on ...\android\build.gradle change Kotlin version to 1.6.10 and gradle build to 7.0.0 like the following code:

buildscript {
     ext.kotlin_version = '1.6.10'
     repositories {
         google()
         mavenCentral()
     }

     dependencies {
         classpath 'com.android.tools.build:gradle:7.0.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
         classpath 'com.google.gms:google-services:4.3.10'
         classpath 'com.android.support:multidex:1.0.3'
     }
}

allprojects {
     repositories {
         google()
         mavenCentral()
     }
}

rootProject.buildDir = '../build'
subprojects {
     project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
     project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
     delete rootProject.buildDir
}

main.dart

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // await MobileAds.instance.initialize(); //uncomment this code if release
  await MobileAds.instance.initialize().then((InitializationStatus status) {
    MobileAds.instance.updateRequestConfiguration(
      RequestConfiguration(testDeviceIds: <String>[
        '0819A79F3F94F37FBABD456D6CF92101', // this is test device id, u can view on console
      ]),
    );
  }); // delete this code if release

  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomeTab(),
    );
  }
}

home_tab.dart

class HomeTab extends StatefulWidget {
  const HomeTab({Key key}) : super(key: key);

  static const String routeName = '/HomeTab';

  @override
  State<StatefulWidget> createState() => HomeTabState();
}

class HomeTabState extends State<HomeTab> {
  static int currentTab = 0;
  final List<HomeTabItem> tabs = [
    HomeTabItem(
      page: const HomePage(),
    ),
  ];

  HomeTabState() {
    tabs.asMap().forEach((index, details) {
      details.setIndex(index);
    });
  }

  void _selectTab(int index) {
    if (index == currentTab) {
      tabs[index].key.currentState.popUntil((route) => route.isFirst);
    } else {
      setState(() => currentTab = index);
    }
  }

  // IKLAN
  BannerAd myBanner;
  bool adShow = false;

  Future<void> _loadAd() async {
    final AnchoredAdaptiveBannerAdSize size = await AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(MediaQuery.of(context).size.width.truncate());
    if (size == null) {
      return;
    }
    myBanner = BannerAd(
      adUnitId: 'your banner unit id',
      size: size,
      request: const AdRequest(
        extras: {'rdp': '1'},
      ),
      listener: BannerAdListener(
        onAdLoaded: (Ad ad) {
          setState(() {
            myBanner = ad as BannerAd;
            adShow = true;
          });
        },
        onAdFailedToLoad: (Ad ad, LoadAdError error) {
          ad.dispose();
          adShow = false;
        },
      ),
    );
    return myBanner.load();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _loadAd();
  }

  @override
  void initState() {
    myBanner;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab = !await tabs[currentTab].key.currentState.maybePop();
        if (isFirstRouteInCurrentTab) {
          if (currentTab != 0) {
            _selectTab(0);
            return false;
          }
        }
        return isFirstRouteInCurrentTab;
      },
      child: Scaffold(
        body: IndexedStack(
          index: currentTab,
          children: tabs.map((e) => e.page).toList(),
        ),
        bottomNavigationBar: adShow == true
            ? SizedBox(
                width: myBanner.size.width.toDouble(),
                height: myBanner.size.height.toDouble(),
                child: AdWidget(ad: myBanner),
              )
            : const SizedBox.shrink(),
      ),
    );
  }
}

class HomeTabItem {
  final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
  int _index = 0;
  Widget _page;
  HomeTabItem({
    @required Widget page,
  }) {
    _page = page;
  }

  void setIndex(int i) {
    _index = i;
  }

  int getIndex() => _index;

  Widget get page {
    return Visibility(
      visible: _index == HomeTabState.currentTab,
      maintainState: true,
      child: Navigator(
        key: key,
        onGenerateRoute: (routeSettings) {
          return MaterialPageRoute(
            builder: (_) => _page,
          );
        },
      ),
    );
  }
}

we make HomePage as first Tab home_page.dart

// HomePage is FIRST TAB
class HomePage extends StatefulWidget {
  const HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    // we wrap the Scaffold with Willpopscope so that when we are on the main page an exit dialog will appear
    return WillPopScope(
      onWillPop: () {
        return showDialog(
          barrierColor: Colors.transparent,
          context: context,
          builder: (BuildContext context) => AlertDialog(
            title: const Text(
              "Exit App?",
              textAlign: TextAlign.center,
            ),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    ElevatedButton(
                      onPressed: () {
                        SystemNavigator.pop();
                      },
                      child: const Text("Yes"),
                    ),
                    ElevatedButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: const Text("No"),
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      },
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Home Page'),
          titleSpacing: 0,
        ),
        drawer: Drawer(),
        body: SingleChildScrollView(
          child: Column(
            children: [
              Container(
                height: 200,
                color: Colors.grey,
                child: const Center(
                  child: Text(
                    'this is\nHome Page',
                    textAlign: TextAlign.center,
                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.white),
                  ),
                ),
              ),
              //
              SizedBox(height: 20),
              //
              ElevatedButton(
                child: const Text('Go to Page Two'),
                onPressed: () {
                  Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => const PageTwo()));
                },
              ),
              ElevatedButton(
                child: const Text('Go to Page Three'),
                onPressed: () {
                  Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => const PageThree()));
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

page_two.dart

class PageTwo extends StatefulWidget {
  const PageTwo({Key key}) : super(key: key);

  @override
  _PageTwoState createState() => _PageTwoState();
}

class _PageTwoState extends State<PageTwo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Page Two'),
        titleSpacing: 0,
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Container(
              height: 200,
              color: Colors.grey,
              child: const Center(
                child: Text(
                  'this is\nPage TWO',
                  textAlign: TextAlign.center,
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.white),
                ),
              ),
            ),
            //
            SizedBox(height: 20),
            //

            ElevatedButton(
              child: const Text('Go to Page Three'),
              onPressed: () {
                Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => const PageThree()));
              },
            ),
            //
            ElevatedButton(
              child: const Text('Go to Home Page'),
              onPressed: () {
                Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => const HomePage()));
              },
            ),
          ],
        ),
      ),
    );
  }
}

page_three.dart

class PageThree extends StatefulWidget {
  const PageThree({Key key}) : super(key: key);

  @override
  _PageThreeState createState() => _PageThreeState();
}

class _PageThreeState extends State<PageThree> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Page Three'),
        titleSpacing: 0,
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Container(
              height: 200,
              color: Colors.grey,
              child: const Center(
                child: Text(
                  'this is\nPage THREE',
                  textAlign: TextAlign.center,
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.white),
                ),
              ),
            ),
            //
            SizedBox(height: 20),
            //

            ElevatedButton(
              child: const Text('Go to Page TWO'),
              onPressed: () {
                Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => const PageTwo()));
              },
            ),
          ],
        ),
      ),
    );
  }
}

Thus the article on how to display the google_mobile_ads banner ad at the bottom of the page. I am very happy for the correction of all friends. I hope this article helps your problem. Have a nice day

Ary Anzh
  • 406
  • 3
  • 15
  • 1
    Awesome. I was struggling a few days with admob_flutter: ^2.0.0. It didn't show ads on Android, only on IOS, and now I followed this small tutorial and works like a charm. There's one thing that I didn't do that is to upgrade gradle. I went with: classpath 'com.android.tools.build:gradle:4.1.0' – Rodrigo Augusto Silva dos Sant Feb 18 '22 at 23:36

0 Answers0