Skip to content

Commit

Permalink
Added UMP SDK integration to Rewarded sample (#1071)
Browse files Browse the repository at this point in the history
* Added UMP SDK integration to Rewarded sample

* Only resume if paused

* app bar widget

* 5.1.0

---------

Co-authored-by: Justin Malandruccolo <[email protected]>
  • Loading branch information
malandr2 and Justin Malandruccolo authored May 9, 2024
1 parent 6ea3fe3 commit 74f7aed
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 11 deletions.
51 changes: 51 additions & 0 deletions samples/admob/rewarded_example/lib/consent_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'dart:async';

import 'package:google_mobile_ads/google_mobile_ads.dart';

typedef OnConsentGatheringCompleteListener = void Function(FormError? error);

/// The Google Mobile Ads SDK provides the User Messaging Platform (Google's IAB
/// Certified consent management platform) as one solution to capture consent for
/// users in GDPR impacted countries. This is an example and you can choose
/// another consent management platform to capture consent.
class ConsentManager {
/// Helper variable to determine if the app can request ads.
Future<bool> canRequestAds() async {
return await ConsentInformation.instance.canRequestAds();
}

/// Helper variable to determine if the privacy options form is required.
Future<bool> isPrivacyOptionsRequired() async {
return await ConsentInformation.instance
.getPrivacyOptionsRequirementStatus() ==
PrivacyOptionsRequirementStatus.required;
}

/// Helper method to call the Mobile Ads SDK to request consent information
/// and load/show a consent form if necessary.
void gatherConsent(
OnConsentGatheringCompleteListener onConsentGatheringCompleteListener) {
// For testing purposes, you can force a DebugGeography of Eea or NotEea.
ConsentDebugSettings debugSettings = ConsentDebugSettings(
debugGeography: DebugGeography.debugGeographyEea,
);
ConsentRequestParameters params =
ConsentRequestParameters(consentDebugSettings: debugSettings);

// Requesting an update to consent information should be called on every app launch.
ConsentInformation.instance.requestConsentInfoUpdate(params, () async {
ConsentForm.loadAndShowConsentFormIfRequired((loadAndShowError) {
// Consent has been gathered.
onConsentGatheringCompleteListener(loadAndShowError);
});
}, (FormError formError) {
onConsentGatheringCompleteListener(formError);
});
}

/// Helper method to call the Mobile Ads SDK method to show the privacy options form.
void showPrivacyOptionsForm(
OnConsentFormDismissedListener onConsentFormDismissedListener) {
ConsentForm.showPrivacyOptionsForm(onConsentFormDismissedListener);
}
}
26 changes: 22 additions & 4 deletions samples/admob/rewarded_example/lib/countdown_timer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,45 @@ import 'package:flutter/material.dart';
enum CountdownState {
notStarted,
active,
paused,
ended,
}

/// A simple class that keeps track of a decrementing timer.
class CountdownTimer extends ChangeNotifier {
final _countdownTime = 10;
final _countdownTime = 5;
late var timeLeft = _countdownTime;
var _countdownState = CountdownState.notStarted;
Timer? _timer;

bool get isComplete => _countdownState == CountdownState.ended;

void start() {
timeLeft = _countdownTime;
_resumeTimer();
_startTimer();
_countdownState = CountdownState.active;

notifyListeners();
}

void _resumeTimer() {
Timer.periodic(const Duration(seconds: 1), (timer) {
void resume() {
if (_countdownState != CountdownState.paused) {
return;
}
_startTimer();
_countdownState = CountdownState.active;
}

void pause() {
if (_countdownState != CountdownState.active) {
return;
}
_timer?.cancel();
_countdownState = CountdownState.paused;
}

void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
timeLeft--;

if (timeLeft == 0) {
Expand Down
117 changes: 111 additions & 6 deletions samples/admob/rewarded_example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

import 'consent_manager.dart';

void main() {
WidgetsFlutterBinding.ensureInitialized();
MobileAds.instance.initialize();
runApp(const MaterialApp(
home: RewardedExample(),
));
Expand All @@ -20,8 +21,14 @@ class RewardedExample extends StatefulWidget {
}

class RewardedExampleState extends State<RewardedExample> {
static const privacySettingsText = 'Privacy Settings';

final _consentManager = ConsentManager();
final CountdownTimer _countdownTimer = CountdownTimer();
var _showWatchVideoButton = false;
var _gamePaused = false;
var _gameOver = false;
var _isMobileAdsInitializeCalled = false;
var _coins = 0;
RewardedAd? _rewardedAd;

Expand All @@ -33,20 +40,55 @@ class RewardedExampleState extends State<RewardedExample> {
void initState() {
super.initState();

_consentManager.gatherConsent((consentGatheringError) {
if (consentGatheringError != null) {
// Consent not obtained in current session.
debugPrint(
"${consentGatheringError.errorCode}: ${consentGatheringError.message}");
}

// Kick off the first play of the "game".
_startNewGame();

// Attempt to initialize the Mobile Ads SDK.
_initializeMobileAdsSDK();
});

// This sample attempts to load ads using consent obtained in the previous session.
_initializeMobileAdsSDK();

// Show the "Watch video" button when the timer reaches zero.
_countdownTimer.addListener(() => setState(() {
if (_countdownTimer.isComplete) {
_gameOver = true;
_showWatchVideoButton = true;
_coins += 1;
} else {
_showWatchVideoButton = false;
}
}));
_startNewGame();
}

void _startNewGame() {
_loadAd();
_countdownTimer.start();
_gameOver = false;
_gamePaused = false;
}

void _pauseGame() {
if (_gameOver || _gamePaused) {
return;
}
_countdownTimer.pause();
_gamePaused = true;
}

void _resumeGame() {
if (_gameOver || !_gamePaused) {
return;
}
_countdownTimer.resume();
_gamePaused = false;
}

@override
Expand All @@ -55,8 +97,10 @@ class RewardedExampleState extends State<RewardedExample> {
title: 'Rewarded Example',
home: Scaffold(
appBar: AppBar(
title: const Text('Rewarded Example'),
),
title: const Text('Rewarded Example'),
actions: _isMobileAdsInitializeCalled
? _privacySettingsAppBarAction()
: null),
body: Stack(
children: [
const Align(
Expand All @@ -82,6 +126,7 @@ class RewardedExampleState extends State<RewardedExample> {
child: TextButton(
onPressed: () {
_startNewGame();
_loadAd();
},
child: const Text('Play Again'),
),
Expand Down Expand Up @@ -116,8 +161,48 @@ class RewardedExampleState extends State<RewardedExample> {
);
}

List<Widget> _privacySettingsAppBarAction() {
return <Widget>[
// Regenerate the options menu to include a privacy setting.
FutureBuilder(
future: _consentManager.isPrivacyOptionsRequired(),
builder: (context, snapshot) {
final bool visibility = snapshot.data ?? false;
return Visibility(
visible: visibility,
child: PopupMenuButton<String>(
onSelected: (String result) {
if (result == privacySettingsText) {
_pauseGame();
_consentManager.showPrivacyOptionsForm((formError) {
if (formError != null) {
debugPrint(
"${formError.errorCode}: ${formError.message}");
}
_resumeGame();
});
}
},
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: privacySettingsText,
child: Text(privacySettingsText))
],
));
})
];
}

/// Loads a rewarded ad.
void _loadAd() {
void _loadAd() async {
// Only load an ad if the Mobile Ads SDK has gathered consent aligned with
// the app's configured messages.
var canRequestAds = await _consentManager.canRequestAds();
if (!canRequestAds) {
return;
}

RewardedAd.load(
adUnitId: _adUnitId,
request: const AdRequest(),
Expand Down Expand Up @@ -146,6 +231,26 @@ class RewardedExampleState extends State<RewardedExample> {
}));
}

/// Initialize the Mobile Ads SDK if the SDK has gathered consent aligned with
/// the app's configured messages.
void _initializeMobileAdsSDK() async {
if (_isMobileAdsInitializeCalled) {
return;
}

var canRequestAds = await _consentManager.canRequestAds();
if (canRequestAds) {
setState(() {
_isMobileAdsInitializeCalled = true;
});

// Initialize the Mobile Ads SDK.
MobileAds.instance.initialize();
// Load an ad.
_loadAd();
}
}

@override
void dispose() {
_rewardedAd?.dispose();
Expand Down
2 changes: 1 addition & 1 deletion samples/admob/rewarded_example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ environment:
dependencies:
flutter:
sdk: flutter
google_mobile_ads: ^5.0.0
google_mobile_ads: ^5.1.0

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit 74f7aed

Please sign in to comment.