מודעות מותאמות מוצגות למשתמשים באמצעות רכיבי ממשק משתמש שמותאמים לפלטפורמה – לדוגמה, View
ב-Android או UIView
ב-iOS.
במדריך הזה מוסבר איך לטעון, להציג ולהתאים אישית מודעות מותאמות באמצעות קוד ספציפי לפלטפורמה.
דרישות מוקדמות
- כדאי לעיין במדריך לתחילת העבודה.
- מומלץ לקרוא את המאמר בנושא אפשרויות למודעות מותאמות.
תמיד כדאי לבצע בדיקות באמצעות מודעות בדיקה
כשמפתחים ובודקים אפליקציות, חשוב להשתמש במודעות בדיקה ולא במודעות פעילות שמוצגות למשתמשים. הדרך הכי קלה לטעון מודעות לבדיקה היא להשתמש במזהה הייעודי של יחידת המודעות לבדיקה של מודעות מותאמות:
Android
ca-app-pub-3940256099942544/2247696110
iOS
ca-app-pub-3940256099942544/3986624511
יחידות המודעות לבדיקה מוגדרות להחזרת מודעות בדיקה לכל בקשה, כך שתוכלו להשתמש בהן באפליקציות שלכם בזמן כתיבת קוד, בדיקה וניפוי באגים. רק הקפידו להחליף אותן במזהים של יחידות המודעות שלכם לפני פרסום האפליקציה.
הגדרות ספציפיות לפלטפורמה
כדי ליצור מודעות מותאמות, צריך לכתוב קוד ספציפי לפלטפורמה עבור iOS ו-Android, ואז לשנות את ההטמעה של Dart כדי לנצל את השינויים בקוד המותאם שביצעתם.
Android
ייבוא הפלאגין
ההטמעה של הפלאגין Google Mobile Ads ב-Android דורשת מחלקה שמטמיעה את NativeAdFactory
API. כדי להפנות ל-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
כל הטמעה של NativeAdFactory
חייבת להירשם באמצעות factoryId
, מזהה ייחודי של String
, כשמתקשרים אל MainActivity.configureFlutterEngine(FlutterEngine)
. הערך factoryId
ישמש בהמשך כשיוצרים מופע של מודעה מותאמת מקוד Dart.
אפשר להטמיע ולרשום NativeAdFactory
לכל פריסת מודעה מותאמת ייחודית שבה נעשה שימוש באפליקציה, או להשתמש בNativeAdFactory
יחיד לכל הפריסות.
חשוב לזכור שאם משתמשים ב-add-to-app, צריך לבטל את הרישום של 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 Mobile Ads ב-iOS מחייבת מחלקה שמטמיעה את FLTNativeAdFactory
API. יוצרים מחלקה שמטמיעה את NativeAdFactory
ומטמיעים את ה-method 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
צריך להיות רשום ב-registerNativeAdFactory:factoryId:nativeAdFactory:
עם factoryId
ומזהה String
ייחודי.
הערך factoryId
ישמש בהמשך כשיוצרים מופע של מודעה מותאמת
מקוד Dart.
אפשר להטמיע FLTNativeAdFactory
ולרשום אותו לכל פריסת מודעה מותאמת ייחודית שבה נעשה שימוש באפליקציה, או להשתמש ב-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 String _adUnitId = Platform.isAndroid
? 'ca-app-pub-3940256099942544/2247696110'
: 'ca-app-pub-3940256099942544/3986624511';
/// 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 AdRequest(),
// 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 String _adUnitId = Platform.isAndroid
? 'ca-app-pub-3940256099942544/2247696110'
: 'ca-app-pub-3940256099942544/3986624511';
/// 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 AdRequest(),
// 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
שמשויך למודעה המקורית מוסר מעץ הווידג'טים, ובקריאת החזרה AdListener.onAdFailedToLoad()
.
השלבים הבאים
- מידע נוסף על מודעות מותאמות זמין במדריך שלנו למודעות מותאמות.
- מדיניות והנחיות בנושא מודעות מותאמות
- כדאי לעיין בסיפורי הצלחה של לקוחות: מקרה לדוגמה 1, מקרה לדוגמה 2.