應用程式開啟頁面廣告

選取平台: Android iOS Unity Flutter

應用程式開啟頁面廣告是一種特殊廣告格式,適合希望藉由應用程式載入畫面賺取收益的發布商。應用程式開啟頁面廣告會在使用者將應用程式切換至前景時出現,而且使用者隨時可以關閉。

應用程式開啟頁面廣告會自動保留一小塊畫面,向使用者顯示應用程式的品牌資訊。以下是應用程式開啟頁面廣告的範例:

必要條件

  • Flutter 外掛程式 0.13.6 以上版本。
  • 完成「開始使用」。您的 Flutter 應用程式應已匯入 Google 行動廣告 Flutter 外掛程式。

一律使用測試廣告進行測試

建構及測試應用程式時,請務必使用測試廣告,而非實際的正式廣告。否則帳戶可能會遭到停權。

如要載入測試廣告,最簡單的方法是使用 Android 和 iOS 獎勵廣告專用的測試廣告單元 ID:

  • /21775744923/example/app-open

這些 ID 經過特別設定,可針對每項要求傳回測試廣告,您可以在編寫程式碼、測試及偵錯時,自由地在自己的應用程式中使用這些 ID。發布應用程式前,請務必將這些 ID 換成您自己的廣告單元 ID。

導入作業

整合應用程式開啟頁面廣告的主要步驟如下:

  1. 建立公用程式類別,在需要顯示廣告前載入廣告。
  2. 載入廣告。
  3. 註冊回呼並顯示廣告。
  4. 訂閱 AppStateEventNotifier.appStateStream,在前景事件期間顯示廣告。

建立公用程式類別

建立名為 AppOpenAdManager 的新類別,用於載入廣告。這個類別會管理執行個體變數,追蹤已載入的廣告,以及每個平台的廣告單元 ID。

import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'dart:io' show Platform;

class AppOpenAdManager {
  
  String adUnitId = '/21775744923/example/app-open';
  
  AppOpenAd? _appOpenAd;
  bool _isShowingAd = false;

  /// Load an AppOpenAd.
  void loadAd() {
    // We will implement this below.
  }

  /// Whether an ad is available to be shown.
  bool get isAdAvailable {
    return _appOpenAd != null;
  }
}

載入廣告

使用者進入應用程式前,應用程式開啟頁面廣告必須已準備就緒。請導入公用程式類別,在需要顯示廣告前發出廣告請求。

載入廣告時,請使用 AppOpenAd 類別的 loadWithAdManagerAdRequest 方法。載入方法需要廣告單元 ID、螢幕方向模式、AdManagerAdRequest 物件,以及廣告載入成功或失敗時呼叫的完成處理常式。載入的 AppOpenAd 物件會以參數形式提供給完成處理常式。以下範例說明如何載入 AppOpenAd

public class AppOpenAdManager {
  ...

  /// Load an AppOpenAd.
  void loadAd() {
    AppOpenAd.loadWithAdManagerAdRequest(
      adUnitId: adUnitId,
      adManagerAdRequest: AdManagerAdRequest(),
      adLoadCallback: AppOpenAdLoadCallback(
        onAdLoaded: (ad) {
          _appOpenAd = ad;
        },
        onAdFailedToLoad: (error) {
          print('AppOpenAd failed to load: $error');
          // Handle the error.
        },
      ),
    );
  }
}

顯示廣告並處理全螢幕回呼

顯示廣告前,請為要監聽的每個廣告事件註冊 FullScreenContentCallback

public class AppOpenAdManager {
  ...

  public void showAdIfAvailable() {
    if (!isAdAvailable) {
      print('Tried to show ad before available.');
      loadAd();
      return;
    }
    if (_isShowingAd) {
      print('Tried to show ad while already showing an ad.');
      return;
    }
    // Set the fullScreenContentCallback and show the ad.
    _appOpenAd!.fullScreenContentCallback = FullScreenContentCallback(
      onAdShowedFullScreenContent: (ad) {
        _isShowingAd = true;
        print('$ad onAdShowedFullScreenContent');
      },
      onAdFailedToShowFullScreenContent: (ad, error) {
        print('$ad onAdFailedToShowFullScreenContent: $error');
        _isShowingAd = false;
        ad.dispose();
        _appOpenAd = null;
      },
      onAdDismissedFullScreenContent: (ad) {
        print('$ad onAdDismissedFullScreenContent');
        _isShowingAd = false;
        ad.dispose();
        _appOpenAd = null;
        loadAd();
      },
    );
  }
}

如果使用者點選應用程式開啟廣告離開應用程式,然後返回,請確保他們不會看到其他應用程式開啟廣告。

監聽應用程式前景事件

如要接收應用程式前景事件的通知,請訂閱 AppStateEventNotifier.appStateStream 並監聽 foreground 事件。

