Adding an AdMob banner and native inline ads to a Flutter app

1. Introduction

In this codelab, you implement an AdMob banner and an AdMob native inline ad in a Flutter app.

What you'll build

This codelab guides you through implementing an AdMob inline banner and AdMob native inline ads in a Flutter app using the Google Mobile Ads plugin for Flutter.

If you have any issues (code bugs, grammatical errors, unclear wording, and so on) as you work through this codelab, report the issue using the Report a mistake link in the lower, left corner of the codelab.

What you'll learn

  • How to configure the Google Mobile Ads Flutter plugin
  • How to implement an inline banner and rewarded ads in a Flutter app

What you'll need

  • Android Studio 4.1 or later
  • Xcode 12 or later (for iOS development)

How would you rate your level of experience with AdMob?

Novice Intermediate Proficient

How would you rate your level of experience with Flutter?

Novice Intermediate Proficient

2. Set up your Flutter development environment

You need two pieces of software to complete this lab—the Flutter SDK and an editor.

You can run the codelab using any of these devices:

  • A physical Android or iOS device connected to your computer and set to Developer mode.
  • The iOS simulator (requires installing Xcode tools).
  • The Android Emulator (requires setup in Android Studio).
  • A browser (Chrome is required for debugging).
  • As a Windows, Linux, or macOS desktop application. You must develop on the platform where you plan to deploy. So, if you want to develop a Windows desktop app, you must develop on Windows to access the appropriate build chain. There are operating system-specific requirements that are covered in detail on docs.flutter.dev/desktop.

Download the code

After you download the zip file, extract its contents. You will have a folder named admob-inline-ads-in-flutter-main.

Alternatively, you can clone the GitHub repository from the command line:

$ git clone https://github.com/googlecodelabs/admob-inline-ads-in-flutter

The repository contains three folders:

  • android_studio_folder.png starter: Starting code that you will build in this codelab.
  • android_studio_folder.png complete: Completed code for this codelab. (Java & Objective-C for native code)
  • android_studio_folder.png complete_kotlin_swift: Completed code for this codelab. (Kotlin & Swift for native code)

3. Set up AdMob app and ad units

Because Flutter is a multi-platform SDK, you need to add an app and ad units for both Android and iOS in AdMob.

Set up for Android

To set up for Android, you need to add an Android app and create ad units.

Add an Android app

  1. In the AdMob console, click ADD APP from the Apps menu.
  2. When you're asked Have you published your app on Google Play or the App Store?, click NO.
  3. Enter AdMob inline ads in the app name field, and select Android as the platform.

d51828db0e2e4f6c.png

  1. Enabling user metrics is not necessary to complete this codelab. However, we recommend that you do because it allows you to understand user behavior in more detail. Click ADD to complete the process.

b918bf44362813a9.png

Create ad units

To add ad units:

  1. Select AdMob inline ads app from Apps menu in the AdMob console.
  2. Click the Ad units menu.

Banner

  1. Click ADD AD UNIT.
  2. Select Banner as the format.
  3. Enter android-inline-banner in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

Native

  1. Click ADD AD UNIT.
  2. Select Native advanced as the format.
  3. Enter android-inline-native in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

It usually takes a few hours for a new ad unit to be able to serve ads.

If you want to test the ad's behavior immediately, then use the test app ID and ad unit IDs listed in the Android app ID/ad unit ID and iOS app ID/ad unit ID tables.

Set up for iOS

To set up for iOS, you need to add an iOS app and create ad units.

Add an iOS app

  1. In the AdMob console, click ADD APP from the Apps menu.
  2. When you're asked Have you published your app on Google Play or the App Store?, click NO.
  3. Enter AdMob inline ads in the app name field, and select iOS as the platform.

a4c963c9aa09519.png

  1. Enabling user metrics is not necessary to complete this codelab. However, we recommend that you do because it allows you to understand user behavior in more detail. Click ADD to complete the process.

b918bf44362813a9.png

Create ad units

To add ad units:

  1. Select AdMob inline ads app from Apps menu in the AdMob console.
  2. Click the Ad units menu.

Banner

  1. Click ADD AD UNIT.
  2. Select Banner as the format.
  3. Enter ios-inline-banner in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

Native

  1. Click ADD AD UNIT.
  2. Select Native advanced as the format.
  3. Enter ios-inline-native in the Ad unit name field.
  4. Click CREATE AD UNIT to complete the process.

It usually takes a few hours for a new ad unit to be able to serve ads.

