Integrate Smart Instream SDK

Step by step guide to integrate instream ads in your application.

  1. Overview
  2. Import the SDK
  3. Configure the SDK
  4. Create an Ad placement
  5. Create optional configurations
  6. Create an Ad Manager
  7. Setup your playhead monitoring
  8. Start your Ad Manager
  9. Responding to Ad Manager events
  10. Fullscreen management

Overview

Ad calls and ad breaks playback are performed by a SVSAdManager instance.

To initialize and start your SVSAdManager, you will need:

All these classes are available for both iOS and tvOS apps, only the header that needs to be imported is different. This is also true for any documented API you will find in the API documentation, unless explicitly stated otherwise.

You can always refer to the samples if you just want to copy/paste the whole integration.

Import the SDK

For iOS apps, you can import the SDK using:


		#import <SVSVideoKit/SVSVideoKit.h>
		

For tvOS apps, you can import the SDK using:


		#import <SVSVideoKitTV/SVSVideoKitTV.h>
		

If you share some code between iOS & tvOS apps, you can use both SDKs at the same time by using a preprocessor directive to import the right SDK at compile time:


#if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV)
    #import <SVSVideoKit/SVSVideoKit.h>
#elif TARGET_OS_TV
    #import <SVSVideoKitTV/SVSVideoKitTV.h>
#endif
		

Configure the SDK

The SDK needs to be configured with your own SiteID before making any ad calls. You will have to call the method configureWithSiteID: of SVSConfiguration shared instance to do so.

A good place to configure the SDK is your application's delegate, in the application:didFinishLaunchingWithOptions: method.


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
	// ...

	// Configure the SDK with your own SiteID.
    [[SVSConfiguration sharedInstance] configureWithSiteID:YOUR_SITE_ID];

    // ...
}

Note that you will not be able to start your SVSAdManager instance and display ads if the SDK is not configured first.

This configuration step will allow Smart to remotely customize your SDK behavior for example if you need help for debugging.

Create an Ad placement

To perform ad calls, the SVSAdManager will need to know about your ad placement.

Instantiate a SVSAdPlacement using your SiteID, PageID (or PageName) and your FormatID.

You can also set targeting informations per ad break type and/or a global one on the ad placement.
Note: if the targeting is not set for an ad break type, the global targeting will be used instead.


@interface ContentPlayerViewController ()
@property (nonatomic, strong) SVSAdPlacement *adPlacement;
@end

@implementation ContentPlayerViewController

// ...

- (void)viewDidLoad {
	// ...
	self.adPlacement = [self instantiateAdPlacement];
	// ...
}

- (SVSAdPlacement *)instantiateAdPlacement {
	// Create an SVSAdPlacement instance from your SiteID, PageID and FormatID
    SVSAdPlacement *adPlacement = [SVSAdPlacement adPlacementWithSiteId:YOUR_SITE_ID pageId:YOUR_PAGE_ID formatId:YOUR_FORMAT_ID];

    // Setup the custom targeting for your placement (optional)
    adPlacement.globalKeywordsTargeting = @"Default keyword targeting"; // Default targeting
    adPlacement.preRollKeywordsTargeting = @"Preroll keyword targeting"; // Preroll targeting
    adPlacement.midRollKeywordsTargeting = @"Midroll keyword targeting"; // Midroll targeting
    adPlacement.postRollKeywordsTargeting = @"Postroll keyword targeting"; // Postroll targeting

    return adPlacement;
}

// ...

@end

The newly created instance of SVSAdPlacement will be used for your SVSAdManager initialization.

Create optional configurations

For a better management of your ads and ad player you can set up optional configurations. This is not mandatory, and if you don't create these objects, default ones will be created by the SDK when instantiating the SVSAdManager.

You can create:


@interface ContentPlayerViewController ()
@property (nonatomic, strong) SVSAdPlacement *adPlacement;

@property (nonatomic, strong) SVSAdRules *adRules;
@property (nonatomic, strong) SVSAdPlayerConfiguration *adPlayerConfiguration;
@property (nonatomic, strong) SVSContentData *contentData;
@end

@implementation ContentPlayerViewController

// ...

