Flutter中实现谷歌广告全局统一类的技术方案咨询
统一管理Google Ads的Flutter单类实现
实现思路
创建一个单例类封装所有广告类型(开屏、横幅、插屏、激励视频等)的加载、展示及回收逻辑,页面仅需调用对应方法即可,彻底避免重复代码。
完整单类代码实现
import 'package:flutter/material.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; class AdManager { // 单例实例,保证全局唯一 static final AdManager _instance = AdManager._internal(); factory AdManager() => _instance; AdManager._internal(); // 广告ID:替换为你的正式ID,测试阶段可使用谷歌提供的测试ID final String _appOpenAdId = 'ca-app-pub-3940256099942544/3419835294'; final String _bannerAdId = 'ca-app-pub-3940256099942544/6300978111'; final String _interstitialAdId = 'ca-app-pub-3940256099942544/1033173712'; final String _rewardedAdId = 'ca-app-pub-3940256099942544/5224354917'; // 广告实例缓存 AppOpenAd? _appOpenAd; BannerAd? _bannerAd; InterstitialAd? _interstitialAd; RewardedAd? _rewardedAd; // 初始化广告SDK Future<void> initialize() async { await MobileAds.instance.initialize(); // 预加载开屏广告(可选,根据业务需求调整) await _loadAppOpenAd(); } // --- 开屏广告 --- Future<void> _loadAppOpenAd() async { try { _appOpenAd = await AppOpenAd.load( adUnitId: _appOpenAdId, request: const AdRequest(), adLoadCallback: AppOpenAdLoadCallback( onAdLoaded: (ad) => _appOpenAd = ad, onAdFailedToLoad: (error) { print('开屏广告加载失败: $error'); _appOpenAd = null; }, ), orientation: AppOpenAd.orientationPortrait, ); } catch (e) { print('开屏广告加载异常: $e'); } } void showAppOpenAd() { if (_appOpenAd != null) { _appOpenAd!.show().then((_) { _appOpenAd = null; _loadAppOpenAd(); // 展示后自动预加载下一次 }).catchError((e) { print('开屏广告展示失败: $e'); _appOpenAd = null; _loadAppOpenAd(); }); } else { _loadAppOpenAd(); } } // --- 横幅广告 --- BannerAd? getBannerAd({required AdSize size}) { _bannerAd = BannerAd( adUnitId: _bannerAdId, size: size, request: const AdRequest(), listener: BannerAdListener( onAdLoaded: (_) => print('横幅广告加载完成'), onAdFailedToLoad: (ad, error) { ad.dispose(); print('横幅广告加载失败: $error'); }, ), ); _bannerAd!.load(); return _bannerAd; } void disposeBannerAd() { _bannerAd?.dispose(); _bannerAd = null; } // --- 插屏广告 --- Future<void> loadInterstitialAd() async { try { _interstitialAd = await InterstitialAd.load( adUnitId: _interstitialAdId, request: const AdRequest(), adLoadCallback: InterstitialAdLoadCallback( onAdLoaded: (ad) => _interstitialAd = ad, onAdFailedToLoad: (error) { print('插屏广告加载失败: $error'); _interstitialAd = null; }, ), ); } catch (e) { print('插屏广告加载异常: $e'); } } void showInterstitialAd({VoidCallback? onAdClosed}) { if (_interstitialAd != null) { _interstitialAd!.fullScreenContentCallback = FullScreenContentCallback( onAdDismissedFullScreenContent: (ad) { ad.dispose(); _interstitialAd = null; loadInterstitialAd(); // 关闭后预加载下一次 onAdClosed?.call(); }, onAdFailedToShowFullScreenContent: (ad, error) { ad.dispose(); _interstitialAd = null; loadInterstitialAd(); print('插屏广告展示失败: $error'); }, ); _interstitialAd!.show(); } else { loadInterstitialAd(); onAdClosed?.call(); } } // --- 激励视频广告 --- Future<void> loadRewardedAd() async { try { _rewardedAd = await RewardedAd.load( adUnitId: _rewardedAdId, request: const AdRequest(), rewardedAdLoadCallback: RewardedAdLoadCallback( onAdLoaded: (ad) => _rewardedAd = ad, onAdFailedToLoad: (error) { print('激励视频广告加载失败: $error'); _rewardedAd = null; }, ), ); } catch (e) { print('激励视频广告加载异常: $e'); } } void showRewardedAd({required Function(RewardItem) onUserEarnedReward}) { if (_rewardedAd != null) { _rewardedAd!.fullScreenContentCallback = FullScreenContentCallback( onAdDismissedFullScreenContent: (ad) { ad.dispose(); _rewardedAd = null; loadRewardedAd(); }, onAdFailedToShowFullScreenContent: (ad, error) { ad.dispose(); _rewardedAd = null; loadRewardedAd(); print('激励视频广告展示失败: $error'); }, ); _rewardedAd!.show(onUserEarnedReward: onUserEarnedReward); } else { loadRewardedAd(); } } // 全局销毁所有广告,避免内存泄漏 void disposeAllAds() { _appOpenAd?.dispose(); _bannerAd?.dispose(); _interstitialAd?.dispose(); _rewardedAd?.dispose(); } }
项目中使用示例
1. 全局初始化广告SDK
在main函数中完成初始化:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await AdManager().initialize(); runApp(const MyApp()); }
2. 页面调用广告
- 展示开屏广告(首页初始化时调用):
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { AdManager().showAppOpenAd(); }); }
- 展示横幅广告:
BannerAd? _bannerAd; @override void initState() { super.initState(); _bannerAd = AdManager().getBannerAd(size: AdSize.banner); } @override void dispose() { AdManager().disposeBannerAd(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('横幅广告示例')), body: Column( children: [ if (_bannerAd != null) Container( width: _bannerAd!.size.width.toDouble(), height: _bannerAd!.size.height.toDouble(), child: AdWidget(ad: _bannerAd!), ), // 其他页面内容 ], ), ); }
- 展示插屏广告(按钮点击触发):
ElevatedButton( onPressed: () { AdManager().showInterstitialAd( onAdClosed: () { // 广告关闭后的业务逻辑,比如跳转页面 }, ); }, child: const Text('展示插屏广告'), )
关键注意事项
- 替换所有广告ID为你的正式ID,测试阶段可使用谷歌官方提供的测试ID
- 广告加载失败时需处理重试逻辑,保证广告可用性
- 页面销毁时必须调用对应广告的
dispose方法,防止内存泄漏 - 激励视频广告需依赖
onUserEarnedReward回调确认用户完成观看后再发放奖励
内容的提问来源于stack exchange,提问作者Shani Malik
相关产品推荐
相关产品推荐

