מודעות בפתיחת אפליקציה

מודעות בפתיחת אפליקציה הן פורמט מודעה מיוחד שמיועד לבעלי אפליקציות שרוצים לייצר הכנסות ממסכי הטעינה של האפליקציה. אפשר לסגור מודעות בפתיחת האפליקציה בכל שלב, והן נועדו להופיע כשהמשתמשים מעבירים את האפליקציה לחזית.

במודעות בפתיחת אפליקציה מוצג באופן אוטומטי אזור קטן של מיתוג כדי שהמשתמשים ידעו שהם נמצאים באפליקציה. לפניכם דוגמה למראה של מודעה בפתיחת אפליקציה:

דרישות מוקדמות

  • הפלאגין של Flutter מגרסה 0.13.6 ואילך.
  • משלימים את תחילת העבודה. הפלאגין של Google Mobile Ads ל-Flutter כבר אמור להיות מיובא לאפליקציה שלכם.

תמיד כדאי לבדוק באמצעות מודעות בדיקה

כשאתם מפתחים ובודקים את האפליקציות, חשוב להשתמש במודעות בדיקה במקום במודעות פעילות בסביבת הייצור. אם לא תעשו זאת, החשבון שלכם עלול להיחסם.

הדרך הקלה ביותר לטעון מודעות בדיקה היא להשתמש במזהי היחידות הייעודיים שלנו למודעות בדיקה של מודעות מתגמלות ל-Android ול-iOS:

  • /21775744923/example/app-open

הם מוגדרים במיוחד להחזרת מודעות בדיקה לכל בקשה, ואתם יכולים להשתמש בהם באפליקציות שלכם בזמן הכתיבה, הבדיקה ותיקון הבאגים. רק חשוב להחליף אותם במזהה יחידת המודעות שלכם לפני פרסום האפליקציה.

הטמעה

השלבים העיקריים לשילוב מודעות בפתיחת אפליקציה הם:

  1. יוצרים סוג שירות (utility class) שטעון מודעה לפני שצריך להציג אותה.
  2. טוענים מודעה.
  3. להירשם לשיחות חוזרות ולהציג את המודעה.
  4. כדי להציג את המודעה במהלך אירועים של העברת חזית, צריך להירשם ל-AppStateEventNotifier.appStateStream.

יצירת סוג שירות

יוצרים מחלקה חדשה בשם AppOpenAdManager כדי לטעון את המודעה. המחלקה הזו מנהלת משתנה מכונה כדי לעקוב אחרי מודעה טעונה ומזהה יחידת המודעות בכל פלטפורמה.

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;
  }
}

טעינת מודעה

המודעה בפתיחת האפליקציה צריכה להיות מוכנה לפני שהמשתמשים נכנסים לאפליקציה. כדאי להטמיע סיווג שירות כדי לשלוח בקשות להצגת מודעות לפני שצריך להציג את המודעה.

טעינת מודעה מתבצעת באמצעות השיטה loadWithAdManagerAdRequest בכיתה AppOpenAd. שיטת הטעינה דורשת מזהה של יחידת מודעות, מצב כיוון, אובייקט 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();
  }
}

הפעלות במצב התחלתי (cold start) ומסכי טעינה

עד כה, במסמכי העזרה התייחסנו רק למצב שבו מודעות בפתיחת אפליקציה מוצגות כשמשתמשים מעבירים את האפליקציה לחזית כשהיא מושהית בזיכרון. 'הפעלה קרה' מתרחשת כשהאפליקציה מופעלת אבל לא הושהתה בזיכרון לפני כן.

דוגמה להתחלה קרה היא כשמשתמש פותח את האפליקציה בפעם הראשונה. בהפעלות מצב התחלתי, לא תהיה לכם מודעה שהוטענה מראש בפתיחת האפליקציה ומוכנה להצגה באופן מיידי. העיכוב בין הזמן שבו שולחים בקשה להצגת מודעה לבין הזמן שבו מקבלים מודעה חזרה עלול ליצור מצב שבו המשתמשים יכולים להשתמש באפליקציה לזמן קצר לפני שהם מופתעים ממודעה שלא קשורה להקשר. רצוי להימנע מכך כי זוהי חוויית משתמש גרועה.

הדרך המועדפת להשתמש במודעות בפתיחת האפליקציה בהפעלה ראשונית היא להשתמש במסך טעינה כדי לטעון את נכסי המשחק או האפליקציה, ולהציג את המודעה רק מהמסך הזה. אם האפליקציה סיימה את הטעינה ושולחת את המשתמש לתוכן הראשי של האפליקציה, אל תציגו את המודעה.

שיטות מומלצות

מודעות בפתיחת האפליקציה עוזרות לכם לייצר הכנסות מדף הטעינה של האפליקציה, כשהאפליקציה מופעלת בפעם הראשונה ובמהלך מעברים בין אפליקציות, אבל חשוב להקפיד על השיטות המומלצות כדי שהמשתמשים ייהנו מהשימוש באפליקציה. מומלץ:

  • כדאי להציג את המודעה הראשונה בפתיחת האפליקציה אחרי שהמשתמשים השתמשו באפליקציה כמה פעמים.
  • כדאי להציג מודעות בפתיחת האפליקציה בזמנים שבהם המשתמשים היו ממתינים לטעינה של האפליקציה.
  • אם יש לכם מסך טעינה מתחת למודעה בפתיחת האפליקציה, והטעינה של מסך הטעינה מסתיימת לפני שהמודעה נסגרת, מומלץ לסגור את מסך הטעינה בטיפול באירוע onAdDismissedFullScreenContent.