跳转至正文

为移动 Flutter 应用或游戏添加广告

如何使用 google_mobile_ads package 在 Flutter 中展示广告。

许多开发者通过广告为移动应用和游戏变现。这允许应用免费下载,从而提高应用的人气。

An illustration of a smartphone showing an ad

要向 Flutter 项目添加广告,请使用 Google 的移动广告平台 AdMob。本食谱演示如何使用 google_mobile_ads package 向应用或游戏添加横幅广告。

1. 获取 AdMob 应用 ID

#
  1. 前往 AdMob 并设置账户。这可能需要一些时间,因为你需要提供银行信息、签署合同等。

  2. AdMob 账户就绪后,在 AdMob 中创建两个应用:一个用于 Android,一个用于 iOS。

  3. 打开 App settings(应用设置)部分。

  4. 获取 Android 应用和 iOS 应用的 AdMob 应用 ID。它们类似 ca-app-pub-1234567890123456~1234567890。注意两个数字之间的波浪号 (~)。

    Screenshot from AdMob showing the location of the App ID

2. 平台特定配置

#

更新 Android 和 iOS 配置以包含你的应用 ID。

Android

#

Android

#

将 AdMob 应用 ID 添加到你的 Android 应用。

  1. 打开应用的 android/app/src/main/AndroidManifest.xml 文件。

  2. 添加新的 <meta-data> 标签。

  3. android:name 元素的值设为 com.google.android.gms.ads.APPLICATION_ID

  4. android:value 元素设为上一步获得的 AdMob 应用 ID。按所示用引号括起来:

    xml
    <manifest>
        <application>
            ...
    
            <!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 -->
            <meta-data
                android:name="com.google.android.gms.ads.APPLICATION_ID"
                android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
        </application>
    </manifest>
    

iOS

#

iOS

#

将 AdMob 应用 ID 添加到你的 iOS 应用。

  1. 打开应用的 ios/Runner/Info.plist 文件。

  2. key 标签包裹 GADApplicationIdentifier

  3. string 标签包裹你的 AdMob 应用 ID。该 AdMob 应用 ID 在第 1 步中创建。

    xml
    <key>GADApplicationIdentifier</key>
    <string>ca-app-pub-################~##########</string>
    

3. 添加 google_mobile_ads 插件

#

要将 google_mobile_ads 插件添加为依赖,运行 flutter pub add

flutter pub add google_mobile_ads

4. 初始化 Mobile Ads SDK

#

加载广告前需要初始化 Mobile Ads SDK。

  1. 调用 MobileAds.instance.initialize() 初始化 Mobile Ads SDK。

    dart
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      unawaited(MobileAds.instance.initialize());
    
      runApp(const MyApp());
    }
    

如上所示,在启动时运行初始化步骤,以便 AdMob SDK 在需要之前有足够时间完成初始化。

5. 加载横幅广告

#

要展示广告,你需要向 AdMob 请求广告。

要加载横幅广告,构造 BannerAd 实例并对其调用 load()

dart
/// Loads a banner ad.
void _loadAd() {
  final bannerAd = BannerAd(
    size: widget.adSize,
    adUnitId: widget.adUnitId,
    request: const AdRequest(),
    listener: BannerAdListener(
      // Called when an ad is successfully received.
      onAdLoaded: (ad) {
        if (!mounted) {
          ad.dispose();
          return;
        }
        setState(() {
          _bannerAd = ad as BannerAd;
        });
      },
      // Called when an ad request failed.
      onAdFailedToLoad: (ad, error) {
        debugPrint('BannerAd failed to load: $error');
        ad.dispose();
      },
    ),
  );

  // Start loading.
  bannerAd.load();
}

要查看完整示例,请参阅本食谱的最后一步。

6. 展示横幅广告

#

获得已加载的 BannerAd 实例后,使用 AdWidget 展示它。

dart
AdWidget(ad: _bannerAd)

建议用 SafeArea 包裹 widget(避免广告被设备刘海遮挡),并用 SizedBox 包裹(使加载前后具有指定的固定尺寸)。

dart
@override
Widget build(BuildContext context) {
  return SafeArea(
    child: SizedBox(
      width: widget.adSize.width.toDouble(),
      height: widget.adSize.height.toDouble(),
      child: _bannerAd == null
          // Nothing to render yet.
          ? const SizedBox()
          // The actual ad.
          : AdWidget(ad: _bannerAd!),
    ),
  );
}