- (void)viewDidLoad {
	// ...
	self.adPlacement = [self instantiateAdPlacement];

	self.adRules = [self instantiateAdRules];
	self.adPlayerConfiguration = [self instantiateAdPlayerConfiguration];
	self.contentData = [self instantiateContentData];
	// ...
}

- (SVSAdRules *)instantiateAdRules {
	// Instantiate 3 SVSAdRuleData for Preroll, Midroll and Postroll
	SVSAdRuleData *prerollData = [SVSAdRuleData prerollDataWithInstances:2];
    SVSAdRuleData *postrollData = [SVSAdRuleData postrollDataWithInstances:2];
    SVSAdRuleData *midrollData = [SVSAdRuleData midrollDataWithInstances:1 percents:@[@(50)]];

    // Instantiate a SVSAdRule with preroll, midroll and postroll SVSAdRuleData instances for a content of any duration.
    SVSAdRule *adRule = [SVSAdRule adRuleWithData:@[prerollData, midrollData, postrollData] durationMin:0 durationMax:-1];

    // Return an array of SVSAdRule
    return [SVSAdRules adRulesWithRules:@[adRule]];
}

- (SVSAdPlayerConfiguration *)instantiateAdPlayerConfiguration {
	// Create a new SVSAdPlayerConfiguration instance.
	SVSAdPlayerConfiguration *configuration = [[SVSAdPlayerConfiguration alloc] init];

	// Force skip delay at 5 seconds for every ad.
	configuration.publisherOptions.forceSkipDelay = YES;
	configuration.publisherOptions.skipDelay = 5.0;

	return configuration;
}

- (SVSContentData *)instantiateContentData {
	// Create new SVSContentData instance based on content data.
	return [[SVSContentData alloc] initWithContentID:@"yourContentID" contentTitle:@"yourContentTitle" videoContentType:@"yourContentType" videoContentCategory:@"yourContentCategory" videoContentDuration:@(30) videoSeasonNumber:@(1) videoEpisodeNumber:@(2) videoContentRating:@"myContentRatin" contentProviderID:@"contentProviderID" contentProviderName:@"contentProviderName" videoContentDistributorID:@"contentDistributorID" videoContentDistributorName:@"contentDistributorName" videoContentTags:@[@"tag1",@"tag2"] externalContentID:@"externalContentID" videoCMSID:@"videoCMSID"];
}

// ...

@end

You are now ready to create your SVSAdManager.

Create an Ad Manager

SVSAdManager is the main class of the SDK. This object is responsible for receiving every configurations, monitor your content and display ad breaks when defined by your advertising policy.

It will also sent events to its delegate. You should listen to these events by implementing the SVSAdManagerDelegate protocol as they will help you to manage your content player during ad breaks.


@interface ContentPlayerViewController ()  <SVSAdManagerDelegate>
@property (nonatomic, strong) SVSAdPlacement *adPlacement;

@property (nonatomic, strong) SVSAdRules *adRules;
@property (nonatomic, strong) SVSAdPlayerConfiguration *adPlayerConfiguration;
@property (nonatomic, strong) SVSContentData *contentData;

@property (nonatomic, strong) SVSAdManager *adManager;
@end

@implementation ContentPlayerViewController

// ...

- (void)viewDidLoad {
	// ...
	self.adPlacement = [self instantiateAdPlacement];

	self.adRules = [self instantiateAdRules];
	self.adPlayerConfiguration = [self instantiateAdPlayerConfiguration];
	self.contentData = [self instantiateContentData];

	self.adManager = [self instantiateAdManager];

	// You want to let the AdManager know if your content player is in fullscreen or not for a better display of ads
	[self.adManager contentPlayerIsFullscreen:[self isContentPlayerInFullscreen]];

	// ...
}

- (SVSAdManager *)instantiateAdManager {
	return [[SVSAdManager alloc] initWithDelegate:self placement:self.adPlacement rules:self.adRules configuration:self.adPlayerConfiguration contentData:self.contentData];
}

// Utility method depending on your content player status.
- (BOOL)isContentPlayerInFullscreen {
	return self.contentPlayerIsInFullscreenMode; // Optional boolean, your content player might have some APIs to let you know about this...
}

// ...

@end

