הגדרות מותאמות ב-Android וב-iOS

מודעות מותאמות מוצגות למשתמשים שמשתמשים ברכיבי ממשק המשתמש של הפלטפורמה, כמו View ב-Android או UIView ב-iOS.

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

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

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

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

  • /6499/example/native

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

הגדרות ספציפיות לפלטפורמה

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

Android

ייבוא הפלאגין

כדי להטמיע את הפלאגין של מודעות Google לנייד ב-Android, נדרשת מחלקה שמטמיעה את ה-API של NativeAdFactory. כדי להפנות ל-API הזה מפרויקט Android שלכם, צריך להוסיף את השורות הבאות אל settings.gradle:

def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
    pluginsFile.withInputStream { stream -> plugins.load(stream) }
}

plugins.each { name, path ->
    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
    include ":$name"
    project(":$name").projectDir = pluginDirectory
}

הטמעת NativeAdFactory

בשלב הבא צריך ליצור מחלקה שמטמיעה בה את NativeAdFactory ומשנה את השיטה createNativeAd().

package io.flutter.plugins.googlemobileadsexample;

import android.graphics.Color;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin.NativeAdFactory;
import java.util.Map;

/**
 * my_native_ad.xml can be found at
 * github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/
 *     example/android/app/src/main/res/layout/my_native_ad.xml
 */
class NativeAdFactoryExample implements NativeAdFactory {
  private final LayoutInflater layoutInflater;

  NativeAdFactoryExample(LayoutInflater layoutInflater) {
    this.layoutInflater = layoutInflater;
  }