If you want to test the ad's behavior immediately, then use the test app ID and ad unit IDs listed in the following table.

Optional: Use the test AdMob app and ad units

If you want to follow the codelab instead of creating a new application and ad units on your own, you can use the test AdMob app ID and ad unit IDs listed in the following tables.

Android app ID/ad unit ID

Item

app ID/ad unit ID

AdMob app ID

ca-app-pub-3940256099942544~3347511713

Banner

ca-app-pub-3940256099942544/6300978111

Native

ca-app-pub-3940256099942544/2247696110

iOS app ID/ad unit ID

Item

app ID/ad unit ID

AdMob app ID

ca-app-pub-3940256099942544~1458002511

Banner

ca-app-pub-3940256099942544/2934735716

Native

ca-app-pub-3940256099942544/3986624511

For more information about the test ads, see the Android test ads and the iOS test ads developer documentation.

4. Add the Google Mobile Ads Flutter plugin

Flutter uses plugins to provide access to a wide range of platform-specific services. Plugins enable you to access services and APIs on each platform.

The google_mobile_ads plugin supports loading and displaying banner, interstitial, rewarded, and native ads using the AdMob API.

Because Flutter is a multi-platform SDK, the google_mobile_ads plugin is applicable for both iOS and Android. So, if you add the plugin to your Flutter app, it's used by both Android and iOS versions of the AdMob inline ads app.

Add the Google Mobile Ads plugin as a dependency

To access the AdMob APIs from the AdMob inline ads project, add google_mobile_ads as a dependency to the pubspec.yaml file located at the root of the project.

pubspec.yaml

...
dependencies:
  flutter:
    sdk: flutter
  google_fonts: ^0.3.9

  # TODO: Add google_mobile_ads as a dependency
  google_mobile_ads: ^1.2.0

...

Click Pub get to install the plugin in the AdMob inline ads project.

93ef6061e58ebc86.png

Update AndroidManifest.xml (Android)

  1. Open the android/app/src/main/AndroidManifest.xml file in Android Studio.
  2. Add your AdMob app ID by adding a <meta-data> tag with the name com.google.android.gms.ads.APPLICATION_ID. For example, if your AdMob app ID is ca-app-pub-3940256099942544~3347511713, then you need to add the following lines to the AndroidManifest.xml file.

AndroidManifest.xml

<manifest>
    ...
    <application>
       ...
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-3940256099942544~3347511713"/>
    </application>

</manifest>

Update Info.plist (iOS)

  1. Open the ios/Runner/Info.plist file in Android Studio.
  2. Add a GADApplicationIdentifier key with the string value of your AdMob app ID. For example, if your AdMob app ID is ca-app-pub-3940256099942544~1458002511, then you need to add the following lines to the Info.plist file.

ios/Runner/Info.plist

...
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
...

5. Add a helper class for ads

Create a new file named ad_helper.dart under the lib directory. Then, implement the AdHelper class, which provides an AdMob app ID and ad unit IDs for Android and iOS.

Make sure that you replace the AdMob app ID (ca-app-pub-xxxxxx~yyyyy) and the ad unit ID (ca-app-pub-xxxxxxx/yyyyyyyy) with the IDs you created in the previous step.

ad_helper.dart

import 'dart:io';

class AdHelper {

  static String get bannerAdUnitId {
    if (Platform.isAndroid) {
      return "<YOUR_ANDROID_BANNER_AD_UNIT_ID";
    } else if (Platform.isIOS) {
      return "<YOUR_IOS_BANNER_AD_UNIT_ID>";
    } else {
      throw UnsupportedError("Unsupported platform");
    }
  }

  static String get nativeAdUnitId {
    if (Platform.isAndroid) {
      return "<YOUR_ANDROID_NATIVE_AD_UNIT_ID>";
    } else if (Platform.isIOS) {
      return "<YOUR_IOS_NATIVE_AD_UNIT_ID>";
    } else {
      throw UnsupportedError("Unsupported platform");
    }
  }
}

Use the following code snippet if you want to use the test AdMob app ID and test ad unit IDs.

ad_helper.dart

import 'dart:io';

class AdHelper {
  
  static String get bannerAdUnitId {
    if (Platform.isAndroid) {
      return 'ca-app-pub-3940256099942544/6300978111';
    } else if (Platform.isIOS) {
      return 'ca-app-pub-3940256099942544/2934735716';
    }
    throw UnsupportedError("Unsupported platform");
  }