import 'package:app_open_example/app_open_ad_manager.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

/// Listens for app foreground events and shows app open ads.
class AppLifecycleReactor {
  final AppOpenAdManager appOpenAdManager;

  AppLifecycleReactor({required this.appOpenAdManager});

  void listenToAppStateChanges() {
    AppStateEventNotifier.startListening();
    AppStateEventNotifier.appStateStream
        .forEach((state) => _onAppStateChanged(state));
  }

  void _onAppStateChanged(AppState appState) {
    // Try to show an app open ad if the app is being resumed and
    // we're not already showing an app open ad.
    if (appState == AppState.foreground) {
      appOpenAdManager.showAdIfAvailable();
    }
  }
}

現在您可以初始化 AppLifecycleReactor,並開始監聽應用程式生命週期變更。舉例來說,在首頁上:

import 'package:app_open_example/app_open_ad_manager.dart';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

import 'app_lifecycle_reactor.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  MobileAds.instance.initialize();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'App Open Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'App Open Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

/// Example home page for an app open ad.
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  late AppLifecycleReactor _appLifecycleReactor;

  @override
  void initState() {
    super.initState();
    
    AppOpenAdManager appOpenAdManager = AppOpenAdManager()..loadAd();
    _appLifecycleReactor = AppLifecycleReactor(
      appOpenAdManager: appOpenAdManager);
  }

考慮廣告效期

為避免顯示已失效的廣告,請在 AppOpenAdManager 中加入時間戳記,以便檢查廣告目前已載入多久。然後使用該時間戳記檢查廣告是否仍有效。

/// Utility class that manages loading and showing app open ads.
class AppOpenAdManager {
  ...
  
  /// Maximum duration allowed between loading and showing the ad.
  final Duration maxCacheDuration = Duration(hours: 4);

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

  /// Load an AppOpenAd.
  void loadAd() {
    AppOpenAd.loadWithAdManagerAdRequest(
      adUnitId: adUnitId,
      orientation: AppOpenAd.orientationPortrait,
      adManagerAdRequest: AdManagerAdRequest(),
      adLoadCallback: AppOpenAdLoadCallback(
        onAdLoaded: (ad) {
          print('$ad loaded');
          _appOpenLoadTime = DateTime.now();
          _appOpenAd = ad;
        },
        onAdFailedToLoad: (error) {
          print('AppOpenAd failed to load: $error');
        },
      ),
    );
  }

  /// Shows the ad, if one exists and is not already being shown.
  ///
  /// If the previously cached ad has expired, this just loads and caches a
  /// new ad.
  void showAdIfAvailable() {
    if (!isAdAvailable) {
      print('Tried to show ad before available.');
      loadAd();
      return;
    }
    if (_isShowingAd) {
      print('Tried to show ad while already showing an ad.');
      return;
    }
    if (DateTime.now().subtract(maxCacheDuration).isAfter(_appOpenLoadTime!)) {
      print('Maximum cache duration exceeded. Loading another ad.');
      _appOpenAd!.dispose();
      _appOpenAd = null;
      loadAd();
      return;
    }
    // Set the fullScreenContentCallback and show the ad.
    _appOpenAd!.fullScreenContentCallback = FullScreenContentCallback(...);
    _appOpenAd!.show();
  }
}

冷啟動和載入畫面

目前為止,文件都假設您只會在使用者將應用程式從記憶體中恢復到前景時,顯示應用程式開啟頁面廣告。如果應用程式啟動時未在記憶體中暫停,就會發生「冷啟動」。

舉例來說,使用者第一次開啟應用程式時,就是冷啟動。 冷啟動時,您不會有先前載入的應用程式開啟頁面廣告,因此無法立即顯示。如果您要求廣告後,廣告過一段時間才傳回,使用者可能會在看到與內容無關的廣告前,短暫使用您的應用程式。這會造成使用者體驗不佳,建議您不要採用。

如要在冷啟動時放送應用程式開啟頁面廣告,建議使用載入畫面載入遊戲或應用程式素材資源,並只在載入畫面中顯示廣告。如果應用程式已完成載入,並將使用者帶往應用程式的主要內容,請勿顯示廣告。

最佳做法

應用程式開啟頁面廣告可協助您在應用程式首次啟動及切換期間,透過應用程式的載入畫面營利,但請務必遵守最佳做法,確保使用者享有良好的應用程式體驗。建議您:

  • 等使用者用過應用程式幾次之後,再放送第一則應用程式開啟頁面廣告。
  • 在使用者等待應用程式載入時,放送應用程式開啟頁面廣告。
  • 如果載入畫面顯示在應用程式開啟頁面廣告的背景中,且載入畫面在廣告關閉前就完成載入,建議您利用 onAdDismissedFullScreenContent 事件處理常式關閉載入畫面。