googleads-mobile-flutter icon indicating copy to clipboard operation
googleads-mobile-flutter copied to clipboard

AdMob - PlatformException(AdShowError, Ad failed to show., null, null)

Open BriceFab opened this issue 10 months ago • 12 comments

Plugin Version

google_mobile_ads: ^5.3.1

flutter doctor -v [√] Flutter (Channel stable, 3.24.5, on Microsoft Windows [version 10.0.22631.4890], locale fr-CH) • Flutter version 3.24.5 on channel stable at C:\flutter\flutter_windows_3.22.0-stable • Upstream repository https://github.com/flutter/flutter.git • Framework revision dec2ee5c1f (3 months ago), 2024-11-13 11:13:06 -0800 • Engine revision a18df97ca5 • Dart version 3.5.4 • DevTools version 2.37.3

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android toolchain - develop for Android devices (Android SDK version 35.0.0-rc4) • Android SDK at C:\Users\fabrr\AppData\Local\Android\sdk • Platform android-35, build-tools 35.0.0-rc4 • Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java • Java version OpenJDK Runtime Environment (build 17.0.10+0--11572160) • All Android licenses accepted.

[√] Chrome - develop for the web • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.10.0) • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community • Visual Studio Community 2022 version 17.10.34916.146 • Windows 10 SDK version 10.0.22621.0

[√] Android Studio (version 2023.3) • Android Studio at C:\Program Files\Android\Android Studio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.10+0--11572160)

[√] VS Code (version 1.97.2) • VS Code at C:\Users\fabrr\AppData\Local\Programs\Microsoft VS Code • Flutter extension version 3.104.0

[√] Connected device (4 available) • SM A346B (mobile) • RFCWA0KWGSN • android-arm64 • Android 14 (API 34) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [version 10.0.22631.4890] • Chrome (web) • chrome • web-javascript • Google Chrome 132.0.6834.197 • Edge (web) • edge • web-javascript • Microsoft Edge 130.0.2849.52

[√] Network resources • All expected network resources are available.

• No issues found!

Describe the problem

Steps to Reproduce

import 'package:fitmetrics_app/di.dart';
import 'package:fitmetrics_app/features/ads/index.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:injectable/injectable.dart';
import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';

/// Documentation : https://developers.google.com/admob/flutter/app-open
@singleton
class AppOpenAdManager {
  final Logger _logger = Logger('AppOpenAdManager');
  AppOpenAd? _appOpenAd;
  bool _isShowingAd = false;

  /// Maximum duration allowed between loading and showing the ad.
  final Duration maxCacheDuration = const Duration(hours: 4);

  /// Shared Preferences key for storing the last ad shown date.
  static const String _lastAdShownKey = 'lastShownAppOpenAdDate';

  /// Keep track of load time so we don't show an expired ad.
  DateTime? _appOpenLoadTime;

  /// Loads an App Open Ad.
  void loadAd() async {
    final AdUnitIdService adUnitService = getIt<AdUnitIdService>();
    final String adUnitId = adUnitService.getUnitId(AdUnitIds.appOpen);

    _logger.info('[AD] Attempting to load App Open Ad: $adUnitId');

    final AdManager adManager = getIt.get<AdManager>();
    final AdRequest adRequest = await adManager.createAdRequest();

    try {
      AppOpenAd.load(
        adUnitId: adUnitId,
        request: adRequest,
        adLoadCallback: AppOpenAdLoadCallback(
          onAdLoaded: (AppOpenAd ad) {
            _logger.info('[AD] App Open Ad loaded successfully.');
            _appOpenLoadTime = DateTime.now();
            _appOpenAd = ad;
          },
          onAdFailedToLoad: (LoadAdError error) {
            _logger.warning('[AD] Failed to load App Open Ad: $error');
          },
        ),
      );
    } catch (e) {
      _logger.severe('[AD] Exception during App Open Ad loading: $e');
    }
  }

  bool get isAdAvailable => _appOpenAd != null;

  /// Shows the ad if available and not expired.
  void showAdIfAvailable() async {
    final adManager = getIt.get<AdManager>();
    if (!adManager.hasAds()) {
      _logger.warning("User doesn't have ads.");
      return;
    }

    if (!isAdAvailable) {
      _logger.info('Tried to show ad before available.');
      loadAd();
      return;
    }

    if (_isShowingAd) {
      _logger.warning('Tried to show ad while already showing an ad.');
      return;
    }

    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final String? lastShownDateString = prefs.getString(_lastAdShownKey);
    DateTime? lastShownDate;

    if (lastShownDateString != null) {
      lastShownDate = DateTime.tryParse(lastShownDateString);
    }

    // Skip showing the ad if it was recently shown.
    if (lastShownDate != null && DateTime.now().difference(lastShownDate) < maxCacheDuration) {
      _logger.info('App Open Ad already shown recently. Skipping display.');
      return;
    }

    // Load a new ad if no ad is available or it's expired.
    if (_isAdExpired()) {
      _logger.info('Maximum cache duration exceeded. Loading another ad.');
      _appOpenAd?.dispose();
      _appOpenAd = null;
      loadAd();
      return;
    }

    _appOpenAd!.fullScreenContentCallback = FullScreenContentCallback(
      onAdShowedFullScreenContent: (AppOpenAd ad) {
        _isShowingAd = true;
        _logger.info('[AD] App Open Ad is showing full screen.');
      },
      onAdFailedToShowFullScreenContent: (AppOpenAd ad, AdError error) {
        _logger.severe('[AD] Failed to show App Open Ad: $error');
        _isShowingAd = false;
        ad.dispose();
        _appOpenAd = null;
      },
      onAdDismissedFullScreenContent: (AppOpenAd ad) async {
        _isShowingAd = false;
        _logger.info('[AD] App Open Ad dismissed.');
        ad.dispose();
        _appOpenAd = null;

        // Save the last shown time.
        await prefs.setString(_lastAdShownKey, DateTime.now().toIso8601String());

        // Preload the next ad.
        loadAd();
      },
    );

    try {
      _appOpenAd!.show();
    } catch (e) {
      // https://github.com/googleads/googleads-mobile-flutter/issues/596
      _logger.severe('Unable to show app open ad $e');
    }
  }