  static String get nativeAdUnitId {
    if (Platform.isAndroid) {
      return 'ca-app-pub-3940256099942544/2247696110';
    } else if (Platform.isIOS) {
      return 'ca-app-pub-3940256099942544/3986624511';
    }
    throw UnsupportedError("Unsupported platform");
  }
}

6. Initialize the Google Mobile Ads SDK

Before loading ads, you need to initialize the Google Mobile Ads SDK. Open the lib/home_page.dart file, and modify _initGoogleMobileAds() to initialize the SDK before the home page is loaded.

Note that you need to change the return type of the _initGoogleMobileAds() method from Future<dynamic> to Future<InitializationStatus> to get the SDK initialization result after it completes.

home_page.dart

// TODO: Import google_mobile_ads.dart
import 'package:google_mobile_ads/google_mobile_ads.dart';

import 'package:flutter/material.dart';

...

class HomePage extends StatelessWidget {

  ...

  Future<InitializationStatus> _initGoogleMobileAds() {
    // TODO: Initialize Google Mobile Ads SDK
    return MobileAds.instance.initialize();
  }
}

7. Add a banner ad

In this section, you display a banner ad in the middle of the list, as shown in the following screenshot.

62c405c962909fd3.png

  1. Open the lib/banner_inline_page.dart file.
  2. Import ad_helper.dart and google_mobile_ads.dart by adding the following lines:
...

// TODO: Import ad_helper.dart
import 'package:admob_inline_ads_in_flutter/ad_helper.dart';

// TODO: Import google_mobile_ads.dart
import 'package:google_mobile_ads/google_mobile_ads.dart';

class BannerInlinePage extends StatefulWidget {
  ...
}
  1. In the _BannerInlinePageState class, add the following members and methods for a banner ad.

Note that _kAdIndex indicates the index where a banner ad will be displayed, and it's used to calculate the item index from the _getDestinationItemIndex() method.

banner_inline_page.dart

class _BannerInlinePageState extends State<BannerInlinePage> {

  // TODO: Add _kAdIndex
  static final _kAdIndex = 4;

  // TODO: Add a banner ad instance
  BannerAd? _ad;

  ...

  // TODO: Add _getDestinationItemIndex()
  int _getDestinationItemIndex(int rawIndex) {
    if (rawIndex >= _kAdIndex && _ad != null) {
      return rawIndex - 1;
    }
    return rawIndex;
  }

  ...
}
  1. In the initState() method, create and load a BannerAd for the 320x50 banner (AdSize.banner). Note that an ad event listener is configured to update the UI (setState()) when an ad is loaded.

banner_inline_page.dart

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

  // TODO: Load a banner ad
  BannerAd(
    adUnitId: AdHelper.bannerAdUnitId,
    size: AdSize.banner,
    request: AdRequest(),
    listener: BannerAdListener(
      onAdLoaded: (ad) {
        setState(() {
          _ad = ad as BannerAd;
        });
      },
      onAdFailedToLoad: (ad, error) {
        // Releases an ad resource when it fails to load
        ad.dispose();
        print('Ad load failed (code=${error.code} message=${error.message})');
      },
    ),
  ).load();
}
  1. Modify the build() method to display a banner ad when available.
  2. Update itemCount, to count a banner ad entry, and update itemBuilder, to render a banner ad at the ad index (_kAdIndex) when the ad is loaded.
  3. Update the code to use the _getDestinationItemIndex() method to retrieve an index for the content item.

banner_inline_page.dart

@override
Widget build(BuildContext context) {
  return Scaffold(
    ...
    body: ListView.builder(
      // TODO: Adjust itemCount based on the ad load state
      itemCount: widget.entries.length + (_ad != null ? 1 : 0),
      itemBuilder: (context, index) {
        // TODO: Render a banner ad
        if (_ad != null && index == _kAdIndex) {
          return Container(
            width: _ad!.size.width.toDouble(),
            height: 72.0,
            alignment: Alignment.center,
            child: AdWidget(ad: _ad!),
          );
        } else {
          // TODO: Get adjusted item index from _getDestinationItemIndex()
          final item = widget.entries[_getDestinationItemIndex(index)];

          return ListTile(
            ...
          );
        }
      },
    ),
  );
}
  1. Release the resource associated with the BannerAd object by calling the BannerAd.dispose() method in the dispose() callback method.

banner_inline_page.dart

@override
void dispose() {
  // TODO: Dispose a BannerAd object
  _ad?.dispose();

  super.dispose();
}

