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

The ad can not be shown when app is not in foreground (Android-iOS interstitial ad show issue) #1196

Closed
aykutuludag opened this issue Oct 22, 2024 · 19 comments
Labels
interstitial ad Issues related to Interstitial Ad

Comments

@aykutuludag
Copy link

aykutuludag commented Oct 22, 2024

Flutter version: 3.24.3
Dart version: 3.5.3
Affected Android versions: Happening in every Android versions:
Affected iOS versions: Happening in every iOS versions.

The issue
This issue is still present google_mobile_ads: ^5.2.0. To be clear, I suspect that this error happening all kind of fullscreen ads (Open Ads, Interstitial Ads etc). Not happening in every time according to firebase data, it is happening around %10 of intertititial show calls. So only %90 of interstitial can be showed successfully.

Error Reasons:
For Android >>> The ad can not be shown when app is not in foreground.
For iOS >>> the provided view controller is not being presented.
For Both >>> The consent form has already been shown.

For Android:

Sceneario
As general the other apps, I am showing interstitial ads between screen changes. Here is my code:

InterstitialAd? fullPageAd;

Future<void> initializeAdmob() async {
    await MobileAds.instance.initialize();
    await createInterstitialAd();
}

Future<void> createInterstitialAd() async {
  if (adCount < 2) {
    var adCompleter = Completer<void>();

    // If ads can't load within 2.5 seconds, skip
    Timer(Duration(milliseconds: 2500), () {
      if (!adCompleter.isCompleted) {
        adCompleter.complete();
      }
    });

    await InterstitialAd.load(
        adUnitId: Platform.isAndroid ? interstitialAndroid : interstitialiOS,
        request: request,
        adLoadCallback: InterstitialAdLoadCallback(
          onAdLoaded: (InterstitialAd ad) {
            if (!adCompleter.isCompleted) {
              adCompleter.complete();
            }
            fullPageAd = ad;
            fullPageAd!.setImmersiveMode(true);
            FirebaseAnalytics.instance.logEvent(
              name: "interstitialLOAD",
            );
          },
          onAdFailedToLoad: (LoadAdError error) async {
            FirebaseAnalytics.instance.logEvent(
              name: "interstitialFAILLOAD",
              parameters: {
                "errorReason": error.message,
              },
            );
          },
        ));

    await adCompleter.future;
  }
}
Future<void> showInterstitialAd(
    BuildContext context, void Function() changeScreen) async {
  if (fullPageAd == null) {
    changeScreen();
    return;
  }

  WidgetsBinding.instance.addPostFrameCallback((_) async {
    if (fullPageAd != null) {
      fullPageAd!.fullScreenContentCallback = FullScreenContentCallback(
        onAdShowedFullScreenContent: (InterstitialAd ad) => {
          createInterstitialAd(),
          FirebaseAnalytics.instance.logEvent(
            name: "interstitialSHOW",
          ),
        },
        onAdDismissedFullScreenContent: (InterstitialAd ad) {
          ad.dispose();
        },
        onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError error) {
          ad.dispose();
          createInterstitialAd();
          FirebaseAnalytics.instance.logEvent(
            name: "interstitialFAILSHOW",
            parameters: {
              "errorReason": error.message,
            },
          );
        },
      );
      await fullPageAd!.show();
      fullPageAd = null;
    }
  });

  changeScreen();
}
Future<void> changeScreen() async {
    await Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => SecondScreen()),
    );
}

Thanks to firebase logs i can see how many device can trigger the onAdFailedToShowFullScreenContent

image

As you can see if the device is Android errorReason is The ad can not be shown when app is not in foreground.. If it is iOS, the provided view controller is not being presented.

