On this page14 sections
Lecture 008 — Rewarded Ads
| Category | 3 — Native & Rewarded Ads |
| Lecture | 008 of 010 |
| Estimated video length | 22 min |
| Target | Flutter 3.44 · Dart 3.12 · google_mobile_ads 9 |
| Level | Beginner |
| Source code | GitHub — urraan_admob_final |
A rewarded ad is the user's choice: watch a short ad, get something — coins, an extra try, an unlocked file. Because the user chose it, it is the best-liked ad format.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Prerequisites
Lectures 001–005.
Connection With Previous Lectures
Interstitials interrupt the user. Rewarded ads let the user say yes first — that is why the button text matters.
Learning Objectives
By the end of this lecture you will be able to:
- Load and show a
RewardedAd - Receive the reward in
onUserEarnedReward - Handle "not ready" gracefully
- Explain the flow before the ad
Lesson
1. The Helper
// lib/admob/rewarded_ad_helper.dart
import 'package:flutter/foundation.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'admob_manager.dart';
class RewardedAdHelper {
bool isAdLoaded = false;
RewardedAd? _rewardedAd;
void loadRewardedAd({
required VoidCallback onAdShowFullScreen,
required VoidCallback onAdDismissed,
}) {
RewardedAd.load(
adUnitId: AdmobManager.rewardedId,
request: const AdRequest(),
rewardedAdLoadCallback: RewardedAdLoadCallback(
onAdLoaded: (ad) {
isAdLoaded = true;
_rewardedAd = ad;
ad.fullScreenContentCallback = FullScreenContentCallback(
onAdShowedFullScreenContent: (_) => onAdShowFullScreen(),
onAdDismissedFullScreenContent: (ad) {
ad.dispose();
isAdLoaded = false;
_rewardedAd = null;
onAdDismissed();
loadRewardedAd(
onAdShowFullScreen: onAdShowFullScreen,
onAdDismissed: onAdDismissed,
);
},
onAdFailedToShowFullScreenContent: (ad, error) {
ad.dispose();
isAdLoaded = false;
_rewardedAd = null;
},
);
},
onAdFailedToLoad: (error) {
isAdLoaded = false;
debugPrint('Rewarded failed: ${error.code} ${error.message}');
},
),
);
}
/// Returns false when no ad is ready, so the screen can tell the user.
bool showAdIfAvailable(void Function(RewardItem reward) onEarnedReward) {
if (_rewardedAd == null || !isAdLoaded) return false;
_rewardedAd!.show(
onUserEarnedReward: (_, reward) => onEarnedReward(reward),
);
return true;
}
void dispose() => _rewardedAd?.dispose();
}showAdIfAvailablereturnstrueif it showed the ad,falseif none was ready.- The reward arrives in
onUserEarnedReward— grant it there, not when the ad closes, because a user who skips early gets no reward. - After dismissal we load the next ad.
2. The Screen
// lib/screen_rewarded_ads.dart
import 'package:flutter/material.dart';
import 'admob/ad_state.dart';
import 'admob/rewarded_ad_helper.dart';
class ScreenRewardedAds extends StatefulWidget {
const ScreenRewardedAds({super.key});
@override
State<ScreenRewardedAds> createState() => _ScreenRewardedAdsState();
}
class _ScreenRewardedAdsState extends State<ScreenRewardedAds> {
final rewardedAdHelper = RewardedAdHelper();
int _coins = 0;
@override
void initState() {
super.initState();
rewardedAdHelper.loadRewardedAd(
onAdShowFullScreen: () => AdState().disableAppOpenAds(),
onAdDismissed: () => AdState().enableAppOpenAdsAfterCooldown(),
);
}
@override
void dispose() {
rewardedAdHelper.dispose();
super.dispose();
}
void _watchAd() {
final shown = rewardedAdHelper.showAdIfAvailable((reward) {
setState(() => _coins += reward.amount.toInt());
});
if (!shown) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Ad is not ready yet, try again')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Rewarded Ads')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Coins: $_coins', style: const TextStyle(fontSize: 24)),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _watchAd,
child: const Text('Watch an ad to earn coins'),
),
],
),
),
);
}
}_coins += reward.amountruns only when the reward is earned.- If no ad is ready, a
SnackBarexplains; the user is never silently ignored.
3. Be Clear Before the Ad
The button text should say what happens: "Watch an ad to earn coins". If the text is not clear, show a short dialog first (see the next lecture).
Code Examples
Example 1 — The Reward Item
RewardItem has an amount and a type set in the AdMob dashboard when you create the ad
unit (for example coins / 10). Test ads return a small default value.
Common Beginner Mistakes
1. Giving the reward on dismiss — users who close early would be rewarded unfairly.
2. Showing a rewarded ad without a clear button — users feel tricked; policy risk.
3. Ignoring "not ready" — the button seems broken.
4. Not disposing.
Best Practices
- Make the reward obvious in the button text
- Grant the reward only in
onUserEarnedReward - Handle a not-ready ad with a message
Mini Challenge
Disable the button until rewardedAdHelper.isAdLoaded is true (use setState from the load callback).
Practice Questions
- Where is the reward granted?
- What does
showAdIfAvailablereturn? - Why a clear button?
- What dashboard value defines the reward?
Practice Answers
onUserEarnedReward.- Whether the ad was shown.
- So users know they are choosing to watch.
- The reward amount and type on the ad unit.
Key Takeaways
- Rewarded = user choice + reward callback
- Always handle not-ready
- Clear text beats surprise