That's it! Run the project, and click the Banner inline ad button from the home page. After an ad is loaded, you'll see a banner ad in the middle of the list.

a5f857a850539fe9.png c32af50872514224.png

8. Add a native ad

In this section, you display a native ad in the middle of the list, as shown in the following screenshot.

f1671b0fa349ccf8.png

Native ads are presented to users using UI components that are native to the platform (for example, View on Android or UIView on iOS).

However, it isn't possible to create native UI components directly by using Flutter widgets. So, you have to implement a NativeAdFactory for each platform, which is used to build a platform-specific native ad view (NativeAdView on Android and GADNativeAdView on iOS) from a native ad object (NativeAd on Android and GADNativeAd on iOS).

Implement NativeAdFactory for Android (Java)

  1. Open the android/build.gradle file (or any file under the android folder), and click Open for Editing in Android Studio to open an Android project.

623ad3d2282ccbf8.png

  1. If you're asked to select a window to open a new project, click New Window to make the Flutter project remain open while you're working on the Android project.

d188bb51cf7c2d08.png

Create a native ad layout

  1. With the Android project opened, right-click app from the project pane in Android Studio, and select New > Android Resource File from the context menu.

2b629ee277a68fd7.png

  1. In the New Resource File dialog, enter list_tile_native_ad.xml as the file name.
  2. Select Layout as the resource type, and enter com.google.android.gms.ads.nativead.NativeAdView as a root element.
  3. Click OK to create a new layout file.

575f126dd018bc0.png

  1. Implement the ad layout as follows. Note that the layout should match the visual design of the user experience for the platform it's intended for.

list_tile_native_ad.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_small"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#F19938"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:textSize="12sp" />

        <ImageView
            android:id="@+id/iv_list_tile_native_ad_icon"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:scaleType="fitXY"
            tools:background="#EDEDED" />

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_large"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:background="#F19938"
            android:gravity="center"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:visibility="invisible" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="80dp"
            android:layout_marginLeft="80dp"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_list_tile_native_ad_headline"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#000000"
                android:textSize="16sp"
                tools:text="Headline" />

            <TextView
                android:id="@+id/tv_list_tile_native_ad_body"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#828282"
                android:textSize="14sp"
                tools:text="body" />

        </LinearLayout>

    </FrameLayout>

</com.google.android.gms.ads.nativead.NativeAdView>

Create the ListTileNativeAdFactory class

  1. In the Project pane, right-click the com.codelab.flutter.admobinlineads package, and select New > Java Class.

9f3f111dd207a9b4.png

  1. Enter ListTileNativeAdFactory as the name, and select Class from the list.

47ff82d92676e26.png

  1. After the New Class dialog appears, leave everything empty, and click OK.

You'll see that the ListTileNativeAdFactory class is created in the package com.codelab.flutter.admobinlineads.

e4ed232c358ffb19.png

  1. Implement the ListTileNativeAdFactory class as follows. Note that the class implements the createNativeAd() method in the GoogleMobileAdsPlugin.NativeAdFactory interface.

The factory class is responsible for creating a view object for rendering a native ad. As you can see from the code, the factory class creates a UnifiedNativeAdView and populates it with a NativeAd object.

ListTileNativeAdFactory.java

// TODO: Implement ListTileNativeAdFactory class

package com.codelab.flutter.admobinlineads;

import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.Map;

import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;

class ListTileNativeAdFactory implements GoogleMobileAdsPlugin.NativeAdFactory {

    private final Context context;

    ListTileNativeAdFactory(Context context) {
        this.context = context;
    }

    @Override
    public NativeAdView createNativeAd(
            NativeAd nativeAd, Map<String, Object> customOptions) {
        NativeAdView nativeAdView = (NativeAdView) LayoutInflater.from(context)
                .inflate(R.layout.list_tile_native_ad, null);

        TextView attributionViewSmall = nativeAdView
                .findViewById(R.id.tv_list_tile_native_ad_attribution_small);
        TextView attributionViewLarge = nativeAdView
                .findViewById(R.id.tv_list_tile_native_ad_attribution_large);

        ImageView iconView = nativeAdView.findViewById(R.id.iv_list_tile_native_ad_icon);
        NativeAd.Image icon = nativeAd.getIcon();
        if (icon != null) {
            attributionViewSmall.setVisibility(View.VISIBLE);
            attributionViewLarge.setVisibility(View.INVISIBLE);
            iconView.setImageDrawable(icon.getDrawable());
        } else {
            attributionViewSmall.setVisibility(View.INVISIBLE);
            attributionViewLarge.setVisibility(View.VISIBLE);
        }
        nativeAdView.setIconView(iconView);

        TextView headlineView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_headline);
        headlineView.setText(nativeAd.getHeadline());
        nativeAdView.setHeadlineView(headlineView);