  /// Checks if the current ad has expired.
  bool _isAdExpired() {
    if (_appOpenLoadTime == null) {
      return true;
    }
    return DateTime.now().subtract(maxCacheDuration).isAfter(_appOpenLoadTime!);
  }
}

Expected results:

Ad show successfully

Actual results:

E/flutter (29916): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(AdShowError, Ad failed to show., null, null) E/flutter (29916): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:648:7) E/flutter (29916): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:334:18) E/flutter (29916): E/flutter (29916):

Reported in crashlytics : Image

BriceFab avatar Feb 17 '25 10:02 BriceFab

Hi @BriceFab, even in the try runtime issues can still occur using the ! operator. If you add a null check such as

try {
  if(_appOpenAd != null){
    _appOpenAd!.show();
  } else {
    _logger.severe("App open ad was null when trying to show.");
  }

} catch (e) {
  _logger.severe('Unable to show app open ad $e');
}

can you still reproduce this crash?

malandr2 avatar Feb 19 '25 22:02 malandr2

Closing due to inactivity. Null check viable solution

malandr2 avatar Feb 24 '25 15:02 malandr2

Hi @malandr2

Yes the problem still persist and the null check doesn't fix the issue.

Image

Could you re-open the issue please

BriceFab avatar Mar 10 '25 20:03 BriceFab

Does version 1.0.6 have the null check? Or is that an old version that is responsible for the crash? Looks like only a spike from one user

Can you share the full stack trace?

malandr2 avatar Mar 11 '25 14:03 malandr2

Yes, version 1.0.6 (40) includes the null check (it’s the latest production version).

With the code :

    try {
      if (_appOpenAd != null) {
        _appOpenAd?.show();
      } else {
        _logger.severe("App open ad was null when trying to show.");
      }
    } catch (e) {
      _logger.severe('Unable to show app open ad $e');
    }

The error is triggered by this line in the GoogleMobileAdsPlugin.java file:

https://github.com/googleads/googleads-mobile-flutter/blob/05541358c075f5259717c201dfaba97ddb03c221/packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/GoogleMobileAdsPlugin.java#L574

My implementation follows the pattern used in the official sample: https://github.com/googleads/googleads-mobile-flutter/blob/05541358c075f5259717c201dfaba97ddb03c221/samples/admob/app_open_example/lib/app_open_ad_manager.dart

One possible cause could be the timing of dispose() and loadAd() as it's Future 🤔.

BriceFab avatar Mar 11 '25 15:03 BriceFab

@BriceFab after messing around with the app_open_example app I'm unable to reproduce a crash. Are you able to? If so, could you provide steps to consistently results in the error you are experiencing. Also when are you calling showAdIfAvailable?

malandr2 avatar Mar 12 '25 15:03 malandr2

I'm facing the same issue here. App Open keep returning the same exception as above.

inc16sec avatar Mar 14 '25 02:03 inc16sec

Hi @inc16sec, can you reproduce in the app_open_example? If not, can you provide a minimal, reproducible example?

As of now the crash itself is WAI and not indicative of an issue with the plugin. It is important to prevent calling show() if the app open ad is null. If you can send over a full stack trace and/or a way to consistently reproduce we can start troubleshooting.

malandr2 avatar Mar 14 '25 14:03 malandr2

Closing due to inactivity

malandr2 avatar Mar 25 '25 16:03 malandr2

Any updates?

moradiyajay avatar Aug 12 '25 07:08 moradiyajay

@moradiyajay I still have the issue but they close this one. Maybe do you have the time to create another one with a reproductible example ?

BriceFab avatar Aug 28 '25 18:08 BriceFab

Hi @moradiyajay and @BriceFab, we've tried but we haven't able to reproduce this at all. If you're able to reproduce consistently, please share a reproducible example and we are available to take a look.

Remember, this error could be thrown because:

  • Expired ad
  • Another ad is already showing
  • App is not in the foreground
  • Invalid Activity or UI state

Please double check your code. Do you have a full stack trace? That can also help.

malandr2 avatar Aug 29 '25 14:08 malandr2

Are you guys using pihole or any adblocker on a network level? For me turning off pihole / switching network to mobile solved this issue.

raiFork avatar Sep 14 '25 08:09 raiFork

Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. If you find this problem please file a new issue with the same description, what happens, logs and the output of 'flutter doctor -v'. All system setups can be slightly different so it's always better to open new issues and reference the related ones. Thanks for your contribution.

github-actions[bot] avatar Sep 19 '25 15:09 github-actions[bot]