Now that your SVSAdManager is created, you need to bind it to your content player so you can display ads along the content's playback.

Setup your playhead monitoring

To be able to trigger ad breaks at the right moment, the SVSAdManager needs to know about your content in real time: total duration, current time, volume, etc...

For this, the SVSAdManager will query informations from an object implementing the SVSContentPlayerPlayHead protocol, which is called a PlayHead Adapter.

A SVSAVPlayerPlayHeadAdapter class for AVPlayer is shipped with the SDK for your convenience.


In the following example we will assume that you use AVPlayer as your content player. If you use JWPlayer, BrightCove or Ooyala, please refer to the PlayHead Adapters documentation.
If you use another player, you will have to create your own playhead adapter, which is easy if your content player is based on AVPlayer !


@interface ContentPlayerViewController ()  <SVSAdManagerDelegate>
@property (nonatomic, strong) SVSAdPlacement *adPlacement;

@property (nonatomic, strong) SVSAdRules *adRules;
@property (nonatomic, strong) SVSAdPlayerConfiguration *adPlayerConfiguration;
@property (nonatomic, strong) SVSContentData *contentData;

@property (nonatomic, strong) SVSAdManager *adManager;

@property (nonatomic, strong) AVPlayer *contentPlayer;
@property (nonatomic, strong) SVSAVPlayerPlayHeadAdapter *contentPlayerPlayHeadAdapter;
@end

@implementation ContentPlayerViewController

// ...

- (void)viewDidLoad {
	// ...
	self.adPlacement = [self instantiateAdPlacement];

	self.adRules = [self instantiateAdRules];
	self.adPlayerConfiguration = [self instantiateAdPlayerConfiguration];
	self.contentData = [self instantiateContentData];

	self.adManager = [self instantiateAdManager];

	self.contentPlayerPlayHeadAdapter = [self instantiatePlayHeadAdapter];
	// ...
}

- (SVSAVPlayerPlayHeadAdapter *)instantiatePlayHeadAdapter {
	BOOL contentDurationIsUnknown = NO; // Use YES if your are streaming live content with an unknown duration. NO if your content duration is finite.
	return [[SVSAVPlayerPlayHeadAdapter alloc] initWithAVPlayer:self.contentPlayer unknownContentDuration:contentDurationIsUnknown];
}

// ...

@end

You are now ready to start your Ad Manager and display your first ads !

Start the Ad Manager

Once your content player is ready to play, you don't need to start it right away !

First you should start your SVSAdManager and wait for it to ask you to resume your content through your implementation of SVSAdManagerDelegate protocol.

To start, the SVSAdManager needs:

If you don't provide both these objects, the SVSAdManager won't be able to start.

Note: do not try to start your SVSAdManager before your content player is ready. If you do so, the playhead adapter will still not know about content duration and ad breaks scheduling will be impossible.


@implementation ContentPlayerViewController

// ...

- (void)contentPlayerIsReadyToPlayCallback {
	// This method is called when your content player is ready to play !
	// For example, if you are using AVPlayer, you should call it when AVPlayerItemStatus is equal to AVPlayerItemStatusReadyToPlay

	// Let's assume that this callback might be called several times...
	// and start the adManager only if it has not been started yet !
	if (![self.adManager isStarted]) {
		[self startAdManager]
	}
}

- (void)startAdManager {
	// Start the SVSAdManager instance by passing it the playheadAdapter and the content player container view.
	[self.adManager startWithPlayHead:self.playheadAdapter adContainerView:self.contentPlayer.containerView];
}

// ...

@end

After it's been started, the SVSAdManager will begin to forward events to its delegate. You might want to respond to these events to manage your content player.

Responding to Ad Manager events

You will periodically receive events from the SVSAdManager if you implemented the SVSAdManagerDelegate protocol.

We actually say IF, but you MUST implement this protocol or your content player will continue to play during ads, or worst it will never start at all.

At least, make sure you implement:

and everything should be fine !


@implementation ContentPlayerViewController

// ...

#pragma mark - SVSAdManagerDelegate General Methods

- (void)adManager:(SVSAdManager *)adManager didFailToStartWithError:(NSError *)error {
	// Called when the AdManager failed to start for some reason.
	// Most of the time it will be because your playheadAdapter is not ready...
	// See error description for more info.
}

