You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 21:15:05