        TextView bodyView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_body);
        bodyView.setText(nativeAd.getBody());
        bodyView.setVisibility(nativeAd.getBody() != null ? View.VISIBLE : View.INVISIBLE);
        nativeAdView.setBodyView(bodyView);

        nativeAdView.setNativeAd(nativeAd);

        return nativeAdView;
    }
}

Register the ListTileNativeAdFactory class

An instance of a NativeAdFactory should be registered to the GoogleMobileAdsPlugin before it can be used from the Flutter side.

  1. Open the MainActivity.java file, and override the configureFlutterEngine() method and the cleanUpFlutterEngine() method.
  2. Register the ListTileNativeAdFactory class with a unique string ID (listTile) in the configureFlutterEngine() method.

MainActivity.java

public class MainActivity extends FlutterActivity {

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);

        // TODO: Register the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTile",
                new ListTileNativeAdFactory(getContext()));
    }

    ...
}
  1. Every NativeAdFactory instance should be unregistered during the cleanup process. Unregister the ListTileNativeAdFactory class in the cleanUpFlutterEngine() method.

MainActivity.java

public class MainActivity extends FlutterActivity {

    ...

    @Override
    public void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine);

        // TODO: Unregister the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile");
    }
}

Now you're ready to use the ListTileNativeAdFactory class to render native ads on Android.

Implement NativeAdFactory for Android (Kotlin)

  1. Open the android/build.gradle file (or any file under the android folder), and click Open for Editing in Android Studio to open an Android project.

623ad3d2282ccbf8.png

  1. If you're asked to select a window to open a new project, click New Window to make the Flutter project remain open while you're working on the Android project.

d188bb51cf7c2d08.png

Create a native ad layout

  1. With the Android project opened, right-click app from the project pane in Android Studio, and select New > Android Resource File from the context menu.

2b629ee277a68fd7.png

  1. In the New Resource File dialog, enter list_tile_native_ad.xml as the file name.
  2. Select Layout as the resource type, and enter com.google.android.gms.ads.nativead.NativeAdView as a root element.
  3. Click OK to create a new layout file.

575f126dd018bc0.png

  1. Implement the ad layout as follows. Note that the layout should match the visual design of the user experience for the platform it's intended for.

list_tile_native_ad.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_small"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#F19938"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:textSize="12sp" />

        <ImageView
            android:id="@+id/iv_list_tile_native_ad_icon"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:scaleType="fitXY"
            tools:background="#EDEDED" />

        <TextView
            android:id="@+id/tv_list_tile_native_ad_attribution_large"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:background="#F19938"
            android:gravity="center"
            android:text="Ad"
            android:textColor="#FFFFFF"
            android:visibility="invisible" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="80dp"
            android:layout_marginLeft="80dp"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_list_tile_native_ad_headline"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#000000"
                android:textSize="16sp"
                tools:text="Headline" />

            <TextView
                android:id="@+id/tv_list_tile_native_ad_body"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:lines="1"
                android:maxLines="1"
                android:textColor="#828282"
                android:textSize="14sp"
                tools:text="body" />

        </LinearLayout>

    </FrameLayout>

</com.google.android.gms.ads.nativead.NativeAdView>

Create the ListTileNativeAdFactory class

  1. In the Project pane, right-click the com.codelab.flutter.admobinlineads package, and select New > Kotlin File/Class.

7311744cb97cad75.png

  1. Enter ListTileNativeAdFactory as the name, and select Class from the list.

25691151b5814867.png

  1. You'll see that the ListTileNativeAdFactory class is created in the package com.codelab.flutter.admobinlineads.
  2. Implement the ListTileNativeAdFactory class as follows. Note that the class implements the createNativeAd() method in the GoogleMobileAdsPlugin.NativeAdFactory interface.

The factory class is responsible for creating a view object for rendering a native ad. As you can see from the code, the factory class creates a NativeAdView and populates it with a NativeAd object.

ListTileNativeAdFactory.kt

// TODO: Implement ListTileNativeAdFactory class

package com.codelab.flutter.admobinlineads

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdView
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin

