إعداد حزمة تطوير البرامج لإعلانات الوسائط التفاعلية لعرض الإعلانات أثناء التشغيل

تسهّل حِزم تطوير البرامج (SDK) لإعلانات الوسائط التفاعلية دمج إعلانات الوسائط المتعددة في مواقعك الإلكترونية وتطبيقاتك. يمكن لحِزم تطوير البرامج لإعلانات الوسائط التفاعلية طلب الإعلانات من أي خادم إعلانات متوافق مع VAST وإدارة تشغيل الإعلانات في تطبيقاتك. باستخدام حِزم تطوير البرامج لإدراج الإعلانات الديناميكي في "إعلانات الوسائط التفاعلية"، تقدّم التطبيقات طلب بث لإعلان وفيديو محتوى، سواء كان فيديو عند الطلب أو محتوى مباشرًا. بعد ذلك، تعرض حزمة SDK بث فيديو مدمجًا، ما يغنيك عن إدارة التبديل بين الفيديو الإعلاني والفيديو الخاص بالمحتوى داخل تطبيقك.

اختيار حلّ "الإعلانات الديناميكية أثناء عرض الفيديو" الذي يهمّك

إدراج إعلان ديناميكي شامل

يوضّح هذا الدليل كيفية دمج حزمة تطوير البرامج (SDK) الخاصة بـ "الإعلانات الديناميكية أثناء عرض الفيديو" من "إعلانات الوسائط التفاعلية" في تطبيق بسيط لمشغّل فيديو. إذا أردت الاطّلاع على نموذج تكامل مكتمل أو اتّباعه، نزِّل BasicExample من GitHub.

نظرة عامة على "الإعلانات الديناميكية أثناء البث" من "إعلانات الوسائط

يتضمّن تنفيذ "إعلانات الوسائط الديناميكية" في "إعلانات الوسائط التفاعلية" أربعة مكوّنات رئيسية في حزمة SDK كما هو موضّح في هذا الدليل:

  • IMAAdDisplayContainer – عنصر حاوية يظهر فوق عنصر تشغيل الفيديو ويضم عناصر واجهة مستخدم الإعلان.
  • IMAAdsLoader – كائن يطلب عمليات بث ويتعامل مع الأحداث التي يتم تشغيلها بواسطة كائنات استجابة طلب البث. يجب إنشاء أداة تحميل إعلانات واحدة فقط، ويمكن إعادة استخدامها طوال مدة تشغيل التطبيق.
  • IMAStreamRequest – إما IMAVODStreamRequest أو IMALiveStreamRequest كائن يحدّد طلب بث. يمكن أن تكون طلبات البث المباشر خاصة بفيديوهات عند الطلب أو أحداث بث مباشر. تحدّد طلبات البث المباشر مفتاح مادة عرض، بينما تحدّد طلبات الفيديو عند الطلب معرّفًا في "نظام إدارة المحتوى" ومعرّف فيديو. يمكن أن يتضمّن كلا نوعَي الطلبات اختياريًا مفتاح واجهة برمجة تطبيقات مطلوبًا للوصول إلى عمليات البث المحدّدة، ورمز شبكة "مدير إعلانات Google" لكي تتعامل أداة تطوير البرامج لإعلانات الوسائط التفاعلية من Google مع معرّفات الإعلانات على النحو المحدّد في إعدادات "مدير إعلانات Google".
  • IMAStreamManager – عنصر يعالج عمليات بث "إدراج الإعلان الديناميكي" والتفاعلات مع الخلفية البرمجية لهذه الميزة. يتولّى مدير البث أيضًا معالجة طلبات اختبار الاتصال الخاصة بالتتبُّع وإعادة توجيه أحداث البث والإعلانات إلى الناشر.

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

قبل البدء، يجب أن يتوفّر لديك ما يلي:

تحتاج أيضًا إلى المَعلمات المستخدَمة لطلب البث من "حزمة تطوير البرامج لإعلانات الوسائط التفاعلية". للاطّلاع على أمثلة على مَعلمات الطلب، راجِع نماذج البث.

مَعلمات البث المباشر
مفتاح مادة العرض مفتاح مادة العرض الذي يحدّد بثّك المباشر في "مدير إعلانات Google"
مثال: c-rArva4ShKVIAkNfy6HUQ
مَعلمات بث الفيديو عند الطلب
معرّف مصدر المحتوى معرّف مصدر المحتوى من "مدير إعلانات Google".
مثال: 2548831
معرّف الفيديو معرّف الفيديو من "مدير إعلانات Google"
مثال: tears-of-steel
المَعلمات الشائعة (الفيديوهات عند الطلب والبث المباشر)
رمز الشبكة رمز شبكة "مدير إعلانات Google"
مثال: 21775744923

