จัดการโฆษณาเนทีฟใน Android และ iOS

ระบบจะแสดงโฆษณาเนทีฟต่อผู้ใช้โดยใช้คอมโพเนนต์ UI ที่เป็นของ แพลตฟอร์มนั้นๆ เช่น 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 Google Mobile Ads Flutter Plugin 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 ใน 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 และใช้เมธอด 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 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 เพื่อรับการเรียกกลับของเหตุการณ์โฆษณา

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,
);

ยกเลิกการจัดสรรโฆษณา

คุณต้องยกเลิกการจัดสรร A NativeAd เมื่อไม่จำเป็นต้องเข้าถึงโฆษณาอีกต่อไป แนวทางปฏิบัติแนะนำสำหรับเวลาที่ควรเรียก dispose() คือหลังจากนำ AdWidget ที่เชื่อมโยงกับโฆษณาเนทีฟออกจากแผนผังวิดเจ็ตแล้ว และในการเรียกกลับ AdListener.onAdFailedToLoad()

ขั้นตอนถัดไป

ตัวอย่างที่สมบูรณ์ใน GitHub

แพลตฟอร์มเนทีฟ