إدارة "الإعلانات المدمجة مع المحتوى" في Android وiOS

يتم عرض "الإعلانات المدمجة مع المحتوى" للمستخدمين باستخدام مكوّنات واجهة المستخدم المدمجة في المنصة، مثل View على Android أو UIView على iOS.

يوضّح لك هذا الدليل كيفية تحميل "الإعلانات المدمجة مع المحتوى" وعرضها وتخصيصها باستخدام رمز برمجي خاص بالمنصة.

المتطلبات الأساسية

قبل المتابعة، عليك تنفيذ ما يلي:

اختبِر دائمًا باستخدام الإعلانات الاختبارية

عند إنشاء تطبيقاتك واختبارها، تأكَّد من استخدام الإعلانات الاختبارية بدلاً من الإعلانات المباشرة والإنتاجية. أسهل طريقة لتحميل الإعلانات الاختبارية هي استخدام معرّف الوحدة الإعلانية الاختبارية المخصّص للإعلانات المدمجة مع المحتوى:

Android

ca-app-pub-3940256099942544/2247696110

iOS

ca-app-pub-3940256099942544/3986624511

تم إعداد الوحدات الإعلانية الاختبارية لعرض إعلانات اختبارية لكل طلب، لذا يمكنك استخدامها في تطبيقاتك أثناء الترميز والاختبار وتصحيح الأخطاء، ولكن تأكَّد من استبدالها بمعرّفات الوحدات الإعلانية الخاصة بك قبل نشر تطبيقك.

عمليات الإعداد الخاصة بالمنصة

لإنشاء "الإعلانات المدمجة مع المحتوى"، عليك كتابة رمز برمجي خاص بالمنصة لنظامَي التشغيل iOS وAndroid، ثم تعديل تنفيذ Dart للاستفادة من تغييرات الرموز البرمجية الأصلية التي أجريتها.

Android

استيراد المكوّن الإضافي

يتطلّب تنفيذ المكوّن الإضافي "إعلانات Google على الأجهزة الجوّالة" في Android استخدام فئة تنفّذ واجهة برمجة التطبيقات NativeAdFactory. للإشارة إلى واجهة برمجة التطبيقات هذه من مشروع 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 وتسجيله لكل تنسيق إعلان مدمج مع المحتوى فريد يستخدمه تطبيقك، أو يمكن لتنسيق واحد التعامل مع جميع التنسيقات.

يُرجى العِلم أنّه عند إنشاء التطبيق باستخدام 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

يتطلّب تنفيذ المكوّن الإضافي "SDK لإعلانات Google على الأجهزة الجوّالة" في نظام التشغيل iOS استخدام فئة تنفّذ واجهة برمجة التطبيقات 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 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,
);

التخلّص من الإعلان

يجب التخلص من NativeAd عندما لا تعود هناك حاجة إلى الوصول إليه. أفضل الممارسات لتحديد وقت استدعاء dispose() هي بعد إزالة AdWidget المرتبط بـ "الإعلان المدمج مع المحتوى" من شجرة التطبيقات المصغّرة وفي دالة الاستدعاء AdListener.onAdFailedToLoad().

الخطوات التالية

مثال كامل على GitHub

للاطّلاع على المثال الكامل، يُرجى مراجعة العرض التوضيحي لواجهة برمجة التطبيقات.