不再需要访问广告时必须释放它。调用 dispose() 的最佳实践是在 AdWidget 从 widget 树移除后,或在 BannerAdListener.onAdFailedToLoad() 回调中调用。

dart
_bannerAd?.dispose();

7. 配置广告

#

要展示测试广告以外的内容,你必须注册广告单元。

  1. 打开 AdMob

  2. 为每个 AdMob 应用创建广告单元

    Screenshot of the location of Ad Units in AdMob web UI

    这会询问广告单元的格式。AdMob 提供横幅广告以外的多种格式 ——插页式广告、激励广告、应用开屏广告等。这些格式的 API 类似,记录在 Ad Manager 文档官方示例中。

  3. 选择横幅广告。

  4. 获取 Android 应用和 iOS 应用的广告单元 ID。你可以在 Ad units(广告单元)部分找到它们。它们类似 ca-app-pub-1234567890123456/1234567890。格式与应用 ID 类似,但两个数字之间是斜杠 (/) 而不是波浪号。这用于区分广告单元 ID应用 ID

    Screenshot of an Ad Unit ID in AdMob web UI

  5. 根据目标应用平台,将这些广告单元 ID 添加到 BannerAd 的构造函数中。

    dart
    final String adUnitId = Platform.isAndroid
        // Use this ad unit on Android...
        ? 'ca-app-pub-3940256099942544/6300978111'
        // ... or this one on iOS.
        : 'ca-app-pub-3940256099942544/2934735716';
    

8. 收尾工作

#

要在已发布的应用或游戏中展示广告(而非调试或测试场景),你的应用必须满足额外要求:

  1. 你的应用必须经过审核和批准才能完整投放广告。遵循 AdMob 的应用就绪指南。例如,你的应用必须至少上架 Google Play 商店或 Apple App Store 等受支持的商店之一。

  2. 你必须创建 app-ads.txt 文件并将其发布在开发者网站上。

An illustration of a smartphone showing an ad

要了解更多应用和游戏变现信息,请访问 AdMobAd Manager 的官方网站。

9. 完整示例

#

以下代码实现了一个加载并展示横幅广告的简单 stateful widget。

dart
import 'dart:io';

import 'package:flutter/widgets.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

class MyBannerAdWidget extends StatefulWidget {
  /// The requested size of the banner. Defaults to [AdSize.banner].
  final AdSize adSize;

  /// The AdMob ad unit to show.
  ///
  /// TODO: replace this test ad unit with your own ad unit
  final String adUnitId = Platform.isAndroid
      // Use this ad unit on Android...
      ? 'ca-app-pub-3940256099942544/6300978111'
      // ... or this one on iOS.
      : 'ca-app-pub-3940256099942544/2934735716';

  MyBannerAdWidget({super.key, this.adSize = AdSize.banner});

  @override
  State<MyBannerAdWidget> createState() => _MyBannerAdWidgetState();
}

class _MyBannerAdWidgetState extends State<MyBannerAdWidget> {
  /// The banner ad to show. This is `null` until the ad is actually loaded.
  BannerAd? _bannerAd;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: SizedBox(
        width: widget.adSize.width.toDouble(),
        height: widget.adSize.height.toDouble(),
        child: _bannerAd == null
            // Nothing to render yet.
            ? const SizedBox()
            // The actual ad.
            : AdWidget(ad: _bannerAd!),
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    _loadAd();
  }

  @override
  void dispose() {
    _bannerAd?.dispose();
    super.dispose();
  }

  /// Loads a banner ad.
  void _loadAd() {
    final bannerAd = BannerAd(
      size: widget.adSize,
      adUnitId: widget.adUnitId,
      request: const AdRequest(),
      listener: BannerAdListener(
        // Called when an ad is successfully received.
        onAdLoaded: (ad) {
          if (!mounted) {
            ad.dispose();
            return;
          }
          setState(() {
            _bannerAd = ad as BannerAd;
          });
        },
        // Called when an ad request failed.
        onAdFailedToLoad: (ad, error) {
          debugPrint('BannerAd failed to load: $error');
          ad.dispose();
        },
      ),
    );

    // Start loading.
    bannerAd.load();
  }

}