إنشاء مشروع Xcode جديد

في Xcode، أنشئ مشروع iOS جديدًا باستخدام Objective-C باسم "BasicExample".

إضافة حزمة تطوير البرامج (SDK) لميزة "الإعلانات الديناميكية أثناء البث" من "إعلانات الوسائط التفاعلية" إلى مشروع Xcode

استخدِم إحدى الطرق الثلاث التالية لتثبيت حزمة تطوير البرامج (SDK) الخاصة بميزة "الإعلانات الديناميكية أثناء عرض الفيديو" في "إعلانات الوسائط التفاعلية".

تثبيت حزمة تطوير البرامج (SDK) باستخدام CocoaPods (الخيار المفضّل)

‫CocoaPods هي أداة لإدارة الملحقات في مشاريع Xcode، وهي الطريقة المقترَحة لتثبيت حزمة تطوير البرامج (SDK) الخاصة بـ "الإعلانات الديناميكية أثناء عرض الفيديو" من "إعلانات الوسائط التفاعلية". لمزيد من المعلومات حول تثبيت CocoaPods أو استخدامه، يُرجى الاطّلاع على مستندات CocoaPods. بعد تثبيت CocoaPods، اتّبِع التعليمات التالية لتثبيت حزمة تطوير البرامج IMA DAI SDK:

  1. في الدليل نفسه الذي يحتوي على ملف BasicExample.xcodeproj، أنشئ ملفًا نصيًا باسم Podfile وأضِف الإعداد التالي:

    source 'https://github.com/CocoaPods/Specs.git'
    
    platform :ios, '14'
    
    target 'BasicExample' do
      pod 'GoogleAds-IMA-iOS-SDK', '~> 3.26.1'
    end
    

  2. من الدليل الذي يحتوي على Podfile، نفِّذ ما يلي:

    pod install --repo-update

تثبيت حزمة تطوير البرامج (SDK) باستخدام Swift Package Manager

تتوافق حزمة تطوير البرامج لإعلانات الوسائط التفاعلية مع Swift Package Manager بدءًا من الإصدار 3.18.4. اتّبِع الخطوات التالية لاستيراد حزمة Swift.

  1. في Xcode، ثبِّت حزمة IMA DAI SDK Swift Package من خلال الانتقال إلى ملف > إضافة حِزم.

  2. في الطلب الذي يظهر، ابحث عن مستودع IMA DAI SDK Swift Package GitHub:

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-ios
    
  3. اختَر إصدار حزمة IMA DAI SDK Swift Package الذي تريد استخدامه. بالنسبة إلى المشاريع الجديدة، ننصحك باستخدام الترقية إلى الإصدار الرئيسي التالي.

بعد الانتهاء، يحلّ Xcode التبعيات المرتبطة بحِزمك وينزّلها في الخلفية. لمزيد من التفاصيل حول كيفية إضافة تبعيات الحِزم، يُرجى الاطّلاع على مقالة Apple.

تنزيل حزمة تطوير البرامج (SDK) وتثبيتها يدويًا

إذا كنت لا تريد استخدام Swift Package Manager أو CocoaPods، يمكنك تنزيل حزمة تطوير البرامج (SDK) الخاصة بـ "إعلانات الوسائط التفاعلية" (DAI) وإضافتها يدويًا إلى مشروعك.

إنشاء مشغّل فيديو بسيط

نفِّذ مشغّل فيديو في وحدة التحكّم الرئيسية في العرض، وذلك باستخدام مشغّل AV مضمّن في عرض واجهة المستخدم. تستخدِم حزمة تطوير البرامج لإعلانات الوسائط التفاعلية عرض واجهة المستخدم لعرض عناصر واجهة المستخدم الخاصة بالإعلانات.

Objective-C

#import "ViewController.h"

#import <AVKit/AVKit.h>

/// Content URL.
static NSString *const kBackupContentUrl =
    @"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";

@interface ViewController ()
/// Play button.
@property(nonatomic, weak) IBOutlet UIButton *playButton;

@property(nonatomic, weak) IBOutlet UIView *videoView;
/// Video player.
@property(nonatomic, strong) AVPlayer *videoPlayer;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor blackColor];

  // Load AVPlayer with the path to your content.
  NSURL *contentURL = [NSURL URLWithString:kBackupContentUrl];
  self.videoPlayer = [AVPlayer playerWithURL:contentURL];

  // Create a player layer for the player.
  AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.videoPlayer];

  // Size, position, and display the AVPlayer.
  playerLayer.frame = self.videoView.layer.bounds;
  [self.videoView.layer addSublayer:playerLayer];
}

