Native ads are presented to users using UI components native to the
platform—for example, a View
on Android or
a UIView
on
iOS.
This guide shows you how to load, display, and customize native ads using platform-specific code.
Prerequisites
- Complete the Get started guide .
- Familiarize yourself with the native ads options .
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:
Android
ca-app-pub-3940256099942544/2247696110
iOS
ca-app-pub-3940256099942544/3986624511
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 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
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<
;
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
SDK
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
.
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
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
, 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
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
.
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
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
String
_adUnitId
=
Platform
.
isAndroid
?
'ca-app-pub-3940256099942544/2247696110'
:
'ca-app-pub-3940256099942544/3986624511'
;
///
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
AdRequest
(),
//
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
property of the ad. Then, implement NativeAdListener
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
String
_adUnitId
=
Platform
.
isAndroid
?
'ca-app-pub-3940256099942544/2247696110'
:
'ca-app-pub-3940256099942544/3986624511'
;
///
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
AdRequest
(),
//
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
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
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.
Next steps
- Learn more about native ads in our native ad playbook .
- See native ads policies and guidelines .
- Check out some customer success stories: Case study 1 , case study 2 .