class ListTileNativeAdFactory(val context: Context) : GoogleMobileAdsPlugin.NativeAdFactory {

    override fun createNativeAd(
            nativeAd: NativeAd,
            customOptions: MutableMap<String, Any>?
    ): NativeAdView {
        val nativeAdView = LayoutInflater.from(context)
                .inflate(R.layout.list_tile_native_ad, null) as NativeAdView

        with(nativeAdView) {
            val attributionViewSmall =
                    findViewById<TextView>(R.id.tv_list_tile_native_ad_attribution_small)
            val attributionViewLarge =
                    findViewById<TextView>(R.id.tv_list_tile_native_ad_attribution_large)

            val iconView = findViewById<ImageView>(R.id.iv_list_tile_native_ad_icon)
            val icon = nativeAd.icon
            if (icon != null) {
                attributionViewSmall.visibility = View.VISIBLE
                attributionViewLarge.visibility = View.INVISIBLE
                iconView.setImageDrawable(icon.drawable)
            } else {
                attributionViewSmall.visibility = View.INVISIBLE
                attributionViewLarge.visibility = View.VISIBLE
            }
            this.iconView = iconView

            val headlineView = findViewById<TextView>(R.id.tv_list_tile_native_ad_headline)
            headlineView.text = nativeAd.headline
            this.headlineView = headlineView

            val bodyView = findViewById<TextView>(R.id.tv_list_tile_native_ad_body)
            with(bodyView) {
                text = nativeAd.body
                visibility = if (nativeAd.body.isNotEmpty()) View.VISIBLE else View.INVISIBLE
            }
            this.bodyView = bodyView

            setNativeAd(nativeAd)
        }

        return nativeAdView
    }
}

Register the ListTileNativeAdFactory class

An instance of a NativeAdFactory should be registered to the GoogleMobileAdsPlugin before it can be used from the Flutter side.

  1. Open the MainActivity.kt file, and override the configureFlutterEngine() method and the cleanUpFlutterEngine() method.
  2. Register the ListTileNativeAdFactory class with a unique string ID (listTile) in the configureFlutterEngine() method.

MainActivity.kt

class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        // TODO: Register the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.registerNativeAdFactory(
                flutterEngine, "listTile", ListTileNativeAdFactory(context))
    }

    ...
}
  1. Every NativeAdFactory instance should be unregistered during the cleanup process. Unregister the ListTileNativeAdFactory class in the cleanUpFlutterEngine() method.

MainActivity.kt

class MainActivity: FlutterActivity() {
    ...

    override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine)

        // TODO: Unregister the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile")
    }
}

Now you're ready to use the ListTileNativeAdFactory class to render native ads on Android.

Implement NativeAdFactory for iOS (Objective-C)

Open the ios/Podfile file (or any file under the ios folder), and click Open iOS module in Xcode to open an iOS project.

62aa12c10e6d671f.png

Prepare a native ad layout

You'll need to have a custom view (*.xib) for laying out native ad assets. In this codelab, the preconfigured view is used to minimize your efforts.

With the iOS project opened in Xcode, confirm that ListTileNativeAdView.xib exists in the Runner project.

a5f04a32f1868d4f.png

Create the ListTileNativeAdFactory class

  1. From the project navigator, right-click the Runner group, and select New File to create a header file for the new class.

6455aab9e9881ca.png

  1. In the template dialog, select the Header File, and name it ListTileNativeAdFactory.
  2. After the ListTileNativeAdFactory.h file is created, define the ListNativeAdFactory class as follows:

ListTileNativeAdFactory.h

#ifndef ListTileNativeAdFactory_h
#define ListTileNativeAdFactory_h

// TODO: Import FLTGoogleMobileAdsPlugin.h
#import "FLTGoogleMobileAdsPlugin.h"

// TODO: Declare ListTileNativeAdFactory
@interface ListTileNativeAdFactory : NSObject<FLTNativeAdFactory>

@end


#endif /* ListTileNativeAdFactory_h */
  1. Create an Objective-C file by selecting New File from the Runner group.
  2. In the next dialog, enter ListTileNativeAdFactory in the File field, and select Empty File as the file type.

2c9c998c48db3a0.png

  1. After you click Next, you're asked to select a folder where the new file should be created. Leave everything unchanged, and click Create.

8635ffe502d1f4ab.png

  1. Implement the ListTileNativeFactory class as follows. Note that the class implements the createNativeAd() method in the FLTNativeAdFactory protocol.