  @Override
  public NativeAdView createNativeAd(
      NativeAd nativeAd, Map<String, Object> customOptions) {
    final NativeAdView adView =
        (NativeAdView) layoutInflater.inflate(R.layout.my_native_ad, null);

    // Set the media view.
    adView.setMediaView((MediaView) adView.findViewById(R.id.ad_media));

    // Set other ad assets.
    adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
    adView.setBodyView(adView.findViewById(R.id.ad_body));
    adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
    adView.setIconView(adView.findViewById(R.id.ad_app_icon));
    adView.setPriceView(adView.findViewById(R.id.ad_price));
    adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
    adView.setStoreView(adView.findViewById(R.id.ad_store));
    adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));

    // The headline and mediaContent are guaranteed to be in every NativeAd.
    ((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
    adView.getMediaView().setMediaContent(nativeAd.getMediaContent());

    // These assets aren't guaranteed to be in every NativeAd, so it's important to
    // check before trying to display them.
    if (nativeAd.getBody() == null) {
      adView.getBodyView().setVisibility(View.INVISIBLE);
    } else {
      adView.getBodyView().setVisibility(View.VISIBLE);
      ((TextView) adView.getBodyView()).setText(nativeAd.getBody());
    }

    if (nativeAd.getCallToAction() == null) {
      adView.getCallToActionView().setVisibility(View.INVISIBLE);
    } else {
      adView.getCallToActionView().setVisibility(View.VISIBLE);
      ((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
    }

    if (nativeAd.getIcon() == null) {
      adView.getIconView().setVisibility(View.GONE);
    } else {
      ((ImageView) adView.getIconView()).setImageDrawable(nativeAd.getIcon().getDrawable());
      adView.getIconView().setVisibility(View.VISIBLE);
    }

    if (nativeAd.getPrice() == null) {
      adView.getPriceView().setVisibility(View.INVISIBLE);
    } else {
      adView.getPriceView().setVisibility(View.VISIBLE);
      ((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
    }

    if (nativeAd.getStore() == null) {
      adView.getStoreView().setVisibility(View.INVISIBLE);
    } else {
      adView.getStoreView().setVisibility(View.VISIBLE);
      ((TextView) adView.getStoreView()).setText(nativeAd.getStore());
    }

    if (nativeAd.getStarRating() == null) {
      adView.getStarRatingView().setVisibility(View.INVISIBLE);
    } else {
      ((RatingBar) adView.getStarRatingView()).setRating(nativeAd.getStarRating()
          .floatValue());
      adView.getStarRatingView().setVisibility(View.VISIBLE);
    }

    if (nativeAd.getAdvertiser() == null) {
      adView.getAdvertiserView().setVisibility(View.INVISIBLE);
    } else {
      adView.getAdvertiserView().setVisibility(View.VISIBLE);
      ((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
    }

    // This method tells the Google Mobile Ads SDK that you have finished populating your
    // native ad view with this native ad.
    adView.setNativeAd(nativeAd);

    return adView;
  }
}

דוגמה להגדרת הפריסה NativeAdView זמינה בכתובת my_native_ad.xml.

רישום ה-NativeAdFactory

כדי לבצע קריאה ל-MainActivity.configureFlutterEngine(FlutterEngine), צריך לרשום כל הטמעה של NativeAdFactory באמצעות factoryId, מזהה String ייחודי. factoryId ישמש בשלב מאוחר יותר כאשר מציגים מודעה מותאמת מקוד Dart.

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

שימו לב שכשמפתחים באמצעות הוספה לאפליקציה, צריך לבטל את הרישום של NativeAdFactory גם ב-cleanUpFlutterEngine(engine).

לאחר יצירת NativeAdFactoryExample, צריך להגדיר את MainActivity באופן הבא:

package my.app.path;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;

public class MainActivity extends FlutterActivity {
  @Override
  public void configureFlutterEngine(FlutterEngine flutterEngine) {
    flutterEngine.getPlugins().add(new GoogleMobileAdsPlugin());
    super.configureFlutterEngine(flutterEngine);

    GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine,
        "adFactoryExample", NativeAdFactoryExample());
  }

  @Override
  public void cleanUpFlutterEngine(FlutterEngine flutterEngine) {
    GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "adFactoryExample");
  }
}

iOS

הטמעת NativeAdFactory

כדי להטמיע את הפלאגין של מודעות Google לנייד ב-iOS, נדרשת מחלקה שמטמיעה את ה-API של FLTNativeAdFactory. יוצרים מחלקה שבה מוטמעת NativeAdFactory ומטמיעים את השיטה createNativeAd().

#import "FLTGoogleMobileAdsPlugin.h"

/**
 * The example NativeAdView.xib can be found at
 * github.com/googleads/googleads-mobile-flutter/blob/main/packages/google_mobile_ads/
 *     example/ios/Runner/NativeAdView.xib
 */
@interface NativeAdFactoryExample : NSObject <FLTNativeAdFactory>
@end

@implementation NativeAdFactoryExample
- (GADNativeAdView *)createNativeAd:(GADNativeAd *)nativeAd
                      customOptions:(NSDictionary *)customOptions {
  // Create and place the ad in the view hierarchy.
  GADNativeAdView *adView =
      [[NSBundle mainBundle] loadNibNamed:@"NativeAdView" owner:nil options:nil].firstObject;

  // Populate the native ad view with the native ad assets.
  // The headline is guaranteed to be present in every native ad.
  ((UILabel *)adView.headlineView).text = nativeAd.headline;

  // These assets are not guaranteed to be present. Check that they are before
  // showing or hiding them.
  ((UILabel *)adView.bodyView).text = nativeAd.body;
  adView.bodyView.hidden = nativeAd.body ? NO : YES;

  [((UIButton *)adView.callToActionView) setTitle:nativeAd.callToAction
                                         forState:UIControlStateNormal];
  adView.callToActionView.hidden = nativeAd.callToAction ? NO : YES;

  ((UIImageView *)adView.iconView).image = nativeAd.icon.image;
  adView.iconView.hidden = nativeAd.icon ? NO : YES;

  ((UILabel *)adView.storeView).text = nativeAd.store;
  adView.storeView.hidden = nativeAd.store ? NO : YES;

  ((UILabel *)adView.priceView).text = nativeAd.price;
  adView.priceView.hidden = nativeAd.price ? NO : YES;

  ((UILabel *)adView.advertiserView).text = nativeAd.advertiser;
  adView.advertiserView.hidden = nativeAd.advertiser ? NO : YES;

  // In order for the SDK to process touch events properly, user interaction
  // should be disabled.
  adView.callToActionView.userInteractionEnabled = NO;

  // Associate the native ad view with the native ad object. This is
  // required to make the ad clickable.
  // Note: this should always be done after populating the ad views.
  adView.nativeAd = nativeAd;

  return adView;
}
@end

דוגמה להגדרת הפריסה GADNativeAdView זמינה בכתובת NativeAdView.xib.

רישום ה-NativeAdFactory

כל FLTNativeAdFactory צריך להיות רשום באמצעות factoryId, מזהה String ייחודי, ב-registerNativeAdFactory:factoryId:nativeAdFactory:. השדה factoryId ישמש בשלב מאוחר יותר להצגת מודעה מותאמת מקוד Dart.

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

לאחר יצירת FLTNativeAdFactory, צריך להגדיר את AppDelegate באופן הבא:

#import "FLTGoogleMobileAdsPlugin.h"
#import "NativeAdFactoryExample.h"

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
      didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];

  // Must be added after GeneratedPluginRegistrant registerWithRegistry:self];
  // is called.
  NativeAdFactoryExample *nativeAdFactory = [[NativeAdFactoryExample alloc] init];
  [FLTGoogleMobileAdsPlugin registerNativeAdFactory:self
                                          factoryId:@"adFactoryExample"
                                    nativeAdFactory:nativeAdFactory];

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

טעינת המודעה

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

class NativeExampleState extends State<NativeExample> {
  NativeAd? _nativeAd;
  bool _nativeAdIsLoaded = false;

 // TODO: replace this test ad unit with your own ad unit.
 final _adUnitId = '/6499/example/native';

  /// Loads a native ad.
  void loadAd() {
    _nativeAd = NativeAd(
        adUnitId: _adUnitId,
        // Factory ID registered by your native ad factory implementation.
        factoryId: 'adFactoryExample',
        listener: NativeAdListener(
          onAdLoaded: (ad) {
            print('$NativeAd loaded.');
            setState(() {
              _nativeAdIsLoaded = true;
            });
          },
          onAdFailedToLoad: (ad, error) {
            // Dispose the ad here to free resources.
            print('$NativeAd failedToLoad: $error');
            ad.dispose();
          },
        ),
        request: const AdManagerAdRequest(),
        // Optional: Pass custom options to your native ad factory implementation.
        customOptions: {'custom-option-1', 'custom-value-1'}
    );
    _nativeAd.load();
  }
}

אירועים של מודעות מותאמות

כדי לקבל התראות על אירועים שקשורים לאינטראקציות עם המודעות המותאמות, צריך להשתמש בנכס listener של המודעה. לאחר מכן, צריך להטמיע את NativeAdListener כדי לקבל קריאות חוזרות (callback) מאירועי מודעה.

class NativeExampleState extends State<NativeExample> {
  NativeAd? _nativeAd;
  bool _nativeAdIsLoaded = false;

 // TODO: replace this test ad unit with your own ad unit.
 final _adUnitId = '/6499/example/native';

  /// Loads a native ad.
  void loadAd() {
    _nativeAd = NativeAd(
        adUnitId: _adUnitId,
        // Factory ID registered by your native ad factory implementation.
        factoryId: 'adFactoryExample',
        listener: NativeAdListener(
          onAdLoaded: (ad) {
            print('$NativeAd loaded.');
            setState(() {
              _nativeAdIsLoaded = true;
            });
          },
          onAdFailedToLoad: (ad, error) {
            // Dispose the ad here to free resources.
            print('$NativeAd failedToLoad: $error');
            ad.dispose();
          },
          // Called when a click is recorded for a NativeAd.
          onAdClicked: (ad) {},
          // Called when an impression occurs on the ad.
          onAdImpression: (ad) {},
          // Called when an ad removes an overlay that covers the screen.
          onAdClosed: (ad) {},
          // Called when an ad opens an overlay that covers the screen.
          onAdOpened: (ad) {},
          // For iOS only. Called before dismissing a full screen view
          onAdWillDismissScreen: (ad) {},
          // Called when an ad receives revenue value.
          onPaidEvent: (ad, valueMicros, precision, currencyCode) {},
        ),
        request: const AdManagerAdRequest(),
        // Optional: Pass custom options to your native ad factory implementation.
        customOptions: {'custom-option-1', 'custom-value-1'}
    );
    _nativeAd.load();
        
  }
}

מודעה ברשת המדיה

כדי להציג ווידג'ט של NativeAd, צריך ליצור AdWidget עם מודעה נתמכת אחרי שמפעילים את load(). אפשר ליצור את הווידג'ט לפני שמפעילים את load(), אבל צריך לקרוא ל-load() לפני שמוסיפים אותו לעץ הווידג'טים.

AdWidget יורש את המחלקה Widget של Flutter וניתן להשתמש בו כמו בכל ווידג'ט אחר. ב-iOS, חשוב לשים את הווידג'ט בקונטיינר עם רוחב וגובה שצוינו. אחרת, ייתכן שהמודעה שלך לא תוצג.

final Container adContainer = Container(
  alignment: Alignment.center,
  child: AdWidget adWidget = AdWidget(ad: _nativeAd!),
  width: WIDTH,
  height: HEIGHT,
);

הסרת המודעה

חובה להשליך את NativeAd כשאין יותר צורך בגישה אליו. השיטה המומלצת למתי כדאי להפעיל את dispose() היא לאחר הסרת ה-AdWidget המשויכת למודעה המותאמת מעץ הווידג'ט ובקריאה החוזרת (callback) AdListener.onAdFailedToLoad().