On this page14 sections
Lecture 005 — Interstitial Ads
| Category | 2 — Banner & Full-Screen Ads |
| Lecture | 005 of 010 |
| Estimated video length | 20 min |
| Target | Flutter 3.44 · Dart 3.12 · google_mobile_ads 9 |
| Level | Beginner |
| Source code | GitHub — urraan_admob_final |
An interstitial covers the whole screen, so timing is everything. We show it at a natural pause — when the user leaves a screen — and carry on with the navigation when it is closed.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Prerequisites
Lectures 001–004; PopScope, callbacks.
Connection With Previous Lectures
The banner sat quietly. The interstitial interrupts, so we need callbacks: what to do when it opens, when it closes, and when it fails.
Learning Objectives
By the end of this lecture you will be able to:
- Load and show an interstitial
- Use
FullScreenContentCallbackfor shown, dismissed and failed - Preload the next ad after one is shown
- Continue the user's action after the ad closes
Lesson
1. The Helper
// lib/admob/interstitial_ad_helper.dart
import 'package:flutter/foundation.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'admob_manager.dart';
class InterstitialAdHelper {
bool isAdLoaded = false;
InterstitialAd? _interstitialAd;
void loadInterstitialAd({
required VoidCallback onAdDismissed,
required VoidCallback onAdShowFullScreen,
}) {
InterstitialAd.load(
adUnitId: AdmobManager.interstitialId,
request: const AdRequest(),
adLoadCallback: InterstitialAdLoadCallback(
onAdLoaded: (ad) {
isAdLoaded = true;
_interstitialAd = ad;
ad.fullScreenContentCallback = FullScreenContentCallback(
onAdShowedFullScreenContent: (_) => onAdShowFullScreen(),
onAdDismissedFullScreenContent: (ad) {
ad.dispose();
isAdLoaded = false;
_interstitialAd = null;
onAdDismissed();
// Load the next one so it is ready next time.
loadInterstitialAd(
onAdDismissed: onAdDismissed,
onAdShowFullScreen: onAdShowFullScreen,
);
},
onAdFailedToShowFullScreenContent: (ad, error) {
ad.dispose();
isAdLoaded = false;
_interstitialAd = null;
},
);
},
onAdFailedToLoad: (error) {
isAdLoaded = false;
debugPrint('Interstitial failed: ${error.code} ${error.message}');
},
),
);
}
void showAdIfAvailable() {
if (_interstitialAd != null && isAdLoaded) {
_interstitialAd!.show();
isAdLoaded = false;
}
}
void dispose() => _interstitialAd?.dispose();
}- Load early, show later.
loadis asynchronous; we call it ininitStateso the ad is ready when needed. - An interstitial can be shown once. After it closes we
disposeit and load the next. onAdShowFullScreenandonAdDismissedare callbacks the screen provides — the helper does not know about navigation.onAdFailedToShowFullScreenContentcleans up so a broken ad is not reused.
2. The Shared Flag
An interstitial and an app-open ad must not collide. This tiny class records "a full-screen ad was just shown":
// lib/admob/ad_state.dart
/// Shared flag: while a full-screen ad is showing (and for 30 seconds after),
/// the app-open ad must stay quiet.
class AdState {
static final AdState _instance = AdState._internal();
factory AdState() => _instance;
AdState._internal();
bool isOtherAdsDisabled = false;
void disableAppOpenAds() => isOtherAdsDisabled = true;
/// Re-enable app-open ads after a cooldown.
void enableAppOpenAdsAfterCooldown({
Duration cooldown = const Duration(seconds: 30),
}) {
Future.delayed(cooldown, () => isOtherAdsDisabled = false);
}
}Lecture 006 reads it; here we only set it.
3. The Screen
// lib/screen_interstitials.dart
import 'package:flutter/material.dart';
import 'admob/ad_state.dart';
import 'admob/interstitial_ad_helper.dart';
class ScreenInterstitials extends StatefulWidget {
const ScreenInterstitials({super.key});
@override
State<ScreenInterstitials> createState() => _ScreenInterstitialsState();
}
class _ScreenInterstitialsState extends State<ScreenInterstitials> {
final interstitialAdHelper = InterstitialAdHelper();
@override
void initState() {
super.initState();
interstitialAdHelper.loadInterstitialAd(
onAdDismissed: () {
AdState().enableAppOpenAdsAfterCooldown();
_doNextFunctionality();
},
onAdShowFullScreen: () => AdState().disableAppOpenAds(),
);
}
@override
void dispose() {
interstitialAdHelper.dispose();
super.dispose();
}
void _doNextFunctionality() {
if (mounted) Navigator.pop(context);
}
void _onBack() {
if (interstitialAdHelper.isAdLoaded) {
interstitialAdHelper.showAdIfAvailable();
} else {
_doNextFunctionality();
}
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, _) {
if (!didPop) _onBack();
},
child: Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: _onBack,
icon: const Icon(Icons.arrow_back_rounded),
),
title: const Text('Second Screen'),
),
body: const Center(child: Text('Press back to see the interstitial')),
),
);
}
}- Back press and the arrow both call
_onBack: show the ad if ready, otherwise leave at once. The user is never blocked by an ad that has not loaded. - When the ad closes,
onAdDismissedruns_doNextFunctionality(here,Navigator.pop). PopScope(canPop: false)lets us intercept the system back gesture too.
Code Examples
Example 1 — Frequency
Showing an interstitial on every back press annoys users and lowers ratings. A simple
rule: show one at most every few minutes, or every third action. Keep a counter or a
DateTime lastShown in AdState and skip the ad when it is too soon.
Common Beginner Mistakes
1. Loading when about to show — the ad is not ready; load early.
2. Showing the same ad twice — an ad object is single-use; load a new one.
3. Showing at app start or on a button tap that expects a result — policy and user experience problems. Show at natural breaks only.
4. Forgetting to continue navigation — if the ad fails, the user must still be able to leave.
Best Practices
- Show interstitials between tasks, never in the middle of one
- Always continue the flow whether or not the ad shows
- Limit the frequency
Mini Challenge
Add a counter in AdState so the interstitial shows only on every second visit to the screen.
Practice Questions
- Why load in
initState? - Why can an interstitial only be used once?
- What happens if the ad is not loaded when Back is pressed?
- What is
PopScopefor here?
Practice Answers
- So it is ready when needed.
- The SDK releases it after showing.
- The screen closes immediately.
- To handle the system back gesture.
Key Takeaways
- Load early, show at natural pauses
- Callbacks continue the user's flow
- Dispose and reload after each show