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

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

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

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

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

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

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

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

Android

ca-app-pub-3940256099942544/9257395921

iOS

ca-app-pub-3940256099942544/5575463023

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

הטמעה

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

  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 = Platform.isAndroid
    ? 'ca-app-pub-3940256099942544/9257395921'
    : 'ca-app-pub-3940256099942544/5575463023';
  
  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;
  }
}

טעינת מודעה

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

טעינת מודעה מתבצעת באמצעות השיטה load בכיתה AppOpenAd. שיטת הטעינה דורשת מזהה של יחידת מודעות, מצב כיוון, אובייקט AdRequest וטיפולן של סיום (completion handler) שנקרא כשהטעינה של המודעה מסתיימת בהצלחה או נכשלת. הפריטים שנטענו האובייקט AppOpenAd מסופק כפרמטר ב-handler של ההשלמה. הדוגמה הבאה מראה איך לטעון AppOpenAd.

public class AppOpenAdManager {
  ...

  /// Load an AppOpenAd.
  void loadAd() {
    AppOpenAd.load(
      adUnitId: adUnitId,
      adRequest: AdRequest(),
      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.load(
      adUnitId: adUnitId,
      orientation: AppOpenAd.orientationPortrait,
      adRequest: AdRequest(),
      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) היא כשמשתמש פותח את האפליקציה בפעם הראשונה. כשמפעילים את התכונה 'הפעלה במצב התחלתי', אין מודעה בפתיחת אפליקציה שנטענה בעבר ומוכנה ל יוצגו מיד. העיכוב בין הזמן שבו שולחים בקשה להצגת מודעה לבין הזמן שבו מקבלים מודעה חזרה יכול ליצור מצב שבו המשתמשים יכולים להשתמש באפליקציה לזמן קצר לפני שהם מופתעים ממודעה שלא קשורה להקשר. יש להימנע מכך, מפני חוויית משתמש גרועה.

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

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

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

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

דוגמה מלאה ב-GitHub

פתיחת האפליקציה