flutter_next_gen_ads
Flutter wrapper for the Google Mobile Ads (GMA) Next-Gen SDK 1.0+ — Banner, Interstitial, Rewarded Interstitial, and App Open ads on Android.
⚠️ Android only. The GMA Next-Gen SDK is currently GA on Android only. For iOS, combine this package with
google_mobile_ads.⚠️ Unofficial. This package is not affiliated with, endorsed by, or sponsored by Google. AdMob, Google Mobile Ads, and Flutter are trademarks of Google LLC. This plugin wraps the publicly distributed GMA Next-Gen SDK for convenience.
Why this package?
The official google_mobile_ads plugin still uses the legacy GMA SDK at
the time of writing. If you want Next-Gen SDK features today on Android —
notably the InterstitialAdPreloader / RewardedInterstitialAdPreloader
pool-based preloaders that the legacy SDK lacks — this is the shortest path.
Requirements
| Flutter | ≥ 3.10 |
| Dart | ≥ 3.10.7 |
Android compileSdk |
35 |
Android minSdk |
24 |
| Kotlin | ≥ 1.9 |
Install
Add the package to your pubspec.yaml:
dependencies:
flutter_next_gen_ads: ^0.1.0
Add your AdMob app ID to android/app/src/main/AndroidManifest.xml:
<application ...>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-XXXXXXXXXXXXXXXX~YYYYYYYYYY"/>
...
</application>
Use AdMob's test ID
ca-app-pub-3940256099942544~3347511713for local development. Replace before shipping.
Quick start
Initialize once at app startup
import 'package:flutter_next_gen_ads/flutter_next_gen_ads.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await MobileAds.initialize(); // reads appId from AndroidManifest
// CRITICAL during development: register your dev device so real ads
// don't accidentally serve and trigger AdMob policy violations.
await MobileAds.setRequestConfiguration(const RequestConfiguration(
testDeviceIds: ['YOUR_DEVICE_HASH'], // grep logcat for the hash
));
runApp(const MyApp());
}
Banner ad
SizedBox(
height: 120,
child: BannerAdView(
adUnitId: 'ca-app-pub-XXX/YYY',
size: AdSize.largeAnchored(),
),
)
Or use the convenience height: param:
const BannerAdView(
adUnitId: 'ca-app-pub-XXX/YYY',
size: AdSize.largeAnchored(),
height: 120,
)
Interstitial ad
try {
final ad = await InterstitialAd.load(
adUnitId: 'ca-app-pub-XXX/YYY',
);
ad.listener = InterstitialAdListener(
onAdDismissedFullScreenContent: () => debugPrint('dismissed'),
);
await ad.show();
} on AdLoadException catch (e) {
debugPrint('load failed: ${e.error}');
}
Rewarded interstitial ad
try {
final ad = await RewardedInterstitialAd.load(
adUnitId: 'ca-app-pub-XXX/YYY',
);
await ad.show(
onUserEarnedReward: (reward) {
grantCoins(reward.amount); // reward.type also available
},
);
} on AdLoadException catch (e) {
debugPrint('rewarded failed: ${e.error}');
}
App open ad (with 4-hour expiry handling)
class _RootState extends State<RootWidget> with WidgetsBindingObserver {
AppOpenAd? _ad;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_preload();
}
Future<void> _preload() async {
try {
_ad = await AppOpenAd.load(adUnitId: 'ca-app-pub-XXX/YYY');
_ad!.listener = AppOpenAdListener(
onAdDismissedFullScreenContent: () {
_ad = null;
_preload();
},
);
} on AdLoadException catch (_) {}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
if (state == AppLifecycleState.resumed) {
final ad = _ad;
if (ad != null && await ad.isAvailable()) await ad.show();
}
}
// ...
}
Preloader pool (Next-Gen exclusive)
Keep a pool of interstitial / rewarded ads ready so show() returns
instantly instead of waiting on a network round trip.
// Startup: fill the pool
await InterstitialAdPreloader.start(
adUnitId: 'ca-app-pub-XXX/YYY',
bufferSize: 2,
);
// Show time: poll the pool; fall back to a fresh load if empty
InterstitialAd? ad = await InterstitialAdPreloader.poll(
adUnitId: 'ca-app-pub-XXX/YYY',
);
ad ??= await InterstitialAd.load(adUnitId: 'ca-app-pub-XXX/YYY');
await ad.show();
Ad targeting hints
const request = AdRequest(
keywords: ['flutter', 'mobile-dev'],
contentUrl: 'https://example.com/article-being-read',
customTargeting: {'genre': ['action', 'adventure']},
);
final ad = await InterstitialAd.load(
adUnitId: 'ca-app-pub-XXX/YYY',
request: request,
);
Cross-platform usage (Android + iOS)
This plugin is Android-only. For iOS in the same codebase, conditionally
fall back to google_mobile_ads:
import 'dart:io' show Platform;
Future<void> showInterstitial(String adUnitId) async {
if (Platform.isAndroid) {
// Use flutter_next_gen_ads
final ad = await InterstitialAd.load(adUnitId: adUnitId);
await ad.show();
} else if (Platform.isIOS) {
// Use google_mobile_ads (separate setup required)
// ...
}
}
The BannerAdView widget collapses to its placeholder on non-Android
platforms automatically, so layouts keep working.
API surface
Re-exported from package:flutter_next_gen_ads/flutter_next_gen_ads.dart:
MobileAds—initialize(),getVersion(),setRequestConfiguration()RequestConfiguration+ enums (TagForChildDirectedTreatment,TagForUnderAgeOfConsent,MaxAdContentRating,PublisherPrivacyPersonalizationState)BannerAdView,BannerAdListener,AdSize(anchored,largeAnchored,inlinefactories)InterstitialAd,InterstitialAdListenerRewardedInterstitialAd,RewardedInterstitialAdListener,RewardItemAppOpenAd,AppOpenAdListenerInterstitialAdPreloader,RewardedInterstitialAdPreloaderAdRequest,AdError,AdLoadException
Roadmap
- 0.2.0 — Native ads (
NativeAd,NativeAdView,NativeAdPreloader). - 0.3.0+ — iOS support (when GMA Next-Gen iOS SDK reaches GA).
Troubleshooting
Banner shows blank space. BannerAdView needs explicit bounded
constraints from its immediate parent. Wrap in SizedBox(height: …) or pass
the height: parameter — without bounds Flutter silently skips PlatformView
creation.
AdLoadException(code: 3, message: No fill). AdMob has no inventory for
your test request right now. Most test units always return ads, so retry or
verify the ad unit ID.
App killed shortly after launch on emulator. The GMA SDK + WebView is ~300 MB at runtime. Emulators with < 4 GB RAM may OOM. Use a real device or allocate more emulator memory.
Real device sees real ads, not test ads. Call
MobileAds.setRequestConfiguration(RequestConfiguration(testDeviceIds: [...]))
before loading any ads. Find your device's hash in logcat — search for
Use RequestConfiguration.Builder.setTestDeviceIds.
Sponsor
If this package saved you a day of work, consider sponsoring a day of mine.
Your sponsorship funds:
- 0.2.0 Native ads — in active development
- Bug fixes & SDK upgrades — keeping pace with Google releases
- Issue & PR triage — replying within days, not weeks
Built and maintained by Hamlet Shu — an independent Flutter developer based in Seoul, Korea.
License
MIT — see LICENSE.
Libraries
- flutter_next_gen_ads
- Flutter wrapper around the Google Mobile Ads (GMA) Next-Gen SDK 1.0+.