Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added UMP SDK integration to Rewarded sample #1071

Merged
merged 5 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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