The factory class is responsible for creating a view object for rendering a native ad. As you can see from the code, the factory class creates a GADNativeAdView and populates it with a GADNativeAd object.

ListTileNativeAdFactory.m

// TODO: Import ListTileNativeAdFactory.h
#import "ListTileNativeAdFactory.h"

// TODO: Implement ListTileNativeAdFactory
@implementation ListTileNativeAdFactory

- (GADNativeAdView *)createNativeAd:(GADNativeAd *)nativeAd
                             customOptions:(NSDictionary *)customOptions {
  GADNativeAdView *nativeAdView =
    [[NSBundle mainBundle] loadNibNamed:@"ListTileNativeAdView" owner:nil options:nil].firstObject;

  ((UILabel *)nativeAdView.headlineView).text = nativeAd.headline;

  ((UILabel *)nativeAdView.bodyView).text = nativeAd.body;
  nativeAdView.bodyView.hidden = nativeAd.body ? NO : YES;

  ((UIImageView *)nativeAdView.iconView).image = nativeAd.icon.image;
  nativeAdView.iconView.hidden = nativeAd.icon ? NO : YES;

  nativeAdView.callToActionView.userInteractionEnabled = NO;

  nativeAdView.nativeAd = nativeAd;

  return nativeAdView;
}

@end

Register the ListTileNativeAdFacotry class

An implementation of a FLTNativeAdFactory should be registered to the FLTGoogleMobileAdsPlugin before it can be used from the Flutter side.

Open the AppDelegate.m file, and register the ListTileNativeAdFactory with a unique string ID (listTile) by calling the [FLTGoogleMobileAdsPlugin registerNativeAdFactory] method.

AppDelegate.m

#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"

// TODO: Import ListTileNativeAdFactory.h
#import "ListTileNativeAdFactory.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

  // TODO: Register ListTileNativeAdFactory
  ListTileNativeAdFactory *listTileFactory = [[ListTileNativeAdFactory alloc] init];
  [FLTGoogleMobileAdsPlugin registerNativeAdFactory:self
                                        factoryId:@"listTile"
                                  nativeAdFactory:listTileFactory];

  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

Now you're ready to use the ListTileNativeAdFactory to render native ads on iOS.

Implement NativeAdFactory for iOS (Swift)

Open the ios/Podfile file (or any file under the ios folder), and click Open iOS module in Xcode to open an iOS project.

62aa12c10e6d671f.png

Prepare a native ad layout

You'll need to have a custom view (*.xib) for laying out native ad assets. In this codelab, the preconfigured view is used to minimize your efforts.

With the iOS project opened in Xcode, confirm that ListTileNativeAdView.xib exists in the Runner project.

a5f04a32f1868d4f.png

Create the ListTileNativeAdFactory class

  1. From the project navigator, right-click the Runner group, and select New File to create a header file for the new class.

9115c92543345ef1.png

  1. In the template dialog, select the Swift File, and name it ListTileNativeAdFactory.
  2. After the ListTileNativeAdFactory.swift file is created, implement the ListNativeAdFactory class.

Note that the class implements the createNativeAd() method in the FLTNativeAdFactory protocol.

The factory class is responsible for creating a view object for rendering a native ad. As you can see from the code, the factory class creates a GADNativeAdView and populates it with a GADNativeAd object.

ListTileNativeAdFactory.swift

// TODO: Import google_mobile_ads
import google_mobile_ads

// TODO: Implement ListTileNativeAdFactory
class ListTileNativeAdFactory : FLTNativeAdFactory {

    func createNativeAd(_ nativeAd: GADNativeAd,
                        customOptions: [AnyHashable : Any]? = nil) -> GADNativeAdView? {
        let nibView = Bundle.main.loadNibNamed("ListTileNativeAdView", owner: nil, options: nil)!.first
        let nativeAdView = nibView as! GADNativeAdView

        (nativeAdView.headlineView as! UILabel).text = nativeAd.headline

        (nativeAdView.bodyView as! UILabel).text = nativeAd.body
        nativeAdView.bodyView!.isHidden = nativeAd.body == nil

        (nativeAdView.iconView as! UIImageView).image = nativeAd.icon?.image
        nativeAdView.iconView!.isHidden = nativeAd.icon == nil

        nativeAdView.callToActionView?.isUserInteractionEnabled = false

        nativeAdView.nativeAd = nativeAd

        return nativeAdView
    }
}

Register the ListTileNativeAdFacotry class