Adding WidgetsBinding.instance.addPostFrameCallback reduced the errors (I just released new version we can't see on the chart) but it is still continuing. Google should fix this because it is reduces incomes significantly. I don't think it is because of my dart code it is pretty standart based on Google examples and also many users getting this error. Kind regards.

Note: Is it possible that those device may installed some kind of AdBlocker and that adblocker not prevent loading, but showing? Maybe we are getting this error because of that. AdBlock may be blocking the display of ads by putting the application in the background? Of course, this may only explain half of the error. I can't explain why this error also occur in iOS too.

Note2: Calling ads first, then navigate screen or visa-versa, DIDN'T WORK. Same error, nothing changed.

Note3: I added following tags to AndroidManifest.xml but it didn't change too. With or without error rate and reasons always same. (https://developers.google.com/admob/android/optimize-initialization)

<meta-data
   android:name="com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION"
   android:value="true"/>
<meta-data
   android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING"
   android:value="true"/>
@aykutuludag aykutuludag changed the title The ad can not be shown when app is not in foreground. (Android-iOS fullscreen ads issuee) The ad can not be shown when app is not in foreground. (Android-iOS fullscreen ads issue) Oct 22, 2024
@peterweb2005
Copy link

peterweb2005 commented Oct 22, 2024

no, my issue is only app open ad, and only in android

update

providing updates in this issue, after 1 year, still counting ~1k 1 month in crashlytics
and i believed that because android render too faster comparing with ios

as this issue flutter/flutter#151516,
which only happen in android

@aykutuludag
Copy link
Author

aykutuludag commented Oct 22, 2024

no, my issue is only app open ad, and only in android

Have you installed firebase analytics or similar technologies to your app for verify nobody in your app experience this issue? Because it is not happening my device I am seeing the ads but according to logs some device can't see the ads. These data aggregated from nearly 50k devices both Android and iOS. It may currently happening your app too. Also this issue is same for all fullscreen ads (open ad, interstitial

@peterweb2005
Copy link

peterweb2005 commented Oct 22, 2024

no, my issue is only app open ad, and only in android

Have you installed firebase analytics or similar technologies to your app for verify nobody in your app experience this issue? Because it is not happening my device I am seeing the ads but according to logs some device can't see the ads. These data aggregated from nearly 50k devices both Android and iOS. It may currently happening your app too. Also this issue is same for all fullscreen ads (open ad, interstitial

yes, my side crash log all errors (not only ad; but skip network error which my app may retry), i see no count in interstitial ad showe error

you may have bug that there is 2 types of resume, 1 is flutter resume
1 is admob resume

i may provide that later

update

updated which type of resume show which type ad

flutter resume, show interstitial ad

  didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:

admob resume, show app open ad

      AppStateEventNotifier.startListening();
      AppStateEventNotifier.appStateStream.forEach((state) async {
        if (state == AppState.foreground) {

@malandr2
Copy link
Collaborator

Hi @aykutuludag, we just released 5.2.0 which included an update to our full-screen presentation logic #1153

Can you confirm the errors you are seeing are happening for users that are running version 5.2.0 of the plugin?

@malandr2 malandr2 added the feedback required Further information is requested label Oct 23, 2024
@aykutuludag
Copy link
Author

aykutuludag commented Oct 23, 2024

Yes I can confirm I'm still getting error app is already integrated v5.2.0. Thanks to WidgetsBinding.instance.addPostFrameCallback and adding await before fullPageAd!.show, errors reduced/reducing significantly but I am seeing on firebase console user's can't ads. Right now it is around %3-%5 of users can't see. Before addPostFrameCallback it were raised up to %12.

Note: In documentation Google is not using await (https://developers.google.com/admob/flutter/interstitial) but adding it and surround the code with WidgetsBinding.instance.addPostFrameCallback helped to reduce ads show errors.

Note2: I checked the #1153, I guess that is only cover iOS bug. But I am still getting iOS show errors too if u check my first firebase screen picture, that is coming from app with mobile_ads v5.2.0 I am getting in Android, too. Actually error rate is higher in Android rather than iOS.

Note3: If any flutter/native crash occur either first or second screen, interstitial ad may not be shown while switching first to second. This is not my case right now but still to remind users.

Screenshot 2024-10-23 at 23 04 22

@github-actions github-actions bot removed the feedback required Further information is requested label Oct 23, 2024
@malandr2
Copy link
Collaborator

@aykutuludag got it. It's possible those errors are working as intended based on the integration. Can you provide a minimal, reproducible example and I can take a look?

@malandr2 malandr2 added feedback required Further information is requested interstitial ad Issues related to Interstitial Ad labels Oct 24, 2024
@aykutuludag
Copy link
Author

aykutuludag commented Oct 24, 2024

I shared the minimal repdocible code in the first comment @malandr2 u can use that. I trimmed ads unrelated codes. I am calling showInterstitialAd function between screen changes. It is pretty standart implementation based on Google docs.

@github-actions github-actions bot removed the feedback required Further information is requested label Oct 24, 2024
@peterweb2005
Copy link

yes, maybe same root cause, why there are 2 types of resume, and admob resume (foreground) very inaccurate

@aykutuludag
Copy link
Author

aykutuludag commented Oct 24, 2024

yes, maybe same root cause, why there are 2 types of resume, and admob resume (foreground) very inaccurate

Root cause seems to be same. Flutter Lifecycle and Admob Interstitial lifecycle seems to be is not coinciding all the time I guess.

Also I am starting to get new error about last 2-3 weeks. I look it up on the internet but I couldn't find any info.

Error Reason: The consent form has already been shown.

image

@aykutuludag
Copy link
Author

aykutuludag commented Oct 25, 2024

I saw that first time.

Timeout for show call succeed.

image

@aykutuludag aykutuludag changed the title The ad can not be shown when app is not in foreground. (Android-iOS fullscreen ads issue) The ad can not be shown when app is not in foreground. (Android-iOS interstitial ad show issue) Oct 26, 2024
@aykutuludag aykutuludag changed the title The ad can not be shown when app is not in foreground. (Android-iOS interstitial ad show issue) The ad can not be shown when app is not in foreground (Android-iOS interstitial ad show issue) Oct 26, 2024
@aykutuludag
Copy link
Author

aykutuludag commented Oct 26, 2024

New error: Web view content process terminated.

image

@malandr2
Copy link
Collaborator

malandr2 commented Oct 28, 2024

Hi @aykutuludag, "The consent form has already been shown." is related to ad unit deployment where an ad unit may be used to gather consent. The form will not show if it has already appeared.

I'm getting multiple compile-time errors when copying your code. Please provide a minimal, reproducible example and I'll be able to properly triage. For example, are you calling showInterstititalAd before the screen changes?

@malandr2 malandr2 added the feedback required Further information is requested label Oct 28, 2024
@aykutuludag
Copy link
Author

aykutuludag commented Oct 28, 2024

Yes I am showing ads between screen changes. changeScreen function is the responsible function to switching screens and here is the code:

InterstitialAd? fullPageAd;

Future<void> initializeAdmob() async {
    await MobileAds.instance.initialize();
    await createInterstitialAd();
}

Future<void> createInterstitialAd() async {
  if (adCount < 2) {
    var adCompleter = Completer<void>();

    // If ads can't load within 2.5 seconds, skip
    Timer(Duration(milliseconds: 2500), () {
      if (!adCompleter.isCompleted) {
        adCompleter.complete();
      }
    });

    await InterstitialAd.load(
        adUnitId: Platform.isAndroid ? interstitialAndroid : interstitialiOS,
        request: request,
        adLoadCallback: InterstitialAdLoadCallback(
          onAdLoaded: (InterstitialAd ad) {
            if (!adCompleter.isCompleted) {
              adCompleter.complete();
            }
            fullPageAd = ad;
            fullPageAd!.setImmersiveMode(true);
            FirebaseAnalytics.instance.logEvent(
              name: "interstitialLOAD",
            );
          },
          onAdFailedToLoad: (LoadAdError error) async {
            FirebaseAnalytics.instance.logEvent(
              name: "interstitialFAILLOAD",
              parameters: {
                "errorReason": error.message,
              },
            );
          },
        ));

    await adCompleter.future;
  }
}
Future<void> showInterstitialAd(
    BuildContext context, void Function() changeScreen) async {
  if (fullPageAd == null) {
    changeScreen();
    return;
  }

  WidgetsBinding.instance.addPostFrameCallback((_) async {
    if (fullPageAd != null) {
      fullPageAd!.fullScreenContentCallback = FullScreenContentCallback(
        onAdShowedFullScreenContent: (InterstitialAd ad) => {
          createInterstitialAd(),
          FirebaseAnalytics.instance.logEvent(
            name: "interstitialSHOW",
          ),
        },
        onAdDismissedFullScreenContent: (InterstitialAd ad) {
          ad.dispose();
        },
        onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError error) {
          ad.dispose();
          createInterstitialAd();
          FirebaseAnalytics.instance.logEvent(
            name: "interstitialFAILSHOW",
            parameters: {
              "errorReason": error.message,
            },
          );
        },
      );
      await fullPageAd!.show();
      fullPageAd = null;
    }
  });

  changeScreen();
}
Future<void> changeScreen() async {
    await Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => SecondScreen()),
    );
}

function call: showInterstitialAd(context, changeScreen) This code is inside a button in First Screen. When user click it, it is opening SecondScreen and showing ads according to code as you can see.

@github-actions github-actions bot removed the feedback required Further information is requested label Oct 28, 2024
@malandr2
Copy link
Collaborator

malandr2 commented Oct 29, 2024

Hi @aykutuludag, try calling changeScreen() only after the interstitial ad is dismissed or fails to show. If changeScreen() is called before show() is called, it may throw an error

@aykutuludag
Copy link
Author

aykutuludag commented Oct 29, 2024

Hi @aykutuludag, try calling changeScreen() only after the interstitial ad is dismissed or fails to show. If changeScreen() is called before show() is called, it may throw an error

I'm trying to your solution and sending new version. Thanks I will notify about the issue if it continue.

Note: I just applied your approach. First thing to notice that there is a delay between 0.4sec-2sec. In iOS screen changes more faster, on Android it is much slower. If I understand correctly, onAdDismissedFullScreenContent triggerred with delay. This delay causes the delay between screen changes. Problem is not about screen change code, it is about callback triggerred after 1-2 seconds of ads closed.

@malandr2
Copy link
Collaborator

Hi @aykutuludag, if changeScreen() is called prior to await fullPageAd!.show(); being called, that is likely a cause for errors to surface. Moving changeScreen() into the callbacks ensures the screen is not changed until the interstitial ad is shown. Theoretically could also try calling changeScreen() in onAdShowedFullScreenContent if onAdDismissedFullScreenContent is not optimal for your use case

@aykutuludag
Copy link
Author

aykutuludag commented Oct 30, 2024

Hi @aykutuludag, if changeScreen() is called prior to await fullPageAd!.show(); being called, that is likely a cause for errors to surface. Moving changeScreen() into the callbacks ensures the screen is not changed until the interstitial ad is shown. Theoretically could also try calling changeScreen() in onAdShowedFullScreenContent if onAdDismissedFullScreenContent is not optimal for your use case

I tried inside of onAdShowedFullScreenContent, it didn't consistent and gave the show fail error again. I applied inside of onAdDismissedFullScreenContent and now ad show fail reduced dramatically but not zero. I will write new errors once new release obtained by more user. The delay is a little bit problematic in Android it is between 300ms-2sec. In iOS, it is almost unnoticeable it is about 150-300ms.

@aykutuludag
Copy link
Author

aykutuludag commented Oct 31, 2024

Okay I am getting new reports from Firebase.

Bad news: Yeah the method you suggested decreased the rate of onAdFailedToShowFullScreenContent errors significantly, but I am still getting it.

For iOS: the provided view controller is not being presented.
For Android: The ad can not be shown when app is not in foreground.

Like I said it is decreased rate of the error significantly, but according to my early calculations show that it is still happen %3-5 (previous %10) of every session. Maybe it will go lower values. I will report new reports in a few days once more user get the update.

Note: Also it would be great if we can reduce the delay of callbacks in the new versions of google_mobile_ads. Apps will look like much more consistent and fast.

@malandr2
Copy link
Collaborator

malandr2 commented Nov 1, 2024

Hi @aykutuludag, it's very possible these errors are completely valid based on how the user is interacting with your app. Small sample size is also possible. I don't imagine it will go down to 0% because users will still be running old versions. Seeing a sharp decrease is great news. I recommend to keep experimenting on the timing of when to present full-screen ads to your users.

The callbacks are determined by the Google Mobile Ads Android and iOS SDKs, respectively. You can create a new thread in the AdMob Developers forum to voice your feedback to the proper channels.

Closing this out. Thanks!

@malandr2 malandr2 closed this as completed Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interstitial ad Issues related to Interstitial Ad
Projects
None yet
Development

No branches or pull requests

3 participants