- (IBAction)onPlayButtonTouch:(id)sender {
  [self.videoPlayer play];
  self.playButton.hidden = YES;
}

@end

Swift

// Copyright 2024 Google LLC. All rights reserved.
//
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under
// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
// ANY KIND, either express or implied. See the License for the specific language governing
// permissions and limitations under the License.

import AVFoundation
import UIKit

class ViewController: UIViewController {

  /// Content URL.
  static let backupStreamURLString =
    "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"

  /// Play button.
  @IBOutlet private weak var playButton: UIButton!

  @IBOutlet private weak var videoView: UIView!
  /// Video player.
  private var videoPlayer: AVPlayer?

  override func viewDidLoad() {
    super.viewDidLoad()

    playButton.layer.zPosition = CGFloat(MAXFLOAT)

    // Load AVPlayer with path to our content.
    // note: this unwrap is safe because the URL is a constant string.
    let contentURL = URL(string: ViewController.backupStreamURLString)!
    videoPlayer = AVPlayer(url: contentURL)

    // Create a player layer for the player.
    let playerLayer = AVPlayerLayer(player: videoPlayer)

    // Size, position, and display the AVPlayer.
    playerLayer.frame = videoView.layer.bounds
    videoView.layer.addSublayer(playerLayer)
  }

  @IBAction func onPlayButtonTouch(_ sender: Any) {
    videoPlayer?.play()
    playButton.isHidden = true
  }
}

إعداد أداة تحميل الإعلانات

استورِد حزمة IMA SDK إلى وحدة التحكّم في العرض، واستخدِم البروتوكولَين IMAAdsLoaderDelegate و IMAStreamManagerDelegate للتعامل مع أحداث أداة تحميل الإعلانات وأداة إدارة البث.

أضِف هذه السمات الخاصة لتخزين المكوّنات الأساسية في "أداة تطوير البرامج لإعلانات الوسائط التفاعلية":

  • IMAAdsLoader: يدير طلبات البث طوال مدة استخدام تطبيقك.
  • IMAAdDisplayContainer: يتولّى إدراج عناصر واجهة مستخدم الإعلان وإدارتها.
  • IMAAVPlayerVideoDisplay: تتواصل هذه الحزمة بين "حزمة تطوير البرامج لإعلانات الوسائط التفاعلية" ومشغّل الوسائط، وتتعامل مع البيانات الوصفية المحدّدة بوقت.
  • IMAStreamManager - تُستخدَم لإدارة تشغيل البث المباشر وتفعيل الأحداث المرتبطة بالإعلانات.

يجب تهيئة أداة تحميل الإعلانات وحاوية عرض الإعلانات وعرض الفيديو بعد تحميل طريقة العرض.

Objective-C

@import GoogleInteractiveMediaAds;

// ...

@interface ViewController () <IMAAdsLoaderDelegate, IMAStreamManagerDelegate>
/// The entry point for the IMA DAI SDK to make DAI stream requests.
@property(nonatomic, strong) IMAAdsLoader *adsLoader;
/// The container where the SDK renders each ad's user interface elements and companion slots.
@property(nonatomic, strong) IMAAdDisplayContainer *adDisplayContainer;
/// The reference of your video player for the IMA DAI SDK to monitor playback and handle timed
/// metadata.
@property(nonatomic, strong) IMAAVPlayerVideoDisplay *imaVideoDisplay;
/// References the stream manager from the IMA DAI SDK after successful stream loading.
@property(nonatomic, strong) IMAStreamManager *streamManager;

// ...

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  // ...

  self.adsLoader = [[IMAAdsLoader alloc] initWithSettings:nil];
  self.adsLoader.delegate = self;

  // Create an ad display container for rendering each ad's user interface elements and companion
  // slots.
  self.adDisplayContainer =
      [[IMAAdDisplayContainer alloc] initWithAdContainer:self.videoView
                                          viewController:self
                                          companionSlots:nil];

  // Create an IMAAVPlayerVideoDisplay to give the SDK access to your video player.
  self.imaVideoDisplay = [[IMAAVPlayerVideoDisplay alloc] initWithAVPlayer:self.videoPlayer];
}

Swift

import GoogleInteractiveMediaAds
// ...

class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAStreamManagerDelegate {
  // ...