An implementation of a FLTNativeAdFactory should be registered to the FLTGoogleMobileAdsPlugin before it can be used from the Flutter side.

Open the AppDelegate.m file, and register the ListTileNativeAdFactory with a unique string ID (listTile) by calling the FLTGoogleMobileAdsPlugin.registerNativeAdFactory() method.

AppDelegate.swift

import UIKit
import Flutter

// TODO: Import google_mobile_ads
import google_mobile_ads

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    // TODO: Register ListTileNativeAdFactory
    let listTileFactory = ListTileNativeAdFactory()
    FLTGoogleMobileAdsPlugin.registerNativeAdFactory(
        self, factoryId: "listTile", nativeAdFactory: listTileFactory)

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Now you're ready to use the ListTileNativeAdFactory to render native ads on iOS.

Integrate the native ad with Flutter widgets

  1. Open lib/native_inline_page.dart file. Then, import ad_helper.dart and google_mobile_ads.dart by adding the following lines:

native_inline_page.dart

...

// TODO: Import ad_helper.dart
import 'package:admob_inline_ads_in_flutter/ad_helper.dart';

// TODO: Import google_mobile_ads.dart
import 'package:google_mobile_ads/google_mobile_ads.dart';

class NativeInlinePage extends StatefulWidget {
  ...
}
  1. In _NativeInlinePageState class, add the following members and methods for a native ad.

Note that _kAdIndex indicates the index where a banner ad will be displayed, and it's used to calculate the item index from the _getDestinationItemIndex() method.

native_inline_page.dart

class _NativeInlinePageState extends State<NativeInlinePage> {

  // TODO: Add _kAdIndex
  static final _kAdIndex = 4;

  // TODO: Add a native ad instance
  NativeAd? _ad;

  ...

  // TODO: Add _getDestinationItemIndex()
  int _getDestinationItemIndex(int rawIndex) {
    if (rawIndex >= _kAdIndex && _ad != null) {
      return rawIndex - 1;
    }
    return rawIndex;
  }

  ...
}
  1. In the initState() method, create and load a NativeAd that uses ListTileNativeAdFactory to generate a native ad view.

Note that the same factory ID (listTile) used to register the factory to the plugin is used.

native_inline_page.dart

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

  // TODO: Create a NativeAd instance
  _ad = NativeAd(
    adUnitId: AdHelper.nativeAdUnitId,
    factoryId: 'listTile',
    request: AdRequest(),
    listener: NativeAdListener(
      onAdLoaded: (ad) {
        setState(() {
          _ad = ad as NativeAd;
        });
      },
      onAdFailedToLoad: (ad, error) {
        // Releases an ad resource when it fails to load
        ad.dispose();
        print('Ad load failed (code=${error.code} message=${error.message})');       },
    ),
  );

  _ad.load();
}
  1. Modify the build() method to display a banner ad when available.
  2. Update itemCount, to count a banner ad entry, and update the itemBuilder, to render a banner ad at the ad index (_kAdIndex) when the ad is loaded.
  3. Update the code to use the _getDestinationItemIndex() method to retrieve an index for the content item.

native_inline_page.dart

@override
Widget build(BuildContext context) {
  return Scaffold(
    ...
    body: ListView.builder(
      // TODO: Adjust itemCount based on the ad load state
      itemCount: widget.entries.length + (_ad != null ? 1 : 0),
      itemBuilder: (context, index) {
        // TODO: Render a banner ad
        if (_ad != null && index == _kAdIndex) {
          return Container(
            height: 72.0,
            alignment: Alignment.center,
            child: AdWidget(ad: _ad!),
          );
        } else {
          // TODO: Get adjusted item index from _getDestinationItemIndex()
          final item = widget.entries[_getDestinationItemIndex(index)];

          return ListTile(
            ...
          );
        }
      },
    ),
  );
}
  1. Release the resource associated with the NativeAd object by calling NativeAd.dispose() method in the dispose() callback method.

native_inline_page.dart

@override
void dispose() {
  // TODO: Dispose a NativeAd object
  _ad?.dispose();

  super.dispose();
}

That's it! Run the project, and click the Native inline ad button from the home page. After an ad is loaded, you'll see a native ad in the middle of the list.

f1671b0fa349ccf8.png 5ead873222c800eb.png

9. All done!

You completed the codelab. You can find the completed code for this codelab in the android_studio_folder.pngcomplete or the android_studio_folder.png complete_kotlin_swift folder.