google_admob_sdk 0.0.8
google_admob_sdk: ^0.0.8 copied to clipboard
A Flutter plugin for Google Mobile Ads (AdMob) with centralized Ad Unit ID management, load duration metrics, adKey tracking, and pre-built ad widgets & managers.
Google AdMob SDK for Flutter (google_admob_sdk) #
A comprehensive, production-ready Flutter SDK wrapper for Google Mobile Ads (google_mobile_ads) with built-in Ad Unit ID management per platform, load time performance tracking, Firebase Analytics integration, customizable ProgressIndicators, and pre-built ad widgets & managers.
Features #
- β‘ Easy Initialization: Initialize Google Mobile Ads with custom or test configuration in a single line.
- π― Ad ID Management: Centralized
AdIdConfigfor Android & iOS supporting 6 ad types (Banner, Interstitial, Rewarded, Rewarded Interstitial, App Open, Native) with fallback to Google official test IDs. - π Performance & Event Analytics: Built-in
AdAnalyticsLoggersupportingFirebaseAdLogger,ConsoleAdLogger, or custom loggers to track ad load duration (ms), impressions, clicks, and load failures withadKeytracking (key_<ad_type>). - πΌοΈ Banner Ad Widget:
BannerAdWidgetwidget with automatic state management, customizableprogressIndicator,loadingBuilder, anderrorBuilder. - π¬ Interstitial Ad Manager:
InterstitialAdManager.sharedsingleton, Frequency Capping (minShowInterval,canShow), andshowAdSafely(...)with countdown warning dialog to prevent accidental clicks (High CTR / Invalid Traffic penalty protection). - π Rewarded Ad Manager:
RewardedAdManager.sharedandshowAdSafely(...)ensuring preloaded ads persist across screens with 0% show rate resolution. - π Rewarded Interstitial Ad Manager:
RewardedInterstitialAdManager.sharedwith safe frequency capping and preloaded lifecycle management. - πͺ App Open Ad Manager:
AppOpenAdManager.sharedwith built-in ad expiration check (4 hours max age per Google guidelines). - π¨ Native Ad Widget & Cache Pool:
NativeAdWidgetwithkeepAlive: trueandNativeAdPoolcache to prevent impression spam (24-34 imp/user) in ListView/TabBarView, plus Figma presets (cls,mediaView,interstitial), custom layouts, and fullscreen native dialogs. - π€ Bidding & Mediation Setup: Out-of-the-box support and native configuration guides for AppLovin, Unity Ads, Pangle, Meta Audience Network, and Mintegral.
Getting Started #
1. Add Dependency #
Add google_admob_sdk to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
google_admob_sdk:
path: ../google_admob_sdk # Or git / pub package path
2. Platform Configuration #
Android Setup (AndroidManifest.xml)
Add your AdMob App ID inside the <application> tag:
<manifest>
<application>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713"/> <!-- Test App ID -->
</application>
</manifest>
iOS Setup (Info.plist)
Add GADApplicationIdentifier to ios/Runner/Info.plist:
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string> <!-- Test App ID -->
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
</array>
Usage #
1. SDK Initialization #
Initialize GoogleAdmobSdk in your main() function:
import 'package:flutter/material.dart';
import 'package:google_admob_sdk/google_admob_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await GoogleAdmobSdk.initialize(
config: AdIdConfig(
android: const PlatformAdIds(
bannerId: 'ca-app-pub-xxx/android_banner',
interstitialId: 'ca-app-pub-xxx/android_interstitial',
rewardedId: 'ca-app-pub-xxx/android_rewarded',
rewardedInterstitialId: 'ca-app-pub-xxx/android_rewarded_interstitial',
appOpenId: 'ca-app-pub-xxx/android_app_open',
nativeId: 'ca-app-pub-xxx/android_native',
),
ios: const PlatformAdIds(
bannerId: 'ca-app-pub-xxx/ios_banner',
interstitialId: 'ca-app-pub-xxx/ios_interstitial',
rewardedId: 'ca-app-pub-xxx/ios_rewarded',
rewardedInterstitialId: 'ca-app-pub-xxx/ios_rewarded_interstitial',
appOpenId: 'ca-app-pub-xxx/ios_app_open',
nativeId: 'ca-app-pub-xxx/ios_native',
),
),
logger: FirebaseAdLogger(), // Log performance metrics to Firebase Analytics
enableConsoleLog: true, // Print ad load duration and events in debug console
);
runApp(const MyApp());
}
2. Banner Ad Widget (Custom progressIndicator) #
Embed BannerAdWidget directly into your widget tree and pass any custom progressIndicator:
BannerAdWidget(
adKey: 'home_bottom_banner',
screenName: 'scrHome',
adPlacement: 'scrHome',
adUnitName: 'Banner_Home',
adSize: AdSize.banner,
// Custom ProgressIndicator widget
progressIndicator: CircularProgressIndicator(
color: Colors.blueAccent,
strokeWidth: 3.0,
),
onAdLoaded: (ad) => print('Banner Loaded'),
onAdFailedToLoad: (error) => print('Banner Failed: $error'),
)
3. Native Ad Widget & Fullscreen Dialog #
Embed NativeAdWidget with built-in presets (mediaView, cls, interstitial, small, dark) or custom styling:
// Using Preset (Blue CTA #1A90FF, 10px rounded corners)
NativeAdWidget(
adKey: 'feed_native_ad',
screenName: 'scrHome',
adPlacement: 'scrHome',
adUnitName: 'Native_Home',
templatePreset: NativeTemplatePreset.mediaView,
height: 320,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
boxShadow: const [
BoxShadow(color: Color(0x0F000000), blurRadius: 8, offset: Offset(0, 2)),
],
),
)
```dart
// 1. Built-in Presets (Auto-links to native Android XML layouts matching Figma designs):
// - NativeTemplatePreset.cls: CTA button #1A90FF on the RIGHT, MediaView on TOP (Figma Node 70:6183)
// - NativeTemplatePreset.mediaView: CTA button #1A90FF on TOP, MediaView in MIDDLE (Figma Node 70:6182)
// - NativeTemplatePreset.interstitial: Large format layout (Figma Node 70:6181)
NativeAdWidget(
adKey: 'feed_native_ad',
templatePreset: NativeTemplatePreset.cls,
height: 320,
)
// 2. Custom Layout Builder in Flutter (rearrange surrounding elements freely):
NativeAdWidget(
adKey: 'feed_native_ad',
templatePreset: NativeTemplatePreset.cls,
height: 320,
header: const Text('Sponsored'),
showCloseButton: true,
onClose: () => print('Closed'),
layoutBuilder: (context, adView) {
return Column(
children: [
adView,
const Text('Tap to view details'),
],
);
},
)
// 3. Fullscreen Native Interstitial Dialog (Figma Ads Interstitial node 70:6181):
showNativeAdInterstitialDialog(
context: context,
adKey: 'native_interstitial_dialog',
screenName: 'scrInterstitialDialog',
);
// 4. In ListView / PageView (keepAlive: true prevents impression spam on scroll):
ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
if (index % 5 == 0) {
return NativeAdWidget(
adKey: 'feed_native_ad',
keepAlive: true, // Default: true. Retains state and prevents reload on scroll
cacheKey: 'feed_native_$index', // Optional: cache in NativeAdPool
templatePreset: NativeTemplatePreset.cls,
height: 320,
);
}
return ListTile(title: Text('Item $index'));
},
);
// 5. 100% Custom Native XML/XIB Layout via factoryId:
NativeAdWidget(
adKey: 'custom_native_factory',
factoryId: 'my_custom_factory', // Registered in Android MainActivity / iOS AppDelegate
height: 300,
)
Registering Custom Native Ad Factory in Android (MainActivity.kt):
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin
import io.flutter.plugins.googlemobileads.NativeAdFactory // TOP-LEVEL INTERFACE in google_mobile_ads 9.x
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GoogleMobileAdsPlugin.registerNativeAdFactory(
flutterEngine,
"my_custom_factory",
MyCustomNativeAdFactory(layoutInflater)
)
}
override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "my_custom_factory")
super.cleanUpFlutterEngine(flutterEngine)
}
}
π Comprehensive Guide: For complete step-by-step XML layouts, drawables, and iOS Swift setup, see doc/CUSTOM_NATIVE_LAYOUTS.md.
4. Interstitial Ad (Shared Instance & Safe Show) #
Use InterstitialAdManager.shared to load and present interstitial ads across your entire app, with built-in Frequency Capping (3-minute cooldown) and Countdown Notice to prevent accidental clicks and invalid traffic penalties:
// Use the shared instance across the whole app
final interstitialManager = InterstitialAdManager.shared;
// 1. Preload Interstitial Ad with Databuckets tracking parameters
await interstitialManager.loadAd(
adKey: 'level_complete_interstitial',
screenName: 'scrLevelComplete',
adPlacement: 'scrLevelComplete',
adUnitName: 'Inter_LevelPass',
sessionNumber: 1,
);
// 2. Safely present with cooldown check & warning countdown overlay:
// - Checks if cooldown elapsed (minShowInterval default 180s)
// - Shows brief countdown notice ("Ad starting shortly") before full-screen takeover
// - Always triggers onCompleted so game/app flow is never blocked
// - Fully customizable via countdownTitle, countdownSubtitle, or countdownConfig
await interstitialManager.showAdSafely(
context: context,
adKey: 'level_complete_interstitial',
checkCooldown: true,
showWarningCountdown: true,
countdownDuration: const Duration(milliseconds: 1200),
countdownTitle: 'Ad starting shortly',
countdownSubtitle: 'Please wait a moment...',
onCompleted: () {
// Proceed to next level or resume gameplay
},
);
5. Rewarded Ad & Rewarded Interstitial Ad #
Use RewardedAdManager.shared or RewardedInterstitialAdManager.shared to ensure preloaded rewarded ads are not lost when switching screens:
// Use the shared instance across screens
final rewardedManager = RewardedAdManager.shared;
await rewardedManager.loadAd(
adKey: 'extra_lives_rewarded',
screenName: 'scrShop',
adPlacement: 'scrShop',
adUnitName: 'Rewarded_ExtraLives',
);
// Present safely
await rewardedManager.showAdSafely(
context: context,
adKey: 'extra_lives_rewarded',
onUserEarnedReward: (ad, reward) {
print('User earned: ${reward.amount} ${reward.type}');
},
onCompleted: () {
print('Rewarded flow finished');
},
);
6. App Open Ad #
Use AppOpenAdManager.shared for app startup or resume ads:
final appOpenManager = AppOpenAdManager.shared;
await appOpenManager.loadAd(
adKey: 'app_launch_open_ad',
screenName: 'scrSplash',
adPlacement: 'scrSplash',
adUnitName: 'AppOpen_Splash',
);
if (appOpenManager.isAdAvailable) {
await appOpenManager.showAdIfAvailable();
}
Databuckets Data Tracking Plan (Sheet "41") #
google_admob_sdk automatically measures ad performance and logs events fully compliant with the Databuckets Tracking Plan (Sheet 41):
Universal IAA Events #
| Event Name | Trigger | Main Parameters Logged |
|---|---|---|
iaa_request |
When ad load request starts | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_mediation, screen_name, session_number |
iaa_loaded |
When ad load succeeds | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_mediation, screen_name, is_load: 1, load_time |
iaa_fail_load |
When ad load fails | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_mediation, screen_name, is_load: 0, error_code, error_message |
iaa_impression |
When ad impression occurs | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_mediation, ad_placement, screen_name, currency, value |
iaa_fail_show |
When ad show fails | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_placement, screen_name, error_code, error_message |
iaa_click |
When user clicks ad | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_mediation, ad_placement, screen_name |
iaa_complete |
When full-screen ad ends | ad_request_id, ad_format, ad_unit_name, ad_unit_id, ad_placement, screen_name, end_type (done/quit), duration_ad |
Parameter Reference #
Note
Format for screen_name & ad_placement: Values representing screen names must strictly follow lowerCamelCase starting with the scr prefix (e.g., scrHome, scrOnboard, scrSplash, scrLevelComplete, scrShop).
When you pass an adKey parameter (e.g. 'home_bottom_banner'), the SDK automatically passes both ad_key and dynamic key_<ad_type> parameters to Firebase Analytics:
| Parameter Name in Analytics | Value Example | Description |
|---|---|---|
ad_key |
'home_bottom_banner' |
Generic ad placement key |
key_banner |
'home_bottom_banner' |
Type-specific key for Banner ads |
key_interstitial |
'level_complete_interstitial' |
Type-specific key for Interstitial ads |
key_rewarded |
'extra_lives_rewarded' |
Type-specific key for Rewarded ads |
key_rewardedInterstitial |
'bonus_stage_rewarded_interstitial' |
Type-specific key for Rewarded Interstitial ads |
key_appOpen |
'app_launch_open_ad' |
Type-specific key for App Open ads |
key_native |
'feed_native_ad' |
Type-specific key for Native ads |
AdMob Quality, Show Rate & Match Rate Protection Architecture #
To ensure your app never suffers from low Match Rates (Fill Rate), dropped Show Rates (< 50%), or account-level Invalid Traffic penalties, the SDK includes enterprise-grade guardrails:
1. Ad TTL & Expiration Auto-Invalidation (60 Minutes) #
Google AdMob terms dictate that fullscreen ads expire within 60 minutes (4 hours for App Open). Displaying stale ads results in dropped impressions or policy penalties.
All managers (InterstitialAdManager, RewardedAdManager, RewardedInterstitialAdManager, AppOpenAdManager) automatically check isAdAvailable and dispose expired ads immediately:
// Check if ad is available and not expired (within 60m)
if (InterstitialAdManager.shared.isAdAvailable) {
// Safe to present
}
2. Exponential Backoff & Circuit Breaker (AdRetryPolicy) #
Aggressive ad requests after No-Fill (ERROR_CODE_NO_FILL = 3) can ruin your Ad Unit's Quality Score. The SDK uses an exponential retry strategy (2s $\rightarrow$ 4s $\rightarrow$ 8s $\rightarrow$ 16s $\rightarrow$ 60s) and automatically trips a Circuit Breaker when consecutive failures occur:
// Managers automatically manage retryPolicy
final retryPolicy = InterstitialAdManager.shared.retryPolicy;
print('Is circuit breaker open: ${retryPolicy.isCircuitOpen}');
3. Smart Auto-Reload & Delay Capping #
Eliminate Orphan Preloads (ads loaded upon dismissal that are abandoned when the user leaves the app):
// Globally configure in GoogleAdmobSdk.initialize:
await GoogleAdmobSdk.initialize(
enableAutoReload: true,
autoReloadDelay: const Duration(seconds: 5), // Gives user time before preloading next ad
);
4. Realtime AdMob Health Monitor (AdHealthMonitor) #
Diagnose your app's live Match Rate, Show Rate, and CTR during testing and release:
// Access live diagnostic metrics
final health = GoogleAdmobSdk.instance.healthMonitor;
print(health.summary());
// Output:
// AdMob Health Summary:
// Requests: 12 | Loaded: 10 | Failed: 2
// Impressions: 8 | Clicks: 1
// Match Rate: 83.3% | Show Rate: 80.0% | CTR: 12.5%
AdMob Mediation & Bidding (AppLovin, Meta, Mintegral, Unity Ads, Pangle) #
The SDK fully supports third-party ad networks (Mediation Adapters) via Google Mobile Ads Bidding & Waterfall mediation. No Dart code changes are requiredβall mediation adapters hook directly into the underlying Google Mobile Ads SDK lifecycle.
Caution
Why is Bidding Reporting 0.00% Bids in AdMob Dashboard?
If your Mediation report shows 0.00% Bids for Unity Ads, AppLovin, or Pangle:
The native mediation adapter binaries were not added to your host app's build.gradle.kts (Android) and Podfile (iOS).
In-app Bidding requires native SDK binaries in the compiled binary so Google AdMob can request real-time bids. Add the snippets below to enable Bidding immediately:
Android Configuration (android/app/build.gradle.kts): #
dependencies {
// Google Mobile Ads Mediation Adapters
implementation("com.google.ads.mediation:applovin:13.1.0.0")
implementation("com.google.ads.mediation:facebook:6.19.0.0")
implementation("com.google.ads.mediation:mintegral:16.9.71.0")
implementation("com.google.ads.mediation:unity:4.13.2.0")
implementation("com.google.ads.mediation:pangle:6.4.0.6.0")
}
iOS Configuration (ios/Podfile): #
target 'Runner' do
# Google Mobile Ads Mediation Adapters
pod 'GoogleMobileAdsMediationAppLovin'
pod 'GoogleMobileAdsMediationFacebook'
pod 'GoogleMobileAdsMediationMintegral'
pod 'GoogleMobileAdsMediationUnity'
pod 'GoogleMobileAdsMediationPangle'
end
π For complete step-by-step setup, Maven repositories, ProGuard rules, SKAdNetworkItems, and Ad Inspector verification, see:
doc/MEDIATION_SETUP_GUIDE.md