Flutter中AppOpenAd后台恢复不显示问题解决(google_mobile_ads:^3.0.0)
解决Flutter中AppOpenAd仅首次启动显示、后台恢复不展示的问题
问题根源分析
你的代码存在以下几个核心问题:
- 未启动生命周期监听:定义了
AppLifecycleReactor但未在main中初始化并启动监听,导致应用从后台切前台时无法触发广告展示逻辑。 - 广告加载后立即展示的错误逻辑:
loadAppOpenAd中在onAdLoaded里直接调用show(),导致广告一加载完成就显示,不符合后台恢复至前台时展示的需求,且后续后台加载的广告用户无法看到。 - 广告对象未正确置空:AppOpenAd实例只能被展示一次,展示后未将
appOpenAd置空,导致后续调用showAdIfAvailable时尝试展示已失效的广告实例。 - 初始化顺序问题:
MobileAds.instance.initialize()未加await,可能导致广告加载时SDK未初始化完成。
修复后的完整代码
1. 修正AppOpenAdManager类
class AppOpenAdManager { AppOpenAd? appOpenAd; bool _isShowingAd = false; // 防止重复触发广告展示 loadAppOpenAd() { // 已有广告或正在展示时,不重复加载 if (appOpenAd != null || _isShowingAd) return; AppOpenAd.load( adUnitId: "ca-app-pub-3940256099942544/3419835294", request: const AdRequest(), adLoadCallback: AppOpenAdLoadCallback( onAdLoaded: (ad) { appOpenAd = ad; // 监听广告生命周期,展示完成后重置状态并预加载下一个广告 ad.fullScreenContentCallback = FullScreenContentCallback( onAdDismissedFullScreenContent: (ad) { appOpenAd = null; _isShowingAd = false; loadAppOpenAd(); }, onAdFailedToShowFullScreenContent: (ad, error) { appOpenAd = null; _isShowingAd = false; loadAppOpenAd(); }, ); }, onAdFailedToLoad: (error) { print('AppOpenAd加载失败: $error'); appOpenAd = null; _isShowingAd = false; }, ), orientation: AppOpenAd.orientationPortrait, ); } void showAdIfAvailable() { // 广告不存在或正在展示时,不执行展示逻辑 if (appOpenAd == null || _isShowingAd) return; _isShowingAd = true; appOpenAd!.show(); } }
2. 修正AppLifecycleReactor类
class AppLifecycleReactor { final AppOpenAdManager appOpenAdManager; AppLifecycleReactor({required this.appOpenAdManager}); void listenToAppStateChanges() { AppStateEventNotifier.startListening(); AppStateEventNotifier.appStateStream.listen((state) => _onAppStateChanged(state)); } void _onAppStateChanged(AppState appState) { // 仅在应用从后台切换至前台时触发广告展示 if (appState == AppState.foreground) { appOpenAdManager.showAdIfAvailable(); appOpenAdManager.loadAppOpenAd(); } } }
3. 修正main函数
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 确保广告SDK初始化完成再加载广告 await MobileAds.instance.initialize(); final cameras = await availableCameras(); final firstCamera = cameras.first; final SharedPreferences prefs = await SharedPreferences.getInstance(); final bool shown = prefs.getBool('carouselShown') ?? false; final String initialRoute = shown ? '/' : '/carousel'; // 初始化广告管理器和生命周期监听 final appOpenAdManager = AppOpenAdManager(); final appLifecycleReactor = AppLifecycleReactor(appOpenAdManager: appOpenAdManager); appLifecycleReactor.listenToAppStateChanges(); // 首次加载广告,为启动和后续前台切换做准备 appOpenAdManager.loadAppOpenAd(); runApp( ChangeNotifierProvider( create: (_) => SettingsProvider(), child: MaterialApp( debugShowCheckedModeBanner: false, title: "QR Code Scanner", theme: ThemeData(primaryColor: Colors.lightBlue.shade300), initialRoute: initialRoute, routes: <String, WidgetBuilder>{ '/': (BuildContext context) => const BottomNavigationBarPage(), '/carousel': (BuildContext context) => CarouselWithBackground( onCarouselCompleted: () async { await prefs.setBool('carouselShown', true); Navigator.of(context).pushReplacementNamed('/'); }, ), '/TakePictureScreen': (BuildContext context) => TakePictureScreen(camera: firstCamera), '/about': (BuildContext context) => AboutPage(), '/rate': (BuildContext context) => RateUsPage(), '/feedback': (BuildContext context) => FeedbackPage(), '/drawer': (BuildContext context) => SideMenuDrawer(), }, ), ), ); }
关键修复点说明
- 启动生命周期监听:在
main中创建AppLifecycleReactor并启动监听,确保应用状态变化时能触发广告展示逻辑。 - 分离加载与展示逻辑:仅在后台切前台时调用
showAdIfAvailable,广告加载后仅保存实例,不立即展示。 - 广告状态管理:添加
_isShowingAd标记防止重复展示,广告关闭或失败后重置状态并预加载下一个广告。 - 确保SDK初始化完成:给
MobileAds.instance.initialize()添加await,避免广告加载时SDK未就绪。
内容的提问来源于stack exchange,提问作者Hafsa Azram
相关产品推荐
相关产品推荐

