کیتهای توسعه نرمافزار IMA ادغام تبلیغات چندرسانهای را در وبسایتها و برنامههای شما آسان میکنند. کیتهای توسعه نرمافزار IMA میتوانند از هر سرور تبلیغاتی سازگار با VAST درخواست تبلیغات کنند و پخش تبلیغات را در برنامههای شما مدیریت کنند. با کیتهای توسعه نرمافزار IMA DAI، برنامهها درخواست پخش جریانی برای تبلیغات و ویدیوی محتوا - چه VOD و چه محتوای زنده - ارسال میکنند. سپس SDK یک جریان ویدیویی ترکیبی را برمیگرداند، به طوری که شما مجبور نیستید جابجایی بین ویدیوی تبلیغ و محتوا را در برنامه خود مدیریت کنید.
راهکار DAI مورد نظرتان را انتخاب کنید
سرویس کامل DAI
این راهنما نحوه ادغام IMA DAI SDK را در یک برنامه پخش کننده ویدیوی ساده نشان میدهد. اگر مایل به مشاهده یا دنبال کردن یک نمونه ادغام تکمیل شده هستید، BasicExample را از GitHub دانلود کنید.
مرور کلی IMA DAI
پیادهسازی IMA DAI شامل سه جزء اصلی SDK است که در این راهنما نشان داده شده است:
-
IMAAdDisplayContainer: یک شیء کانتینر که روی عنصر پخش ویدیو قرار میگیرد و عناصر رابط کاربری تبلیغ را در خود جای میدهد. -
IMAAdsLoader: شیءای که جریانها را درخواست میکند و رویدادهایی را که توسط اشیاء پاسخ درخواست جریان ایجاد میشوند، مدیریت میکند. شما فقط باید یک بارگذار تبلیغات را نمونهسازی کنید که میتواند در طول عمر برنامه بارها مورد استفاده قرار گیرد. -
IMAStreamRequest– یا یکIMAVODStreamRequestیا یکIMALiveStreamRequest: شیءای که درخواست پخش جریانی را تعریف میکند. درخواستهای پخش جریانی میتوانند برای پخشهای ویدیویی درخواستی یا پخش زنده باشند. درخواستهای پخش زنده یک کلید دارایی را مشخص میکنند، در حالی که درخواستهای VOD یک شناسه CMS و شناسه ویدیو را مشخص میکنند. هر دو نوع درخواست میتوانند به صورت اختیاری شامل یک کلید API مورد نیاز برای دسترسی به پخشهای مشخص شده و یک کد شبکه Google Ad Manager برای IMA SDK باشند تا شناسههای تبلیغات را مطابق با تنظیمات Google Ad Manager مدیریت کند. -
IMAStreamManager: شیءای که جریانهای درج تبلیغات پویا و تعاملات با بکاند DAI را مدیریت میکند. مدیر جریان همچنین پینگهای ردیابی را مدیریت کرده و رویدادهای جریان و تبلیغات را به ناشر ارسال میکند.
پیشنیازها
قبل از شروع، به موارد زیر نیاز دارید:
- ایکسکد ۱۳ یا بالاتر
- Swift Package Manager ، CocoaPods یا یک نسخه دانلود شده از IMA DAI SDK برای tvOS
ایجاد یک پروژه جدید Xcode
در Xcode، یک پروژه tvOS جدید با استفاده از Objective-C ایجاد کنید. از BasicExample به عنوان نام پروژه استفاده کنید.
اضافه کردن IMA DAI SDK به پروژه Xcode
برای نصب IMA DAI SDK از یکی از این سه روش استفاده کنید.
نصب SDK با استفاده از Swift Package Manager
کیت توسعه نرمافزاری تبلیغات رسانهای تعاملی (Interactive Media Ads SDK) از نسخه ۴.۸.۲ به بعد از Swift Package Manager پشتیبانی میکند. برای وارد کردن بسته Swift، این مراحل را دنبال کنید.
در Xcode، با رفتن به مسیر File > Add Packages ، بستهی سویفت GoogleInteractiveMediaAds را نصب کنید.
در اعلانی که ظاهر میشود، مخزن گیتهاب GoogleInteractiveMediaAds Swift Package را جستجو کنید:
https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvosنسخهای از بستهی سویفت GoogleInteractiveMediaAds را که میخواهید استفاده کنید، انتخاب کنید. برای پروژههای جدید، توصیه میکنیم از نسخه اصلی Up to Next استفاده کنید.
وقتی کارتان تمام شد، Xcode وابستگیهای بسته شما را حل کرده و آنها را در پسزمینه دانلود میکند. برای جزئیات بیشتر در مورد نحوه اضافه کردن وابستگیهای بسته، به مقاله اپل مراجعه کنید.
نصب SDK با استفاده از CocoaPods
CocoaPods یک مدیر وابستگی برای پروژههای Xcode است و روش پیشنهادی برای نصب IMA DAI SDK میباشد. برای اطلاعات بیشتر در مورد نصب یا استفاده از CocoaPods، به مستندات CocoaPods مراجعه کنید. پس از نصب CocoaPods، از دستورالعملهای زیر برای نصب IMA DAI SDK استفاده کنید:
در همان دایرکتوری که فایل BasicExample.xcodeproj شما قرار دارد، یک فایل متنی به نام Podfile ایجاد کنید و پیکربندی زیر را به آن اضافه کنید:
source 'https://github.com/CocoaPods/Specs.git' platform :tvos, '15' target "BasicExample" do pod 'GoogleAds-IMA-tvOS-SDK', '~> 4.16.0' endاز دایرکتوری که شامل Podfile است، دستور زیر را اجرا کنید:
pod install --repo-updateبا باز کردن فایل BasicExample.xcworkspace و تأیید اینکه شامل دو پروژه است، تأیید کنید که نصب موفقیتآمیز بوده است: BasicExample و Pods (وابستگیهای نصب شده توسط CocoaPods).
دانلود و نصب دستی SDK
اگر نمیخواهید از Swift Package Manager یا CocoaPods استفاده کنید، میتوانید IMA DAI SDK را دانلود کرده و به صورت دستی آن را به پروژه خود اضافه کنید.
وارد کردن IMA SDK
اضافه کردن چارچوب IMA با استفاده از دستور import:
هدف-سی
#import "ViewController.h"
#import <AVKit/AVKit.h>
@import GoogleInteractiveMediaAds;
سویفت
import AVFoundation
import GoogleInteractiveMediaAds
import UIKit
یک پخش کننده ویدیو ایجاد کنید و IMA SDK را ادغام کنید
مثال زیر IMA SDK را مقداردهی اولیه میکند:
هدف-سی
// Live stream asset key, VOD content source and video IDs, and backup content URL.
static NSString *const kAssetKey = @"c-rArva4ShKVIAkNfy6HUQ";
static NSString *const kContentSourceID = @"2548831";
static NSString *const kVideoID = @"tears-of-steel";
static NSString *const kNetworkCode = @"21775744923";
static NSString *const kBackupStreamURLString =
@"http://googleimadev-vh.akamaihd.net/i/big_buck_bunny/bbb-,480p,720p,1080p,.mov.csmil/"
@"master.m3u8";
static const StreamType kDefaultStreamType = StreamTypeLive;
@interface ViewController () <IMAAdsLoaderDelegate,
IMAStreamManagerDelegate,
AVPlayerViewControllerDelegate>
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) IMAAdDisplayContainer *adDisplayContainer;
@property(nonatomic) UIView *adContainerView;
@property(nonatomic) id<IMAVideoDisplay> videoDisplay;
@property(nonatomic) IMAStreamManager *streamManager;
@property(nonatomic) AVPlayerViewController *playerViewController;
@property(nonatomic, getter=isAdBreakActive) BOOL adBreakActive;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
self.streamType = kDefaultStreamType;
[self setupAdsLoader];
[self setupPlayer];
[self setupAdContainer];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self requestStream];
}
- (void)setupPlayer {
// Create a stream video player.
AVPlayer *player = [[AVPlayer alloc] init];
self.playerViewController = [[AVPlayerViewController alloc] init];
self.playerViewController.player = player;
// Attach video player to view hierarchy.
[self addChildViewController:self.playerViewController];
[self.view addSubview:self.playerViewController.view];
self.playerViewController.view.frame = self.view.bounds;
[self.playerViewController didMoveToParentViewController:self];
}
سویفت
class ViewController:
UIViewController,
IMAAdsLoaderDelegate,
IMAStreamManagerDelegate,
AVPlayerViewControllerDelegate
{
// Live stream asset key, VOD content source and video IDs, Google Ad Manager network code, and
// backup content URL.
static let assetKey = "c-rArva4ShKVIAkNfy6HUQ"
static let contentSourceID = "2548831"
static let videoID = "tears-of-steel"
static let networkCode = "21775744923"
static let backupStreamURLString =
"http://googleimadev-vh.akamaihd.net/i/big_buck_bunny/bbb-,480p,720p,1080p,.mov.csmil/master.m3u8"
var adsLoader: IMAAdsLoader?
var videoDisplay: IMAAVPlayerVideoDisplay!
var adDisplayContainer: IMAAdDisplayContainer?
var adContainerView: UIView?
private var streamManager: IMAStreamManager?
private var contentPlayhead: IMAAVPlayerContentPlayhead?
private var playerViewController: AVPlayerViewController!
private var userSeekTime = 0.0
private var adBreakActive = false
private enum StreamType {
case live
/// Video on demand.
case vod
}
/// Set the stream type here.
private let currentStreamType: StreamType = .live
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black
setupAdsLoader()
setupPlayer()
setupAdContainer()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
requestStream()
}
func setupPlayer() {
let player = AVPlayer()
let playerViewController = AVPlayerViewController()
playerViewController.delegate = self
playerViewController.player = player
// Set up our content playhead and contentComplete callback.
contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: player)
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.contentDidFinishPlaying(_:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: player.currentItem)
self.addChild(playerViewController)
playerViewController.view.frame = self.view.bounds
self.view.insertSubview(playerViewController.view, at: 0)
playerViewController.didMove(toParent: self)
self.playerViewController = playerViewController
}
در viewDidLoad() ، تابع setupAdsLoader() تابع IMAAdsLoader را ایجاد میکند، setupPlayer() تابع AVPlayerViewController را ایجاد میکند و setupAdContainer() UIView (UIView) را برای نمایش تبلیغ آماده میکند. وقتی نما قابل مشاهده میشود، تابع viewDidAppear() تابع requestStream() را برای درخواست جریان DAI فراخوانی میکند.
برای تعریف پارامترهای درخواست پخش زنده، این مثال از ثابتهایی مانند asset key برای پخش زنده یا content source ID و video ID برای پخش VOD استفاده میکند. این مثال همچنین از اجزای زیر برای مدیریت IMA SDK استفاده میکند:
-
adsLoader: درخواستهای پخش جریانی به Google Ad Manager را مدیریت میکند. توصیه میکنیم از یک نمونه واحد برای چرخه عمر برنامه استفاده کنید. -
videoDisplay: یک پیادهسازیIMAVideoDisplayکه به IMA اجازه میدهد پخش ویدیو را کنترل کند و رویدادهای پخش را با استفاده از AVPlayer پیگیری کند. -
adDisplayContainer: نمای مورد استفاده برای رندر کردن عناصر رابط کاربری تبلیغات و مدیریت تمرکز رابط کاربری در طول نمایش تبلیغات را مدیریت میکند. -
streamManager: پخش جریان ترکیبی تبلیغ و محتوا را مدیریت میکند و رویدادهای چرخه حیات تبلیغ را با استفاده از نماینده خود ارسال میکند. -
playerViewController: پخشکنندهی tvOS که برای ارائهی استریم ویدیویی مدیریتشده توسط IMA SDK استفاده میشود. -
adBreakActive: یک پرچم بولی که نشان میدهد آیا یک تبلیغ در حال پخش است یا خیر، و برای جلوگیری از جستجوی بیش از حد تبلیغات و مدیریت تمرکز رابط کاربری استفاده میشود.
پیادهسازی IMAAdsLoader
در مرحله بعد، IMAAdsLoader نمونهسازی کنید و نمای کانتینر تبلیغات را به سلسله مراتب نماها متصل کنید.
هدف-سی
- (void)setupAdsLoader {
self.adsLoader = [[IMAAdsLoader alloc] init];
self.adsLoader.delegate = self;
}
- (void)setupAdContainer {
// Attach the ad container to the view hierarchy on top of the player.
self.adContainerView = [[UIView alloc] init];
[self.view addSubview:self.adContainerView];
self.adContainerView.frame = self.view.bounds;
// Keep hidden initially, until an ad break.
self.adContainerView.hidden = YES;
}
سویفت
func setupAdsLoader() {
let adsLoader = IMAAdsLoader(settings: nil)
adsLoader.delegate = self
self.adsLoader = adsLoader
}
func setupAdContainer() {
// Attach the ad container to the view hierarchy on top of the player.
let adContainerView = UIView()
self.view.addSubview(adContainerView)
adContainerView.frame = self.view.bounds
// Keep hidden initially, until an ad break.
adContainerView.isHidden = true
self.adContainerView = adContainerView
}
درخواست پخش جریانی بدهید
چند ثابت برای نگهداری اطلاعات جریان ایجاد کنید و سپس تابع درخواست جریان را برای ایجاد درخواست پیادهسازی کنید.
هدف-سی
- (void)requestStream {
self.videoDisplay =
[[IMAAVPlayerVideoDisplay alloc] initWithAVPlayer:self.playerViewController.player];
self.adDisplayContainer = [[IMAAdDisplayContainer alloc] initWithAdContainer:self.adContainerView
viewController:self];
// Use the streamType property to determine which request to create.
IMAStreamRequest *request;
switch (self.streamType) {
case StreamTypeLive: {
request = [[IMALiveStreamRequest alloc] initWithAssetKey:kAssetKey
networkCode:kNetworkCode
adDisplayContainer:self.adDisplayContainer
videoDisplay:self.videoDisplay
userContext:nil];
NSLog(@"IMA: Requesting Live Stream with Asset Key: %@.", kAssetKey);
break;
}
case StreamTypeVOD: {
request = [[IMAVODStreamRequest alloc] initWithContentSourceID:kContentSourceID
videoID:kVideoID
networkCode:kNetworkCode
adDisplayContainer:self.adDisplayContainer
videoDisplay:self.videoDisplay
userContext:nil];
NSLog(@"IMA: Requesting VOD Stream with Video ID: %@.", kVideoID);
break;
}
}
if (request) {
[self.adsLoader requestStreamWithRequest:request];
} else {
// Fallback or error handling if no request object was created
NSLog(@"IMA Error: Could not create stream request for unknown type.");
[self playBackupStream];
}
}
سویفت
func requestStream() {
guard let playerViewController = self.playerViewController else { return }
guard let adContainerView = self.adContainerView else { return }
guard let adsLoader = self.adsLoader else { return }
self.videoDisplay = IMAAVPlayerVideoDisplay(avPlayer: playerViewController.player!)
let adDisplayContainer = IMAAdDisplayContainer(
adContainer: adContainerView, viewController: self)
self.adDisplayContainer = adDisplayContainer
// Variable to hold the specific stream request object.
let request: IMAStreamRequest
switch self.currentStreamType {
case .live:
// Create a live stream request.
request = IMALiveStreamRequest(
assetKey: ViewController.assetKey,
networkCode: ViewController.networkCode,
adDisplayContainer: adDisplayContainer,
videoDisplay: self.videoDisplay,
pictureInPictureProxy: nil,
userContext: nil)
print("IMA: Requesting Live Stream with asset key \(ViewController.assetKey)")
case .vod:
// Create a VOD stream request.
request = IMAVODStreamRequest(
contentSourceID: ViewController.contentSourceID,
videoID: ViewController.videoID,
networkCode: ViewController.networkCode,
adDisplayContainer: adDisplayContainer,
videoDisplay: self.videoDisplay,
pictureInPictureProxy: nil,
userContext: nil)
print(
"IMA: Requesting VOD Stream with content source ID \(ViewController.contentSourceID) and "
+ "video ID \(ViewController.videoID)")
}
adsLoader.requestStream(with: request)
}
مدیریت رویدادهای جریان
IMAAdsLoader و IMAStreamManager رویدادهایی را اجرا میکنند که برای مدیریت مقداردهی اولیه، خطاها و تغییرات در وضعیت جریان استفاده میشوند. این رویدادها از طریق پروتکلهای IMAAdsLoaderDelegate و IMAStreamManagerDelegate اجرا میشوند. به رویداد بارگذاری تبلیغات گوش دهید و جریان را مقداردهی اولیه کنید. اگر یک تبلیغ بارگذاری نشد، به جای آن یک جریان پشتیبان پخش کنید.
هدف-سی
- (void)playBackupStream {
NSURL *backupStreamURL = [NSURL URLWithString:kBackupStreamURLString];
[self.videoDisplay loadStream:backupStreamURL withSubtitles:@[]];
[self.videoDisplay play];
[self startMediaSession];
}
- (void)startMediaSession {
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
}
#pragma mark - IMAAdsLoaderDelegate
- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
// Initialize and listen to stream manager's events.
self.streamManager = adsLoadedData.streamManager;
self.streamManager.delegate = self;
[self.streamManager initializeWithAdsRenderingSettings:nil];
NSLog(@"Stream created with: %@.", self.streamManager.streamId);
}
- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
// Fall back to playing the backup stream.
NSLog(@"Error loading ads: %@", adErrorData.adError.message);
[self playBackupStream];
}
سویفت
@objc func contentDidFinishPlaying(_ notification: Notification) {
guard let adsLoader = self.adsLoader else { return }
adsLoader.contentComplete()
}
func startMediaSession() {
try? AVAudioSession.sharedInstance().setActive(true, options: [])
try? AVAudioSession.sharedInstance().setCategory(.playback)
}
// MARK: - IMAAdsLoaderDelegate
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
let streamManager = adsLoadedData.streamManager!
streamManager.delegate = self
streamManager.initialize(with: nil)
self.streamManager = streamManager
}
func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
print("Error loading ads: \(adErrorData.adError.message)")
let streamUrl = URL(string: ViewController.backupStreamURLString)
self.videoDisplay.loadStream(streamUrl!, withSubtitles: [])
self.videoDisplay.play()
playerViewController.player?.play()
}
مدیریت رویدادهای ثبت وقایع و خطاها
چندین رویداد وجود دارد که میتوانند توسط نماینده مدیریت جریان مدیریت شوند، اما برای پیادهسازیهای اولیه، مهمترین کاربردها عبارتند از انجام ثبت وقایع، جلوگیری از اقدامات جستجو هنگام پخش تبلیغات و مدیریت خطاها.
هدف-سی
#pragma mark - IMAStreamManagerDelegate
- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdEvent:(IMAAdEvent *)event {
NSLog(@"StreamManager event (%@).", event.typeString);
switch (event.type) {
case kIMAAdEvent_STREAM_STARTED: {
[self startMediaSession];
break;
}
case kIMAAdEvent_STARTED: {
// Log extended data.
NSString *extendedAdPodInfo = [[NSString alloc]
initWithFormat:@"Showing ad %zd/%zd, bumper: %@, title: %@, description: %@, contentType:"
@"%@, pod index: %zd, time offset: %lf, max duration: %lf.",
event.ad.adPodInfo.adPosition, event.ad.adPodInfo.totalAds,
event.ad.adPodInfo.isBumper ? @"YES" : @"NO", event.ad.adTitle,
event.ad.adDescription, event.ad.contentType, event.ad.adPodInfo.podIndex,
event.ad.adPodInfo.timeOffset, event.ad.adPodInfo.maxDuration];
NSLog(@"%@", extendedAdPodInfo);
break;
}
case kIMAAdEvent_AD_BREAK_STARTED: {
self.adContainerView.hidden = NO;
// Trigger an update to send focus to the ad display container.
self.adBreakActive = YES;
[self setNeedsFocusUpdate];
break;
}
case kIMAAdEvent_AD_BREAK_ENDED: {
self.adContainerView.hidden = YES;
// Trigger an update to send focus to the content player.
self.adBreakActive = NO;
[self setNeedsFocusUpdate];
break;
}
case kIMAAdEvent_ICON_FALLBACK_IMAGE_CLOSED: {
// Resume playback after the user has closed the dialog.
[self.videoDisplay play];
break;
}
default:
break;
}
}
- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdError:(IMAAdError *)error {
// Fall back to playing the backup stream.
NSLog(@"StreamManager error: %@", error.message);
[self playBackupStream];
}
سویفت
// MARK: - IMAStreamManagerDelegate
func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
print("StreamManager event \(event.typeString).")
switch event.type {
case IMAAdEventType.STREAM_STARTED:
self.startMediaSession()
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:
if let adContainerView = self.adContainerView {
adContainerView.isHidden = false
}
// Trigger an update to send focus to the ad display container.
adBreakActive = true
setNeedsFocusUpdate()
break
case IMAAdEventType.AD_BREAK_ENDED:
if let adContainerView = self.adContainerView {
adContainerView.isHidden = true
}
// Trigger an update to send focus to the content player.
adBreakActive = false
setNeedsFocusUpdate()
break
case IMAAdEventType.ICON_FALLBACK_IMAGE_CLOSED:
// Resume playback after the user has closed the dialog.
self.videoDisplay.play()
break
default:
break
}
}
func streamManager(_ streamManager: IMAStreamManager, didReceive error: IMAAdError) {
print("StreamManager error: \(error.message ?? "Unknown Error")")
}
همین! شما اکنون با استفاده از SDK مربوط به IMA DAI، تبلیغات را درخواست و نمایش میدهید. برای کسب اطلاعات بیشتر در مورد ویژگیهای پیشرفتهتر SDK، به راهنماهای دیگر یا نمونههای موجود در GitHub مراجعه کنید.