- (void)adManager:(SVSAdManager *)adManager didFailToStartAdBreak:(SVSAdBreakType)adBreakType error:(NSError *)error {
	// Called when an AdBreak did fail to start.
}

- (void)adManager:(SVSAdManager *)adManager didStartAdBreak:(SVSAdBreakType)adBreakType {
	// Called when an AdBreak starts.
}

- (void)adManager:(SVSAdManager *)adManager didFinishAdBreak:(SVSAdBreakType)adBreakType numberOfAds:(NSInteger)numberOfAdsPlayed duration:(NSTimeInterval)duration error:(nullable NSError *)error {
	// Called when an AdBreak finishes.
}

#pragma mark - SVSAdManagerDelegate Playback Methods

- (void)adManagerDidRequestToPauseContentPlayer:(SVSAdManager *)adManager forAdBreak:(SVSAdBreakType)adBreakType {
	// Called when the AdManager wants you to pause your content player. You should obey !
	[self.contentPlayer pause];
}

- (void)adManagerDidRequestToResumeContentPlayer:(SVSAdManager *)adManager afterAdBreak:(SVSAdBreakType)adBreakType {
	// Called when the AdManager wants you to resume your content player. You should obey !
	[self.contentPlayer play];
}

- (void)adManager:(SVSAdManager *)adManager didProgressToTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
	// Called periodically to keep track of the ad manager's playback status.
}

#pragma mark - SVSAdManagerDelegate Fullscreen Methods

- (void)adManagerDidRequestToEnterFullscreen:(SVSAdManager *)adManager {
	// Called when the enter fullscreen button of an Ad is clicked by the user.
	// Adapt your UI to properly react to this user action: you should resize your container view so it fits the whole screen.
	[self transitionToFullscreen:YES];
}

- (void)adManagerDidRequestToExitFullscreen:(SVSAdManager *)adManager {
	// Called when the exit fullscreen button of an Ad is clicked by the user.
	// Adapt your UI to properly react to this user action: you should resize your container view so it goes back to its original size.
	[self transitionToFullscreen:NO];
}

#pragma mark - Modal Presentation

- (UIViewController *)adManagerDidRequestPostClickPresentationViewController:(SVSAdManager *)adManager {
	// Called when the ad has been clicked and needs to open a modal.
	return self;
}

// ...

@end

That's it, you are all set ! Enjoy your ads ;-)

Fullscreen management

To avoid breaking your app, SVSAdManager will never force your content player into fullscreen. It is your app that decides how the fullscreen will be handled for your content player and the ad player.

If you allow the fullscreen / exit fullscreen buttons on the Ad Player Interface, SVSAdManager will ask its delegate to enter fullscreen through the adManagerDidRequestToEnterFullscreen method of SVSAdManagerDelegate protocol.

You are responsible for responding to this event. The ad player view will always stick to the content player container view you passed when your started the SVSAdManager.
This means that if you allow your content player to enter/exit fullscreen you have to modify the container view frame || bounds || superview...

Once you modified the container view size or status, gently let the SVSAdManager know about it by setting the new state of the content player through the contentPlayerIsFullscreen: method of SVSAdManager


@implementation ContentPlayerViewController

// ...

#pragma mark - SVSAdManagerDelegate

- (void)adManagerDidRequestToEnterFullscreen:(SVSAdManager *)adManager {
    [self transitionToFullscreen:YES];
}

- (void)adManagerDidRequestToExitFullscreen:(SVSAdManager *)adManager {
    [self transitionToFullscreen:NO];
}

#pragma mark - My implementation of fullscreen depending on what I want my app to do

- (void)transitionToFullscreen:(BOOL)fullscreen {
	if (fullscreen) {
		[self askMyContentPlayerToEnterFullscreen];
	} else {
		[self askMyContentPlayerToExitFullscreen];
	}
}

- (void)myContentPlayerEnteredFullscreenCallback {
	[self.adManager setContentPlayerIsFullscreen:YES];
}

- (void)myContentPlayerExitedFullscreenCallback {
	[self.adManager setContentPlayerIsFullscreen:NO];
}

// ...

@end