How to Integrate Google AdMob Native Ads in Flutter (with Full Code & Custom Layout)

π± How to Integrate Google AdMob Native Ads in Flutter (with Full Code & Custom Layout)
Keywords: AdMob Flutter Native Ads, Flutter Native Ad Example, Google Mobile Ads Integration Flutter, AdMob Layout XML, Flutter Monetization Guide, Custom Native AdView Flutter
π Final Output Preview
Watch the full implementation in this YouTube tutorial:
β¨ Introduction
Monetizing your Flutter apps with Google AdMob Native Ads is a powerful way to boost your income while offering a seamless user experience. Native ads blend into your appβs layout, making them appear as part of the UI instead of typical intrusive banners.
In this post, weβll walk through a complete working example of how to integrate native ads in Flutter using a custom XML layout in Android, and how to load and display them from your Dart code.
This guide is beginner-friendly and uses the official google_mobile_ads Flutter plugin from Google.
π§© Prerequisites
-
Flutter 3.19 or higher
-
Android device or emulator
-
Google AdMob account
π¦ Step 1: Add the google_mobile_ads Package
In your pubspec.yaml
:
dependencies:
google_mobile_ads: ^6.0.0
Install it:
flutter pub get
π Docs: google_mobile_ads on pub.dev
π Step 2: Configure Android for AdMob
Edit android/app/src/main/AndroidManifest.xml
:
Inside the <application>
tag, add:
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713"/> <!-- Test App ID -->
π Note: Replace this with your own AdMob App ID when deploying your app.
π Test App & Ad Unit IDs
Β
Set the Minimum SDK Version
In android/app/build.gradle
, ensure:
minSdkVersion 23
π§βπ» Step 3: Add Native Ad Layout in Android
Create the following XML file:
π Path: android/app/src/main/res/layout/native_ads_medium.xml
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/uadview" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFF">
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:minHeight="50dp" android:orientation="vertical">
<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content">
<LinearLayout android:id="@+id/icone" android:layout_width="match_parent" android:layout_height="55dp" android:layout_above="@+id/qwer" android:layout_marginBottom="10dp" android:orientation="horizontal" android:paddingRight="4dp">
<ImageView android:id="@+id/native_ad_icon" android:layout_width="50dp" android:layout_height="50dp" android:layout_margin="2.5dp" android:adjustViewBounds="true"/>
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginLeft="4dp" android:orientation="vertical" android:paddingTop="4dp">
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp" android:layout_marginTop="2dp" android:layout_marginRight="2dp" android:layout_marginBottom="2dp" android:background="#FF8400" android:paddingLeft="3dp" android:paddingTop="2dp" android:paddingRight="3dp" android:paddingBottom="2dp" android:text="Ad" android:textColor="#fff" android:textSize="7dp"/>
<TextView android:id="@+id/native_ad_headline" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:layout_marginTop="2dp" android:ellipsize="end" android:maxLines="1" android:textSize="14sp"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:visibility="visible">
<TextView android:id="@+id/native_ad_body" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="3dp" android:ellipsize="end" android:gravity="bottom" android:maxLines="1" android:textSize="12sp"/>
<RatingBar android:id="@+id/ad_stars" style="?android:attr/ratingBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:isIndicator="true" android:numStars="5" android:stepSize="0.5" android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<LinearLayout android:id="@+id/qwer" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true">
<Button android:id="@+id/native_ad_button" android:layout_width="match_parent" android:layout_height="45dp" android:layout_centerVertical="true" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_marginBottom="5dp" android:background="@drawable/install_btn" android:gravity="center" android:paddingLeft="10dp" android:paddingRight="10dp" android:textAllCaps="false" android:textColor="#fff" android:textSize="16dp"/>
</LinearLayout>
<LinearLayout android:id="@+id/vdhara" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/icone" android:gravity="center" android:orientation="vertical">
<com.google.android.gms.ads.nativead.MediaView android:id="@+id/native_ad_media" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal"/>
</LinearLayout>
<RelativeLayout android:id="@+id/btnview" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_gravity="end" android:orientation="horizontal" android:paddingLeft="10dp" android:paddingTop="10dp" android:paddingRight="6dp" android:paddingBottom="10dp" android:visibility="gone">
<TextView android:id="@+id/ad_advertiser" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginEnd="10dp" android:layout_marginRight="10dp" android:ellipsize="end" android:maxLines="2" android:textSize="12sp" android:visibility="visible"/>
<TextView android:id="@+id/ad_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="5dp" android:paddingLeft="5dp" android:paddingEnd="5dp" android:paddingRight="5dp" android:textSize="12sp" android:visibility="gone"/>
<TextView android:id="@+id/ad_store" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="5dp" android:paddingLeft="5dp" android:paddingEnd="5dp" android:paddingRight="5dp" android:textSize="12sp" android:visibility="gone"/>
<TextView android:layout_width="wrap_content" android:layout_height="30dp" android:layout_alignParentRight="true" android:background="@drawable/install_btn" android:gravity="center" android:paddingLeft="10dp" android:paddingRight="10dp" android:textAllCaps="false" android:textColor="#fff" android:textSize="13sp"/>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
π¨ Step 4: Add Button Background Drawable
Create:
π Path: android/app/src/main/res/drawable/install_btn.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:shape="rectangle">
<gradient android:startColor="#F2A000" android:endColor="#FFA800" android:angle="270"/>
<corners android:radius="12dp"/>
</shape>
βοΈ Step 5: Setup NativeAdFactory in Java
Create NativeAdFactoryMedium.java
in your package folder (in same folder where MainActivity.java is present):
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.gms.ads.nativead.MediaView;
import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;
import java.util.Map;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;
public class NativeAdFactoryMedium implements GoogleMobileAdsPlugin.NativeAdFactory {
private final Context context;
public NativeAdFactoryMedium(Context context) {
this.context = context;
}
@Override
public NativeAdView createNativeAd(NativeAd nativeAd, Map customOptions) {
NativeAdView adView = (NativeAdView) LayoutInflater.from(context)
.inflate(R.layout.native_ads_medium, null);
adView.setMediaView((MediaView) adView.findViewById(R.id.native_ad_media));
adView.setHeadlineView(adView.findViewById(R.id.native_ad_headline));
adView.setBodyView(adView.findViewById(R.id.native_ad_body));
adView.setIconView(adView.findViewById(R.id.native_ad_icon));
adView.setCallToActionView(adView.findViewById(R.id.native_ad_button));
((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
((TextView) adView.getBodyView()).setText(nativeAd.getBody());
if (nativeAd.getIcon() != null) {
((ImageView) adView.getIconView()).setImageDrawable(nativeAd.getIcon().getDrawable());
} else {
adView.getIconView().setVisibility(View.GONE);
}
((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
adView.setNativeAd(nativeAd);
return adView;
}
}
Modify MainActivity.java
Add following code into your MainActivity.java file
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) {
super.configureFlutterEngine(flutterEngine);
GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTileMedium",
new NativeAdFactoryMedium(this));
}
@Override
public void cleanUpFlutterEngine(FlutterEngine flutterEngine) {
super.cleanUpFlutterEngine(flutterEngine);
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTileMedium");
}
}
π§ͺ Step 6: Use NativeAd in Flutter Code
Now you can use NativeAd from google_mobile_ads package as following. just load native ad with factory id listTileMedium and show it anywhere you want:
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State createState() => _HomeScreenState();
}
class _HomeScreenState extends State {
NativeAd? nativeAd;
bool isNativeAdLoaded = false;
@override
void initState() {
super.initState();
loadNativeAd();
}
void loadNativeAd() {
nativeAd = NativeAd(
adUnitId: 'ca-app-pub-3940256099942544/2247696110', // Test Native Ad Unit
factoryId: 'listTileMedium',
request: const AdRequest(),
listener: NativeAdListener(
onAdLoaded: (ad) {
setState(() => isNativeAdLoaded = true);
},
onAdFailedToLoad: (ad, error) {
ad.dispose();
debugPrint('Native Ad failed: $error');
},
),
)..load();
}
@override
void dispose() {
nativeAd?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Native Ad Example')),
body: ListView(
children: [
const SizedBox(height: 20),
Center(child: Text('Google AdMob Native Ad')),
const SizedBox(height: 20),
if (isNativeAdLoaded)
Container(
height: 300,
margin: const EdgeInsets.all(15),
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
),
child: AdWidget(ad: nativeAd!),
)
],
),
);
}
}
β Best Practices & Important Notes
-
-
Use test ad units while developing.
π Google AdMob Sample Ad Units -
Ensure you're complying with Google's native ad policies.
π Native Ads Guidelines -
Read the official Flutter AdMob Integration Guide
-
π Conclusion
With this full setup, you've successfully integrated Google AdMob Native Ads in Flutter using a custom XML layout, Dart logic, and Java factory registration. Native ads provide a sleek and efficient monetization method by blending ads directly into your UI.
π Related Links
π Bonus: Displaying Smaller Sized Native Ads in Flutter
If you want to display compact native adsβideal for list items, feed cards, or tighter spacesβyou can create a custom NativeAdFactory
with a smaller layout. Hereβs how to set it up step-by-step.
π Step 1: Create a Smaller Native Ad Layout
Create a new layout file: res/layout/native_ads_small.xml
. Below is an optimized, smaller design for native ads.Β
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/uadview" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFF">
<FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content">
<LinearLayout android:id="@+id/ll_space" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#e9e9e9" android:visibility="gone">
<TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="7dp" android:gravity="center" android:text="Reserved For Ads Space" android:textColor="#b9b9b9" android:textSize="12dp"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="150dp" android:orientation="vertical">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp" android:layout_marginTop="2dp" android:layout_marginRight="2dp" android:layout_marginBottom="2dp" android:background="#FF8400" android:paddingLeft="3dp" android:paddingTop="2dp" android:paddingRight="3dp" android:paddingBottom="2dp" android:text="Ad" android:textColor="#fff" android:textSize="7dp"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="2dp" android:layout_marginTop="1dp" android:layout_marginRight="2dp" android:layout_marginBottom="4dp" android:orientation="vertical">
<com.google.android.gms.ads.nativead.MediaView android:id="@+id/ad_media" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:visibility="gone"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginTop="2dp" android:layout_marginRight="8dp" android:orientation="horizontal">
<ImageView android:id="@+id/native_ad_icon" android:layout_width="65dp" android:layout_height="65dp" android:layout_gravity="center" android:adjustViewBounds="true"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:layout_weight="1" android:orientation="vertical">
<TextView android:id="@+id/native_ad_headline" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:textColor="#000" android:textSize="15dp" android:textStyle="bold"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:gravity="center_vertical" android:orientation="horizontal">
<TextView android:id="@+id/ad_advertiser" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="bottom" android:textColor="#000" android:textSize="10dp" android:textStyle="normal" android:visibility="gone"/>
<RatingBar android:id="@+id/ad_stars" style="?android:attr/ratingBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp" android:isIndicator="true" android:numStars="5" android:stepSize="0.5" android:visibility="gone"/>
</LinearLayout>
<TextView android:id="@+id/native_ad_body" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="2dp" android:layout_weight="1" android:maxLines="3" android:minLines="3" android:textSize="9dp" android:visibility="visible"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" android:visibility="gone">
<TextView android:id="@+id/ad_price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="4dp" android:paddingRight="4dp" android:textColor="#000" android:textSize="12dp"/>
<TextView android:id="@+id/ad_store" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingLeft="4dp" android:paddingRight="4dp" android:textColor="#000" android:textSize="10dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="4dp" app:cardElevation="4dp" app:cardUseCompatPadding="true">
<Button android:id="@+id/native_ad_button" android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginTop="8dp" android:background="@drawable/install_btn" android:gravity="center" android:singleLine="true" android:textAllCaps="true" android:textColor="#fff" android:textSize="16dp" android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
π οΈ Step 2: Create NativeAdFactorySmall.java
This class inflates your custom layout and binds ad data:
public class NativeAdFactorySmall implements GoogleMobileAdsPlugin.NativeAdFactory {
private final Context context;
NativeAdFactorySmall(Context context) {
this.context = context;
}
public NativeAdView createNativeAd(NativeAd nativeAd, Map customOptions) {
NativeAdView adView = (NativeAdView) LayoutInflater.from(context)
.inflate(R.layout.native_ads_small, null);
adView.setIconView(adView.findViewById(R.id.native_ad_icon));
if (nativeAd.getIcon() != null) {
((ImageView) adView.getIconView()).setImageDrawable(nativeAd.getIcon().getDrawable());
} else {
adView.getIconView().setVisibility(View.GONE);
}
adView.setCallToActionView(adView.findViewById(R.id.native_ad_button));
if (nativeAd.getCallToAction() != null) {
((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
} else {
adView.getCallToActionView().setVisibility(View.GONE);
}
adView.setHeadlineView(adView.findViewById(R.id.native_ad_headline));
((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
adView.setBodyView(adView.findViewById(R.id.native_ad_body));
if (nativeAd.getBody() != null) {
((TextView) adView.getBodyView()).setText(nativeAd.getBody());
} else {
adView.getBodyView().setVisibility(View.GONE);
}
adView.setNativeAd(nativeAd);
return adView;
}
}
π§ Step 3: Register in MainActivity.java
Update your MainActivity
to register and clean up the native ad factory:
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
// TODO: Register the ListTileNativeAdFactory
GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTile",
new NativeAdFactorySmall(getContext()));
GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTileMedium",
new NativeAdFactoryMedium(getContext()));
}
@Override
public void cleanUpFlutterEngine(FlutterEngine flutterEngine) {
super.cleanUpFlutterEngine(flutterEngine);
// TODO: Unregister the ListTileNativeAdFactory
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile");
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTileMedium");
}
}
β Flutter Usage Example
In your Dart code:
NativeAd(
adUnitId: 'your-admob-ad-unit-id',
factoryId: 'listTile', // Must match the one you registered
listener: NativeAdListener(
onAdLoaded: (_) => print('Ad loaded!'),
onAdFailedToLoad: (ad, error) {
print('Ad failed to load: $error');
ad.dispose();
},
),
request: AdRequest(),
),