Native ads are presented to users using UI components native to the
platform---for example, a
[`View`](https://developer.android.com/reference/android/view/View) on Android or
a [`UIView`](https://developer.apple.com/documentation/uikit/uiview?language=objc) on
iOS.

This guide shows you how to load, display, and customize native ads using
platform-specific code.

## Prerequisites

Before you continue, do the following:

- [Set up Google Mobile Ads Flutter Plugin](https://developers.google.com/ad-manager/mobile-ads-sdk/flutter/quick-start.md.txt).
- [Set up native ads](https://developers.google.com/ad-manager/mobile-ads-sdk/flutter/native.md.txt).

## Always test with test ads

When building and testing your apps, make sure you use test ads rather than
live, production ads. The easiest way to load test ads is to use our dedicated
test ad unit ID for native ads:

- `/21775744923/example/native`

The test ad units are configured to return test ads for every request, so
you can use them in your own apps while coding, testing, and
debugging---just make sure you replace them with your own ad unit IDs before
publishing your app.

## Platform-specific setups

To create your native ads, you'll need to write platform-specific code for iOS
and Android, followed by modifying your [Dart implementation](https://developers.google.com/ad-manager/mobile-ads-sdk/flutter/native/platforms.md.txt#load) to take
advantage of the native code changes you made.

### Android

#### Import the plugin

The Android implementation of the Google Mobile Ads plugin requires a class
implementing the
[`NativeAdFactory`](https://github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/GoogleMobileAdsPlugin.java#L103-L116)
API. In order to reference this API from your Android project, add the
following lines to your settings.gradle:

    def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
    def plugins = new Properties()
    def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
    if (pluginsFile.exists()) {
        pluginsFile.withInputStream { stream -> plugins.load(stream) }
    }

    plugins.each { name, path ->
        def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
        include ":$name"
        project(":$name").projectDir = pluginDirectory
    }

#### Implement NativeAdFactory

Next, create a class that implements `NativeAdFactory` and overrides
the `createNativeAd()` method.

    package io.flutter.plugins.googlemobileadsexample;

    import android.graphics.Color;
    import android.view.LayoutInflater;
    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.NativeAdFactory;
    import java.util.Map;

    /**
     * my_native_ad.xml can be found at
     * github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/
     *     example/android/app/src/main/res/layout/my_native_ad.xml
     */
    class NativeAdFactoryExample implements NativeAdFactory {
      private final LayoutInflater layoutInflater;

      NativeAdFactoryExample(LayoutInflater layoutInflater) {
        this.layoutInflater = layoutInflater;
      }

      @Override
      public NativeAdView createNativeAd(
          NativeAd nativeAd, Map&lt;String, Object> customOptions) {
        final NativeAdView adView =
            (NativeAdView) layoutInflater.inflate(R.layout.my_native_ad, null);

        // Set the media view.
        adView.setMediaView((MediaView) adView.findViewById(R.id.ad_media));

        // Set other ad assets.
        adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
        adView.setBodyView(adView.findViewById(R.id.ad_body));
        adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
        adView.setIconView(adView.findViewById(R.id.ad_app_icon));
        adView.setPriceView(adView.findViewById(R.id.ad_price));
        adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
        adView.setStoreView(adView.findViewById(R.id.ad_store));
        adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));

        // The headline and mediaContent are guaranteed to be in every NativeAd.
        ((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
        adView.getMediaView().setMediaContent(nativeAd.getMediaContent());

        // These assets aren't guaranteed to be in every NativeAd, so it's important to
        // check before trying to display them.
        if (nativeAd.getBody() == null) {
          adView.getBodyView().setVisibility(View.INVISIBLE);
        } else {
          adView.getBodyView().setVisibility(View.VISIBLE);
          ((TextView) adView.getBodyView()).setText(nativeAd.getBody());
        }

        if (nativeAd.getCallToAction() == null) {
          adView.getCallToActionView().setVisibility(View.INVISIBLE);
        } else {
          adView.getCallToActionView().setVisibility(View.VISIBLE);
          ((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
        }

        if (nativeAd.getIcon() == null) {
          adView.getIconView().setVisibility(View.GONE);
        } else {
          ((ImageView) adView.getIconView()).setImageDrawable(nativeAd.getIcon().getDrawable());
          adView.getIconView().setVisibility(View.VISIBLE);
        }

        if (nativeAd.getPrice() == null) {
          adView.getPriceView().setVisibility(View.INVISIBLE);
        } else {
          adView.getPriceView().setVisibility(View.VISIBLE);
          ((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
        }

        if (nativeAd.getStore() == null) {
          adView.getStoreView().setVisibility(View.INVISIBLE);
        } else {
          adView.getStoreView().setVisibility(View.VISIBLE);
          ((TextView) adView.getStoreView()).setText(nativeAd.getStore());
        }

        if (nativeAd.getStarRating() == null) {
          adView.getStarRatingView().setVisibility(View.INVISIBLE);
        } else {
          ((RatingBar) adView.getStarRatingView()).setRating(nativeAd.getStarRating()
              .floatValue());
          adView.getStarRatingView().setVisibility(View.VISIBLE);
        }

        if (nativeAd.getAdvertiser() == null) {
          adView.getAdvertiserView().setVisibility(View.INVISIBLE);
        } else {
          adView.getAdvertiserView().setVisibility(View.VISIBLE);
          ((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
        }

        // This method tells Google Mobile Ads Flutter Plugin that you have finished populating your
        // native ad view with this native ad.
        adView.setNativeAd(nativeAd);

        return adView;
      }
    }

For an example of configuring your `NativeAdView` layout, see [my_native_ad.xml](https://github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/example/android/app/src/main/res/layout/my_native_ad.xml).

#### Register your NativeAdFactory

Each `NativeAdFactory` implementation is required to be registered with a
`factoryId`, a unique `String` identifier, when calling
`MainActivity.configureFlutterEngine(FlutterEngine)`. The `factoryId` will be
used later when [instantiating a native ad](https://developers.google.com/ad-manager/mobile-ads-sdk/flutter/native/platforms.md.txt#load) from Dart code.

A `NativeAdFactory` can be implemented and registered for each unique native
ad layout used by your app, or a single one can handle all layouts.

Note that when building with
[add-to-app](https://flutter.dev/docs/development/add-to-app#add-to-app), the
`NativeAdFactory` should also be unregistered in
`cleanUpFlutterEngine(engine)`.

Once you've created `NativeAdFactoryExample`, set up your`MainActivity` as
follows:

    package my.app.path;

    import io.flutter.embedding.android.FlutterActivity;
    import io.flutter.embedding.engine.FlutterEngine;
    import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;

    public class MainActivity extends FlutterActivity {
      @Override
      public void configureFlutterEngine(FlutterEngine flutterEngine) {
        flutterEngine.getPlugins().add(new GoogleMobileAdsPlugin());
        super.configureFlutterEngine(flutterEngine);

        GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine,
            "adFactoryExample", NativeAdFactoryExample());
      }

      @Override
      public void cleanUpFlutterEngine(FlutterEngine flutterEngine) {
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "adFactoryExample");
      }
    }

### iOS

#### Implement NativeAdFactory

The iOS implementation of the Google Mobile Ads plugin requires a class
implementing the
[`FLTNativeAdFactory`](https://github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/ios/Classes/FLTGoogleMobileAdsPlugin.h#L34-L47)
API. Create a class that implements `NativeAdFactory` and implement the
`createNativeAd()` method.

    #import "FLTGoogleMobileAdsPlugin.h"

    /**
     * The example NativeAdView.xib can be found at
     * github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/
     *     example/ios/Runner/NativeAdView.xib
     */
    @interface NativeAdFactoryExample : NSObject &lt;FLTNativeAdFactory>
    @end

    @implementation NativeAdFactoryExample
    - (GADNativeAdView *)createNativeAd:(GADNativeAd *)nativeAd
                          customOptions:(NSDictionary *)customOptions {
      // Create and place the ad in the view hierarchy.
      GADNativeAdView *adView =
          [[NSBundle mainBundle] loadNibNamed:@"NativeAdView" owner:nil options:nil].firstObject;

      // Populate the native ad view with the native ad assets.
      // The headline is guaranteed to be present in every native ad.
      ((UILabel *)adView.headlineView).text = nativeAd.headline;

      // These assets are not guaranteed to be present. Check that they are before
      // showing or hiding them.
      ((UILabel *)adView.bodyView).text = nativeAd.body;
      adView.bodyView.hidden = nativeAd.body ? NO : YES;

      [((UIButton *)adView.callToActionView) setTitle:nativeAd.callToAction
                                             forState:UIControlStateNormal];
      adView.callToActionView.hidden = nativeAd.callToAction ? NO : YES;

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

      ((UILabel *)adView.storeView).text = nativeAd.store;
      adView.storeView.hidden = nativeAd.store ? NO : YES;

      ((UILabel *)adView.priceView).text = nativeAd.price;
      adView.priceView.hidden = nativeAd.price ? NO : YES;

      ((UILabel *)adView.advertiserView).text = nativeAd.advertiser;
      adView.advertiserView.hidden = nativeAd.advertiser ? NO : YES;

      // In order for the SDK to process touch events properly, user interaction
      // should be disabled.
      adView.callToActionView.userInteractionEnabled = NO;

      // Associate the native ad view with the native ad object. This is
      // required to make the ad clickable.
      // Note: this should always be done after populating the ad views.
      adView.nativeAd = nativeAd;

      return adView;
    }
    @end

For an example of configuring your `GADNativeAdView` layout, see [NativeAdView.xib](https://github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/example/ios/Runner/NativeAdView.xib).

#### Register your NativeAdFactory

Each `FLTNativeAdFactory` needs to be registered with a `factoryId`, a unique
`String` identifier, in `registerNativeAdFactory:factoryId:nativeAdFactory:`.
The `factoryId` will be used later when [instantiating a native ad](https://developers.google.com/ad-manager/mobile-ads-sdk/flutter/native/platforms.md.txt#load)
from Dart code.

An `FLTNativeAdFactory` can be implemented and registered for each unique
native ad layout used by your app, or a single one can handle all layouts.

Once you've created `FLTNativeAdFactory`, set up your `AppDelegate` as
follows:

    #import "FLTGoogleMobileAdsPlugin.h"
    #import "NativeAdFactoryExample.h"

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

      // Must be added after GeneratedPluginRegistrant registerWithRegistry:self];
      // is called.
      NativeAdFactoryExample *nativeAdFactory = [[NativeAdFactoryExample alloc] init];
      [FLTGoogleMobileAdsPlugin registerNativeAdFactory:self
                                              factoryId:@"adFactoryExample"
                                        nativeAdFactory:nativeAdFactory];

      return [super application:application didFinishLaunchingWithOptions:launchOptions];
    }
    @end

## Load ad

After you've added your platform-specific code, turn to Dart to load ads. Make
sure `factoryID` match the ID you registered earlier.

    class NativeExampleState extends State<NativeExample> {
      NativeAd? _nativeAd;
      bool _nativeAdIsLoaded = false;

     // TODO: replace this test ad unit with your own ad unit.
     final _adUnitId = '/21775744923/example/native';

      /// Loads a native ad.
      void loadAd() {
        _nativeAd = NativeAd(
            adUnitId: _adUnitId,
            // Factory ID registered by your native ad factory implementation.
            factoryId: 'adFactoryExample',
            listener: NativeAdListener(
              onAdLoaded: (ad) {
                print('$NativeAd loaded.');
                setState(() {
                  _nativeAdIsLoaded = true;
                });
              },
              onAdFailedToLoad: (ad, error) {
                // Dispose the ad here to free resources.
                print('$NativeAd failedToLoad: $error');
                ad.dispose();
              },
            ),
            request: const AdManagerAdRequest(),
            // Optional: Pass custom options to your native ad factory implementation.
            customOptions: {'custom-option-1', 'custom-value-1'}
        );
        _nativeAd.load();
      }
    }

## Native ad events

To be notified of events related to the native ad interactions, use the
[`listener`](https://pub.dev/documentation/google_mobile_ads/latest/google_mobile_ads/NativeAd/listener.html)
property of the ad. Then, implement
[`NativeAdListener`](https://pub.dev/documentation/google_mobile_ads/latest/google_mobile_ads/NativeAdListener-class.html)
to receive ad event callbacks.

    class NativeExampleState extends State<NativeExample> {
      NativeAd? _nativeAd;
      bool _nativeAdIsLoaded = false;

     // TODO: replace this test ad unit with your own ad unit.
     final _adUnitId = '/21775744923/example/native';

      /// Loads a native ad.
      void loadAd() {
        _nativeAd = NativeAd(
            adUnitId: _adUnitId,
            // Factory ID registered by your native ad factory implementation.
            factoryId: 'adFactoryExample',
            listener: NativeAdListener(
              onAdLoaded: (ad) {
                print('$NativeAd loaded.');
                setState(() {
                  _nativeAdIsLoaded = true;
                });
              },
              onAdFailedToLoad: (ad, error) {
                // Dispose the ad here to free resources.
                print('$NativeAd failedToLoad: $error');
                ad.dispose();
              },
              // Called when a click is recorded for a NativeAd.
    onAdClicked: (ad) {},
    // Called when an impression occurs on the ad.
    onAdImpression: (ad) {},
    // Called when an ad removes an overlay that covers the screen.
    onAdClosed: (ad) {},
    // Called when an ad opens an overlay that covers the screen.
    onAdOpened: (ad) {},
    // For iOS only. Called before dismissing a full screen view
    onAdWillDismissScreen: (ad) {},
    // Called when an ad receives revenue value.
    onPaidEvent: (ad, valueMicros, precision, currencyCode) {},
            ),
            request: const AdManagerAdRequest(),
            // Optional: Pass custom options to your native ad factory implementation.
            customOptions: {'custom-option-1', 'custom-value-1'}
        );
        _nativeAd.load();
            
      }
    }

## Display ad

To display a `NativeAd` as a widget, you must instantiate an
[`AdWidget`](https://pub.dev/documentation/google_mobile_ads/latest/google_mobile_ads/AdWidget-class.html)
with a supported ad after calling `load()`. You can create the widget before
calling `load()`, but `load()` must be called before adding it to the widget
tree.

`AdWidget` inherits from Flutter's `Widget` class and can be used like any other
widget. On iOS, make sure you place the widget in a container with a specified
width and height. Otherwise, your ad may not be displayed.

    final Container adContainer = Container(
      alignment: Alignment.center,
      child: AdWidget adWidget = AdWidget(ad: _nativeAd!),
      width: WIDTH,
      height: HEIGHT,
    );

## Dispose ad

A
[`NativeAd`](https://pub.dev/documentation/google_mobile_ads/latest/google_mobile_ads/NativeAd-class.html)
must be disposed of when access to it is no longer needed. The best practice for
when to call `dispose()` is after the `AdWidget` associated with the native ad
is removed from the widget tree and in the `AdListener.onAdFailedToLoad()`
callback.