Native Google Ads
A Flutter plugin for integrating Google Mobile Ads (AdMob) using native platform implementations. This plugin provides a simple and efficient way to display banner, native, interstitial, and rewarded ads in your Flutter applications.
Features
- ✅ Native Implementation - Direct integration with Google Mobile Ads SDK
- ✅ iOS & Android Support - Full support for both platforms
- ✅ Banner Ads - Display banner ads in various sizes including adaptive
- ✅ Native Ads - Show native ads using simple default layouts
- ✅ Interstitial Ads - Full-screen ads at natural transition points
- ✅ Rewarded Ads - Reward users for watching video ads
- ✅ Platform Views - Native ad rendering using platform-specific views
- ✅ Comprehensive Callbacks - Full lifecycle event handling
- ✅ Swift Package Manager - Modern iOS dependency management
- ✅ Kotlin Support - Modern Android implementation
Platform Support
Platform | Minimum Version | Architecture |
---|---|---|
Android | API 24 (7.0) | Kotlin |
iOS | 13.0 | Swift |
Installation
Add native_googleads
to your pubspec.yaml
:
dependencies:
native_googleads: ^0.0.1
Then run:
flutter pub get
Platform Setup
Android Setup
1. Update android/app/build.gradle
Ensure your minimum SDK version is at least 24:
android {
defaultConfig {
minSdkVersion 24
// ... other configurations
}
}
2. Add AdMob App ID to AndroidManifest.xml
Add your AdMob App ID to android/app/src/main/AndroidManifest.xml
:
<manifest>
<application>
<!-- Add your AdMob App ID here -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
</application>
</manifest>
Note: Use test App ID
ca-app-pub-3940256099942544~3347511713
for development
iOS Setup
1. Update iOS Deployment Target (or Swift Package Manager)
In your ios/Podfile
, ensure the platform version is at least 13.0:
platform :ios, '13.0'
2. Add AdMob App ID to Info.plist
Add the following to your ios/Runner/Info.plist
:
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy</string>
<!-- For iOS 14+ App Tracking Transparency -->
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>
<!-- Required SKAdNetwork identifiers -->
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<!-- Add other SKAdNetwork identifiers as needed -->
</array>
Note: Use test App ID
ca-app-pub-3940256099942544~1458002511
for development
3. Update iOS Pods
cd ios
pod install
Usage
Basic Usage
import 'package:native_googleads/native_googleads.dart';
// Get the singleton instance
final ads = NativeGoogleads.instance;
// Initialize with App ID (use platform test App ID during development)
await ads.initialize(appId: 'your-app-id');
// Load and show a banner ad (programmatic API)
final bannerId = await ads.loadBannerAd(
adUnitId: 'your-banner-ad-unit-id',
size: BannerAdSize.adaptive,
);
if (bannerId != null) {
await ads.showBannerAd(bannerId);
}
// Load and show a native ad (programmatic API)
final nativeAdId = await ads.loadNativeAd(
adUnitId: 'your-native-ad-unit-id',
);
if (nativeAdId != null) {
await ads.showNativeAd(nativeAdId);
}
// Preload and show interstitial ad
await ads.preloadInterstitialAd(
adUnitId: 'your-interstitial-ad-unit-id',
);
await ads.showInterstitialAd(adUnitId: 'your-interstitial-ad-unit-id');
// Preload and show rewarded ad
await ads.preloadRewardedAd(
adUnitId: 'your-rewarded-ad-unit-id',
);
await ads.showRewardedAd(adUnitId: 'your-rewarded-ad-unit-id');
Caching
This plugin preloads and caches full-screen ads at the platform level per adUnitId
.
- Preload: call
preloadInterstitialAd(adUnitId)
orpreloadRewardedAd(adUnitId)
ahead of time. - Check: use
isInterstitialReady(adUnitId)
orisRewardedReady(adUnitId)
before showing. - Show: call
showInterstitialAd(adUnitId: ...)
orshowRewardedAd(adUnitId: ...)
. - Auto-preload: after an ad is dismissed or fails to show, the native layer auto-preloads the next ad for the same
adUnitId
to keep a warm cache.
Best practices:
- Preload during app start or at natural pauses (e.g., level start).
- Always check readiness for smoother UX; if not ready, delay or show alternative UI.
- Use one
adUnitId
per placement; the cache holds one ready ad per type peradUnitId
.
Preload → Check → Show (with auto-preload)
import 'dart:io';
import 'package:native_googleads/native_googleads.dart';
final ads = NativeGoogleads.instance;
late final String interstitialId;
Future<void> initAds() async {
interstitialId = Platform.isAndroid
? AdTestIds.androidInterstitial
: AdTestIds.iosInterstitial;
// 1) Initialize and preload early
await ads.initialize(appId: Platform.isAndroid
? AdTestIds.androidAppId
: AdTestIds.iosAppId);
await ads.preloadInterstitialAd(adUnitId: interstitialId);
// Optional: listen for lifecycle to reflect auto-preload
ads.setAdCallbacks(
onAdDismissed: (type) async {
if (type == 'interstitial') {
await Future.delayed(const Duration(milliseconds: 200));
final ready = await ads.isInterstitialReady(interstitialId);
// Update UI state accordingly
}
},
);
}
Future<void> maybeShowInterstitial() async {
// 2) Check readiness before showing
final ready = await ads.isInterstitialReady(interstitialId);
if (!ready) {
await ads.preloadInterstitialAd(adUnitId: interstitialId);
return;
}
// 3) Show when ready
await ads.showInterstitialAd(adUnitId: interstitialId);
}
Use the same pattern for rewarded ads with preloadRewardedAd
, isRewardedReady
, and showRewardedAd(adUnitId: ...)
.
Using Test Ads
For development, always use test ad unit IDs:
import 'dart:io';
// Use test IDs during development
final testAdUnitId = Platform.isAndroid
? AdTestIds.androidInterstitial // Test interstitial for Android
: AdTestIds.iosInterstitial; // Test interstitial for iOS
await ads.preloadInterstitialAd(adUnitId: testAdUnitId);
Available test IDs:
AdTestIds.androidInterstitial
/AdTestIds.iosInterstitial
AdTestIds.androidRewarded
/AdTestIds.iosRewarded
AdTestIds.androidBanner
/AdTestIds.iosBanner
AdTestIds.androidNativeAdvanced
/AdTestIds.iosNativeAdvanced
Setting Up Callbacks
ads.setAdCallbacks(
onAdDismissed: (adType) {
print('Ad dismissed: $adType');
// Handle ad dismissal
},
onAdShowed: (adType) {
print('Ad showed: $adType');
// Handle ad display
},
onAdFailedToShow: (adType, error) {
print('Ad failed: $adType, error: $error');
// Handle ad failure
},
onUserEarnedReward: (type, amount) {
print('Reward earned: $amount $type');
// Grant reward to user
},
);
Working with Banner Ads
Banner ads can be displayed in various sizes:
// Available banner sizes
BannerAdSize.banner // 320x50
BannerAdSize.largeBanner // 320x100
BannerAdSize.mediumRectangle // 300x250
BannerAdSize.fullBanner // 468x60
BannerAdSize.leaderboard // 728x90
BannerAdSize.adaptive // Adaptive size based on device width
// Load a banner ad (programmatic API)
final bannerId = await ads.loadBannerAd(
adUnitId: Platform.isAndroid
? AdTestIds.androidBanner
: AdTestIds.iosBanner,
size: BannerAdSize.adaptive,
);
// Show the banner (programmatic API)
if (bannerId != null) {
await ads.showBannerAd(bannerId);
}
// Hide the banner (keeps it loaded)
await ads.hideBannerAd(bannerId);
// Dispose when no longer needed
await ads.disposeBannerAd(bannerId);
You can also use the BannerAdWidget
for easier integration:
BannerAdWidget(
adUnitId: AdTestIds.androidBanner,
size: BannerAdSize.adaptive,
onAdLoaded: () => print('Banner loaded'),
onAdFailedToLoad: (error) => print('Banner failed: $error'),
)
Note:
- When using
BannerAdWidget
, do not callshowBannerAd
/hideBannerAd
— the PlatformView handles attaching/detaching the banner. - On iOS, the programmatic
showBannerAd
attaches the banner to the root view controller, not inside a widget tree. - If you preloaded via
loadBannerAd(...)
, you can render that ad by passingpreloadedBannerId
to the widget:BannerAdWidget(preloadedBannerId: bannerId, ...)
.
Working with Native Ads
Native ads allow you to customize the ad appearance to match your app:
// Load a native ad (programmatic API)
final nativeAdId = await ads.loadNativeAd(
adUnitId: Platform.isAndroid
? AdTestIds.androidNativeAdvanced
: AdTestIds.iosNativeAdvanced,
);
// Show the native ad (programmatic API)
if (nativeAdId != null) {
await ads.showNativeAd(nativeAdId);
}
// Dispose when no longer needed
await ads.disposeNativeAd(nativeAdId);
Use the NativeAdWidget
for easier integration:
NativeAdWidget(
adUnitId: AdTestIds.androidNativeAdvanced,
height: 300,
backgroundColor: Colors.white,
onAdLoaded: () => print('Native ad loaded'),
onAdFailedToLoad: (error) => print('Native ad failed: $error'),
)
Note:
- If you preloaded via
loadNativeAd(...)
, you can render that ad by passingpreloadedNativeAdId
to the widget:NativeAdWidget(preloadedNativeAdId: nativeId, ...)
.
Complete Example
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:native_googleads/native_googleads.dart';
class AdExample extends StatefulWidget {
@override
_AdExampleState createState() => _AdExampleState();
}
class _AdExampleState extends State<AdExample> {
final NativeGoogleads _ads = NativeGoogleads.instance;
bool _interstitialReady = false;
bool _rewardedReady = false;
int _rewardAmount = 0;
@override
void initState() {
super.initState();
_initializeAds();
}
Future<void> _initializeAds() async {
// Set up callbacks
_ads.setAdCallbacks(
onAdDismissed: (adType) {
setState(() {
if (adType == 'interstitial') _interstitialReady = false;
if (adType == 'rewarded') _rewardedReady = false;
});
},
onUserEarnedReward: (type, amount) {
setState(() {
_rewardAmount += amount;
});
},
);
// Initialize with test App ID for development
await _ads.initialize(appId: Platform.isAndroid
? AdTestIds.androidAppId
: AdTestIds.iosAppId);
}
Future<void> _preloadInterstitialAd() async {
final adUnitId = Platform.isAndroid
? AdTestIds.androidInterstitial
: AdTestIds.iosInterstitial;
final success = await _ads.preloadInterstitialAd(adUnitId: adUnitId);
setState(() => _interstitialReady = success);
}
Future<void> _showInterstitialAd() async {
if (_interstitialReady) {
await _ads.showInterstitialAd(adUnitId: Platform.isAndroid
? AdTestIds.androidInterstitial
: AdTestIds.iosInterstitial);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Native Google Ads Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Rewards: $_rewardAmount'),
ElevatedButton(
onPressed: _preloadInterstitialAd,
child: Text('Preload Interstitial'),
),
ElevatedButton(
onPressed: _interstitialReady ? _showInterstitialAd : null,
child: Text('Show Interstitial'),
),
],
),
),
);
}
}
API Reference
NativeGoogleads
Method | Description | Parameters | Returns |
---|---|---|---|
initialize |
Initialize the ads SDK | appId: String? |
Future<Map<String, dynamic>?> |
loadBannerAd |
Load a banner ad | adUnitId: String , size: BannerAdSize |
Future<String?> |
showBannerAd |
Show loaded banner | bannerId: String |
Future<bool> |
hideBannerAd |
Hide loaded banner | bannerId: String |
Future<bool> |
disposeBannerAd |
Dispose banner ad | bannerId: String |
Future<bool> |
loadNativeAd |
Load a native ad | adUnitId: String |
Future<String?> |
showNativeAd |
Show loaded native ad | nativeAdId: String |
Future<bool> |
disposeNativeAd |
Dispose native ad | nativeAdId: String |
Future<bool> |
preloadInterstitialAd |
Preload an interstitial | adUnitId: String |
Future<bool> |
isInterstitialReady |
Check if interstitial ready | adUnitId: String |
Future<bool> |
showInterstitialAd |
Show preloaded interstitial | adUnitId: String |
Future<bool> |
preloadRewardedAd |
Preload a rewarded ad | adUnitId: String |
Future<bool> |
isRewardedReady |
Check if rewarded is ready | adUnitId: String |
Future<bool> |
showRewardedAd |
Show preloaded rewarded ad | adUnitId: String |
Future<bool> |
setAdCallbacks |
Set ad event callbacks | Various callbacks | void |
BannerAdSize
Enum for banner ad sizes:
Size | Description | Dimensions | Notes |
---|---|---|---|
banner |
Standard banner | 320x50 | Works on all devices |
largeBanner |
Large banner | 320x100 | Works on all devices |
mediumRectangle |
Medium rectangle | 300x250 | Works on most devices |
fullBanner |
Full banner | 468x60 | Requires tablet or landscape |
leaderboard |
Leaderboard | 728x90 | Requires tablet or large screen |
adaptive |
Adaptive banner | Width based on device | Recommended for best fit |
Note: The widget automatically validates banner sizes and will use a smaller size if the requested size doesn't fit the screen width. For example:
- Leaderboard (728px) on phones → uses Adaptive size
- Full Banner (468px) on small phones → uses Banner size
Testing
The plugin includes test ad unit IDs from Google. Always use test ads during development:
// Use test ad unit IDs
final testInterstitial = Platform.isAndroid
? AdTestIds.androidInterstitial
: AdTestIds.iosInterstitial;
Production ID Validation
To help prevent accidental use of Google test ad unit IDs in release:
- Default: warns in release if a test ad unit ID is used.
- Strict mode: throws an error in release when a test ad unit ID is used.
- Disable: you can disable the check if needed.
// Warn-only (default)
NativeGoogleads.instance.setAdIdValidationPolicy(
disallowTestIdsInRelease: true,
strict: false,
);
// Strict: throw in release when using test IDs
NativeGoogleads.instance.setAdIdValidationPolicy(strict: true);
// Disable check
NativeGoogleads.instance.setAdIdValidationPolicy(
disallowTestIdsInRelease: false,
);
Troubleshooting
Common Issues
-
Ads not loading
- Ensure you have a valid AdMob account
- Verify your App ID and Ad Unit IDs are correct
- Check internet connectivity
- For iOS, ensure App Tracking Transparency is handled
-
Build errors on Android
- Verify minimum SDK is 24 or higher
- Run
flutter clean
and rebuild
-
Build errors on iOS
- Ensure deployment target is iOS 13.0+
- Run
pod install
in the ios directory - Clean build folder in Xcode
-
Test ads not showing
- Use test App IDs and ad unit IDs
- Check console logs for error messages
- Ensure proper initialization
Migration Guide
If you're migrating from another ads plugin:
- Remove the old plugin from
pubspec.yaml
- Follow the platform setup instructions above
- Replace initialization and ad loading code
- Update ad unit IDs and callbacks
- Test thoroughly with test ads first
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature
) - Commit your changes (
git commit -m 'Add some AmazingFeature'
) - Push to the branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For issues and feature requests, please use the GitHub issue tracker.
Acknowledgments
- Google Mobile Ads SDK team
- Flutter community
- All contributors
Changelog
See CHANGELOG.md for version history.
Made with ❤️ by Your Name