Issue
The firebase_admob package has an option to display RewardedVideoAd's, but only one video will load and each successive call to load() fails to trigger a RewardedVideoAdEvent.loaded, so only one ad can be shown per session.
Steps to Reproduce:
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713"/>
firebase_admob: 0.9.0+1
main.dart:
import 'package:firebase_admob/firebase_admob.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
FirebaseAdMob.instance.initialize(appId: FirebaseAdMob.testAppId);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: RewardedVideoAdTest(),
);
}
}
class RewardedVideoAdTest extends StatefulWidget {
@override
RewardedVideoAdTestState createState() => RewardedVideoAdTestState();
}
class RewardedVideoAdTestState extends State<RewardedVideoAdTest> {
bool rewardedVideoAdLoaded = false;
@override
void initState() {
super.initState();
// Add a listener for RewardedVideoAd's
RewardedVideoAd.instance.listener =
(RewardedVideoAdEvent event, {String rewardType, int rewardAmount}) {
if (event == RewardedVideoAdEvent.rewarded) {
print("RewardedVideoAd.listener - Rewarded");
} else if ( event == RewardedVideoAdEvent.loaded ) {
print("RewardedVideoAd.listener - Loaded");
setState(() {
rewardedVideoAdLoaded = true;
});
} else if ( event == RewardedVideoAdEvent.opened ) {
print("RewardedVideoAd.listener - Opened");
loadRewardedVideoAd();
} else if ( event == RewardedVideoAdEvent.failedToLoad ) {
print("RewardedVideoAd.listener - FailedToLoad");
} else if ( event == RewardedVideoAdEvent.started ) {
print("RewardedVideoAd.listener - Started");
} else if ( event == RewardedVideoAdEvent.completed ) {
print("RewardedVideoAd.listener - Completed");
} else if ( event == RewardedVideoAdEvent.leftApplication ) {
print("RewardedVideoAd.listener - Left Application");
} else if ( event == RewardedVideoAdEvent.closed ) {
print("RewardedVideoAd.listener - Closed");
}
};
// Load our first RewardedVideoAd
loadRewardedVideoAd();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Rewarded Ad Video Test")
),
body: Center(
child: RaisedButton(
child: Text("Show Rewarded Video Ad"),
onPressed: rewardedVideoAdLoaded ? showRewardedVideoAd : null
),
)
);
}
void loadRewardedVideoAd() {
print("RewardedVideoAd.load() - Called");
RewardedVideoAd.instance.load(
adUnitId: RewardedVideoAd.testAdUnitId,
targetingInfo: MobileAdTargetingInfo(
nonPersonalizedAds: true,
)
).catchError((error) {
print("RewardedVideoAd.load() - Error");
}).then((onVal) {
print("RewardedVideoAd.load() - Returned ${onVal}");
return onVal;
}).whenComplete(() {
print("RewardedVideoAd.load() - Complete");
});
}
void showRewardedVideoAd() {
setState(() {
rewardedVideoAdLoaded = false;
});
RewardedVideoAd.instance.show();
}
}
Observations
You'll notice that at first the "Show Rewarded Video Ad" button is temporarily disabled, that is because on startup we are still loading the first video ad. Once the ad loads the button will be enabled, you can click it to see the test video ad.
After clicking the ad you will see an attempt to load the next video ad that is triggered by our listener. This second load() attempt will never finish.
The output you'll see to console will be something like:
RewardedVideoAd.load() - Called
RewardedVideoAd.load() - Returned true <--- First load() triggers an event...
RewardedVideoAd.load() - Complete
RewardedVideoAd.listener - Loaded <--- ... right here. We now can show ad
RewardedVideoAd.listener - Opened <--- We open an ad
RewardedVideoAd.load() - Called
RewardedVideoAd.load() - Returned true <--- Second load() works, never triggers event
RewardedVideoAd.load() - Complete
RewardedVideoAd.listener - Started
RewardedVideoAd.listener - Completed
RewardedVideoAd.listener - Rewarded
RewardedVideoAd.listener - Closed
In the case above we waited for the video to load and watched it while attempted to load the next, which is why we see the "rewarded" line. The next video never loads.
flutter doctor
Here are my flutter doctor results:
[✓] Flutter (Channel dev, v1.7.4, on Mac OS X 10.14.5 18F203, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 10.2.1)
[✓] iOS tools - develop for iOS devices
[✓] Android Studio (version 3.4)
[✓] Connected device (1 available)
Here are the verbose flutter doctor results:
[✓] Flutter (Channel dev, v1.7.4, on Mac OS X 10.14.5 18F203, locale en-US)
• Flutter version 1.7.4 at /Users/mas7967/Library/Flutter/flutter
• Framework revision dfecafa4ab (4 days ago), 2019-06-14 09:46:23 -0700
• Engine revision 2589785b5c
• Dart version 2.4.0
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
• Android SDK at /Users/mas7967/Library/Android/sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-28, build-tools 28.0.3
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 10.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 10.2.1, Build version 10E1001
• CocoaPods version 1.6.1
[✓] iOS tools - develop for iOS devices
• ios-deploy 1.9.4
[✓] Android Studio (version 3.4)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 36.1.1
• Dart plugin version 183.6270
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
[✓] Connected device (1 available)
• Pixel 2 XL • 711KPFX0768491 • android-arm64 • Android 9 (API 28)
• No issues found!
@mas7967
The issue at https://github.com/flutter/flutter/issues/34670 has been closed and moved here. Future collaboration on this issue will be done here.
Hello @mas7967 !
Did you manage to solve the issue? Does the problem still persist in the latest plugin version with latest flutter stable?
Sorry for the delay in response, I did figure this issue out.
The problem is with this part of my code:
} else if ( event == RewardedVideoAdEvent.opened ) {
print("RewardedVideoAd.listener - Opened");
loadRewardedVideoAd();
}
The issue is I was trying to load a second reward video ad when the user opens a loaded ad. My thought process was that I would load a second ad in the background so that when the user finishes watching the first ad, another ad would be in a loaded state and ready to be opened. This apparently isn't allowed. You need to wait until the current reward video hits the completed status, and only then can you begin loading another reward video.
It was unclear to me that this was how it worked, it's not mentioned in the documentation, and the only way I tracked down the problem was going through the native implementation which seems to be forcing this behavior.
See the FirebaseAdMobPlugin.java file of the Android implementation for reference.
Lines 128:
private void callLoadRewardedVideoAd(MethodCall call, Result result) {
if (rewardedWrapper.getStatus() != RewardedVideoAdWrapper.Status.CREATED
&& rewardedWrapper.getStatus() != RewardedVideoAdWrapper.Status.FAILED) {
result.success(Boolean.TRUE); // The ad was already loading or loaded.
return;
}
...
}
While viewing a reward video, the RewardedVideoAdWrapper.Status is still LOADED, and so the method returned true, even though it didn't load a new reward video. So in my log statements:
RewardedVideoAd.load() - Called
RewardedVideoAd.load() - Returned true <--- First load() triggers an event...
RewardedVideoAd.load() - Complete
RewardedVideoAd.listener - Loaded <--- ... right here. We now can show ad
RewardedVideoAd.listener - Opened <--- We open an ad
RewardedVideoAd.load() - Called
RewardedVideoAd.load() - Returned true <--- Second load() works, never triggers event
RewardedVideoAd.load() - Complete
RewardedVideoAd.listener - Started
RewardedVideoAd.listener - Completed
RewardedVideoAd.listener - Rewarded
RewardedVideoAd.listener - Closed
The second time we call RewardedVideoAd.load() and it returned true, it didn't actually load another video. It had interpreted the reward video currently being viewed by the user as LOADED and didn't bother loading a second one.
I do think this should be addressed in some way in the package, some options are:
Do nothing but at a minimum mention this as a "Limitation" in the package documentation.
Ad another status to the RewardVideoAdWrapper.Status enum. The current enum is:
enum Status {
CREATED,
LOADING,
FAILED,
LOADED
}
The Status does not differentiate between a video that is LOADED, and one that is being viewed by the user. I'm unsure if there is a technical limitation here, but if another status could be added, such as VIEWING, then the previously mentioned method callLoadRewardedVideoAd could load another reward video. Or, in the case that two reward videos cannot be loaded at once, it could at least throw a meaningful error.
result.success(Boolean.TRUE);
which is very misleading since it wasn't successful at all, instead it should return something like:
result.error("ad_not_loaded", "load failed, cannot load two reward videos at one time", null);
I'm not sure if this was a technical limitation or a choice by the author, but there is something misleading here that I think should be addressed, since at a higher level anyone using this package would get misleading returns without any explicit documentation saying that what they are trying to do is not allowed.
Thanks!
I hit exactly this problem. I was loading an advert, then when switching user account I was attempting to load it again (this time with different tracking settings).
However, the second call to load never triggered the listener because (after much investigation) I realised the advert was already loaded and the listener didn't trigger on the second load.
I would suggest that the listener should still trigger the 'loaded' event even if the advert is already loaded.
Anyway, I hadn't noticed the boolean being returned from the load method, so I'll see if that solves my problem :)
Hi @mas7967
are you still experiencing the issue with the latest stable version of flutter
and the latest version of firebase_admob?
thank you
Going to leave this one open for the time being. Not 100% sure whether this should be documentation or additional code to support this.
I am experiencing a similar issue, but what happens is that if I, load the video first but don't show it, if I exit the page (by popping the route) and come back to the page, the loaded event does not fire again. I have to get out of the app and come back for it to actually load and the listener to alert that the ad was loaded.
I am assuming this is because the video is already loaded and doing a new instance.load() won't load another one and hence not alert the listener of it.
I have yet to find another way to check whether the video was previously loaded and can be shown right away without listener alerting of the Loaded event.
This does not happen and it behaves properly if I show the video. But if the video is never shown, then it won't load again.
RewardedVideoAd doesn't seem to have the same .isLoaded() method as the other ads
EDIT:
I see theres this in the source code:
/// Only one rewarded video ad can be loaded at a time. Because the video assets
/// are so large, it's a good idea to start loading an ad well in advance of
/// when it's likely to be needed.
But there is not mention on how to check if that video was already loaded if the listener does not fire the event.
I hit exactly this problem. I was loading an advert, then when switching user account I was attempting to load it again (this time with different tracking settings).
However, the second call to load never triggered the listener because (after much investigation) I realised the advert was already loaded and the listener didn't trigger on the second load.I would suggest that the listener should still trigger the 'loaded' event even if the advert is already loaded.
Anyway, I hadn't noticed the boolean being returned from the load method, so I'll see if that solves my problem :)
Agree! It should fire the Loaded event instantly if it's already loaded and there is a call to instance.load()
Having same problem here. I'm loading a reward video ad on a particular page and if someone leaves that page after the ad gets loaded then enters again he will end up waiting for the listener event that will never show :/
Most helpful comment
I hit exactly this problem. I was loading an advert, then when switching user account I was attempting to load it again (this time with different tracking settings).
However, the second call to load never triggered the listener because (after much investigation) I realised the advert was already loaded and the listener didn't trigger on the second load.
I would suggest that the listener should still trigger the 'loaded' event even if the advert is already loaded.
Anyway, I hadn't noticed the boolean being returned from the load method, so I'll see if that solves my problem :)