  /// The entry point for the IMA DAI SDK to make DAI stream requests.
  private var adsLoader: IMAAdsLoader?
  /// The container where the SDK renders each ad's user interface elements and companion slots.
  private var adDisplayContainer: IMAAdDisplayContainer?
  /// The reference of your video player for the IMA DAI SDK to monitor playback and handle timed
  /// metadata.
  private var imaVideoDisplay: IMAAVPlayerVideoDisplay!
  /// References the stream manager from the IMA DAI SDK after successfully loading the DAI stream.
  private var streamManager: IMAStreamManager?

  // ...

  override func viewDidLoad() {
    super.viewDidLoad()

    // ...

    adsLoader = IMAAdsLoader(settings: nil)
    adsLoader?.delegate = self

    // Create an ad display container for rendering ad UI elements and the companion ad.
    adDisplayContainer = IMAAdDisplayContainer(
      adContainer: videoView,
      viewController: self,
      companionSlots: nil)

    // Create an IMAAVPlayerVideoDisplay to give the SDK access to your video player.
    imaVideoDisplay = IMAAVPlayerVideoDisplay(avPlayer: videoPlayer)
  }

تقديم طلب بث

عندما يضغط المستخدم على زر التشغيل، أرسِل طلبًا جديدًا للبث. استخدِم فئة IMALiveStreamRequest للبث المباشر. بالنسبة إلى بث المحتوى عند الطلب، استخدِم الفئة IMAVODStreamRequest.

يتطلّب طلب البث مَعلمات البث، بالإضافة إلى مرجع إلى حاوية عرض الإعلان وعرض الفيديو.

Objective-C

- (IBAction)onPlayButtonTouch:(id)sender {
  [self requestStream];
  self.playButton.hidden = YES;
}

- (void)requestStream {
  // Create a stream request. Use one of "Live stream request" or "VOD request", depending on your
  // type of stream.
  IMAStreamRequest *request;
  if (kStreamType == StreamTypeLive) {
    // Live stream request. Replace the asset key with your value.
    request = [[IMALiveStreamRequest alloc] initWithAssetKey:kLiveStreamAssetKey
                                                 networkCode:kNetworkCode
                                          adDisplayContainer:self.adDisplayContainer
                                                videoDisplay:self.imaVideoDisplay
                                                 userContext:nil];
  } else {
    // VOD request. Replace the content source ID and video ID with your values.
    request = [[IMAVODStreamRequest alloc] initWithContentSourceID:kVODContentSourceID
                                                           videoID:kVODVideoID
                                                       networkCode:kNetworkCode
                                                adDisplayContainer:self.adDisplayContainer
                                                      videoDisplay:self.imaVideoDisplay
                                                       userContext:nil];
  }
  [self.adsLoader requestStreamWithRequest:request];
}

Swift

@IBAction func onPlayButtonTouch(_ sender: Any) {
  requestStream()
  playButton.isHidden = true
}

func requestStream() {
  // Create a stream request. Use one of "Livestream request" or "VOD request".
  if ViewController.requestType == StreamType.live {
    // Livestream request.
    let request = IMALiveStreamRequest(
      assetKey: ViewController.assetKey,
      networkCode: ViewController.networkCode,
      adDisplayContainer: adDisplayContainer!,
      videoDisplay: imaVideoDisplay,
      userContext: nil)
    adsLoader?.requestStream(with: request)
  } else {
    // VOD stream request.
    let request = IMAVODStreamRequest(
      contentSourceID: ViewController.contentSourceID,
      videoID: ViewController.videoID,
      networkCode: ViewController.networkCode,
      adDisplayContainer: adDisplayContainer!,
      videoDisplay: imaVideoDisplay,
      userContext: nil)
    adsLoader?.requestStream(with: request)
  }
}

الاستماع إلى أحداث تحميل البث

يستدعي الصف IMAAdsLoader الطريقتَين IMAAdsLoaderDelegate عند نجاح عملية الإعداد أو تعذُّر طلب البث.

في طريقة التفويض adsLoadedWithData، اضبط IMAStreamManagerDelegate. تهيئة أداة إدارة البث عند بدء التشغيل، يبدأ مدير البث تشغيل الفيديو.

في طريقة التفويض failedWithErrorData، سجِّل الخطأ. يمكنك تشغيل البث الاحتياطي. اطّلِع على أفضل الممارسات المتعلّقة بميزة "الإعلانات الديناميكية أثناء عرض الفيديو".

Objective-C

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  NSLog(@"Stream created with: %@.", adsLoadedData.streamManager.streamId);
  self.streamManager = adsLoadedData.streamManager;
  self.streamManager.delegate = self;
  [self.streamManager initializeWithAdsRenderingSettings:nil];
}

- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
  // Log the error and play the content.
  NSLog(@"AdsLoader error, code:%ld, message: %@", adErrorData.adError.code,
        adErrorData.adError.message);
  [self.videoPlayer play];
}

Swift

func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
  print("DAI stream loaded. Stream session ID: \(adsLoadedData.streamManager!.streamId!)")
  streamManager = adsLoadedData.streamManager!
  streamManager!.delegate = self
  streamManager!.initialize(with: nil)
}

func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
  print("Error loading DAI stream. Error message: \(adErrorData.adError.message!)")
  // Play the backup stream.
  videoPlayer.play()
}

الاستماع إلى أحداث الإعلانات

يستدعي IMAStreamManager طُرق IMAStreamManagerDelegate لتمرير أحداث البث والأخطاء إلى تطبيقك.

في هذا المثال، سجِّل أحداث الإعلان الأساسية في وحدة التحكّم:

Objective-C

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdEvent:(IMAAdEvent *)event {
  NSLog(@"Ad event (%@).", event.typeString);
  switch (event.type) {
    case kIMAAdEvent_STARTED: {
      // Log extended data.
      NSString *extendedAdPodInfo = [[NSString alloc]
          initWithFormat:@"Showing ad %ld/%ld, bumper: %@, title: %@, description: %@, contentType:"
                         @"%@, pod index: %ld, time offset: %lf, max duration: %lf.",
                         (long)event.ad.adPodInfo.adPosition, (long)event.ad.adPodInfo.totalAds,
                         event.ad.adPodInfo.isBumper ? @"YES" : @"NO", event.ad.adTitle,
                         event.ad.adDescription, event.ad.contentType,
                         (long)event.ad.adPodInfo.podIndex, event.ad.adPodInfo.timeOffset,
                         event.ad.adPodInfo.maxDuration];

      NSLog(@"%@", extendedAdPodInfo);
      break;
    }
    case kIMAAdEvent_AD_BREAK_STARTED: {
      NSLog(@"Ad break started");
      break;
    }
    case kIMAAdEvent_AD_BREAK_ENDED: {
      NSLog(@"Ad break ended");
      break;
    }
    case kIMAAdEvent_AD_PERIOD_STARTED: {
      NSLog(@"Ad period started");
      break;
    }
    case kIMAAdEvent_AD_PERIOD_ENDED: {
      NSLog(@"Ad period ended");
      break;
    }
    default:
      break;
  }
}

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdError:(IMAAdError *)error {
  NSLog(@"StreamManager error with type: %ld\ncode: %ld\nmessage: %@", error.type, error.code,
        error.message);
  [self.videoPlayer play];
}

Swift

func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
  print("Ad event \(event.typeString).")
  switch event.type {
  case IMAAdEventType.STARTED:
    // Log extended data.
    if let ad = event.ad {
      let extendedAdPodInfo = String(
        format: "Showing ad %zd/%zd, bumper: %@, title: %@, "
          + "description: %@, contentType:%@, pod index: %zd, "
          + "time offset: %lf, max duration: %lf.",
        ad.adPodInfo.adPosition,
        ad.adPodInfo.totalAds,
        ad.adPodInfo.isBumper ? "YES" : "NO",
        ad.adTitle,
        ad.adDescription,
        ad.contentType,
        ad.adPodInfo.podIndex,
        ad.adPodInfo.timeOffset,
        ad.adPodInfo.maxDuration)

      print("\(extendedAdPodInfo)")
    }
    break
  case IMAAdEventType.AD_BREAK_STARTED:
    print("Ad break started.")
    break
  case IMAAdEventType.AD_BREAK_ENDED:
    print("Ad break ended.")
    break
  case IMAAdEventType.AD_PERIOD_STARTED:
    print("Ad period started.")
    break
  case IMAAdEventType.AD_PERIOD_ENDED:
    print("Ad period ended.")
    break
  default:
    break
  }
}

func streamManager(_ streamManager: IMAStreamManager, didReceive error: IMAAdError) {
  print("StreamManager error with type: \(error.type)")
  print("code: \(error.code)")
  print("message: \(error.message ?? "Unknown Error")")
}

شغِّل تطبيقك، وإذا نجحت العملية، يمكنك طلب بثوق Google DAI وتشغيلها باستخدام حزمة تطوير البرامج لإعلانات الوسائط التفاعلية. لمزيد من المعلومات حول ميزات حزمة تطوير البرامج (SDK) المتقدّمة، يمكنك الاطّلاع على الأدلة الأخرى المدرَجة في الشريط الجانبي الأيمن أو الأمثلة على GitHub.