tvOS Framework Integration Guide Server-Side Ad Insertion (SSAI)
Framework Version: 1.5.0
Last Updated: 2023/8/15
Supports: tvOS 10.0+ for Apple TV Gen 4+
Engineer and co-author: Jason McGowan | Elias Kahwaji |
This document explains how to integrate the BrightLine tvOS SDK within a native (Objective-C/Swift) application that supports Server Side Ad Insertion (SSAI)
Download the tvOS 1.5.0 packages below for your development harness:
Table of Contents:
- Overview
- Step 1: SDK setup
- 1.1 Linking required libraries in Xcode
- 1.2 Implementing BLCoreEventsDelegate to receive callbacks
- - Objective-C
- - Swift
- 1.3 Compiling your application
- 1.4 App Transport Security (ATS)
- Step 2: Initializing the BrightLine Framework
- - Example configuration URL
- - Analytics root URL
- - Objective-C
- - Swift
- Step 3: Displaying BrightLine ads
- 3.1 VAST trackingEvents ownership
- - Construct JSON ad definition ad data object
- - Ad definition attributes
- 3.2 Call the ShowAd method
- - Objective-C
- - Swift
- Step 4: Removing BrightLine ads
- - Objective-C
- - Swift
- Step 5: Business logic for BrightLine ads
- - TVML/TVJS application
- - Objective-C (native) application
- Release notes
- v1.5.0
- v1.3.7
- v1.3.6
- v1.3.5
- v1.3.4
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.9
- v1.2.8
- v1.2.7
- v1.2.6
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- BrightLine SDK life cycle flow chart
- Server side ad insertion UML
- Server side ad insertion flow chart
Overview
The BrightLine tvOS SDK is an Objective-C framework that can be integrated within an Objective-C or Swift application. Apple TV BrightLine ad experiences are rendered using the UIKit framework.
Important:
Apple TV Gen 4+ prohibits the use of UIWebView. The BrightLine tvOS SDK does not support Apple TV Gen 3 and older.
Step 1: SDK setup
1.1 Linking required libraries in Xcode
From the application's target window, link the frameworks in Xcode in the "Frameworks, Libraries, And Embedded Content" section in the "General" tab.
1.2 Implement BLCoreEventDelegate to receive callbacks
The BLCoreEvents relate to the SDK and BrightLine ad life cycle.
Objective-C
@interface ViewController ()>BLCoreEventDelegate<
@end
@implementation ViewController
@end
// ##### REQUIRED FOR DISPLAYING THE AD #####
-(void)BLInitialize:(NSString*)libVersion{
// An SDK event called when framework receives publisher configuration response successfully and returns the current SDK version
}
-(void)BLInitializeFailed:(NSString*)libVersion: (NSError*)error{
// An SDK event called when framework failed to get publisher configuration response
}
// ##### OPTIONAL EVENTS #####
-(void)BLMicrositeWillOpen{
// An SDK event called when the microsite will appear but has not yet appeared
}
-(void)BLOverlayDidClose{
// An Ad event called when the overlay is closed
}
-(void)BLOverlayDidOpen{
// An event called when the overlay opens
}
-(void)BLMicrositeDidClose{
//An Ad event called when microsite closes
}
-(void)BLMicrositeDidOpen{
// An Ad event called when microsite opens
// Example: if app is entering foreground and microsite was open on enter background, don’t resume the commercial spot
}
-(void)BLManifestRequested{
// An SDK event called when publisher configuration is requested
}
-(void)BLManifestLoaded{
// An SDK event called when publisher configuration is loaded
}
-(void)BLManifestUnavailable{
//An SDK event called when publisher configuration is unavailable
}
-(void)BLAdRequested{
// An Ad event called when Ad is requested from Ad server
}
-(void)BLAdUnavailable{
// An Ad event called when Ad is unavailable
}
-(void)BLAdLoaded{
// An Ad event called when Ad is loaded and the hosting application should trigger video playback if owning video controller
}
-(void)BLAdDestroyed{
// An event called when Ad is completely removed from memory and is no longer displayed. Invoked by calling hideAd method externally or internally in the SDK
}
-(void)BLPreferredFocusView:(UIView*)focusView{
// An event called during the spot ad to request focus to the overlay. The hosting application should implement the UIViewController preferredFocusedView or preferredFocusEnviornments. This is required if the hosting applications owns the video player
}
Swift
@UIApplicationMain
Class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate, BLCoreEventDelegate {
var window: UIWindow?
var appController: TVApplicationController?
}
// ##### REQUIRED FOR DISPLAYING THE AD #####
func blInitialize(_libVersion: String!) {
//event called when framework receives publisher configuration response successfully and returns the current SDK version
}
func blInitializeFailed(_libVersion: String!, _error: Error!) {
//event called when framework failed to get publisher configuration response
}
// ##### OPTIONAL EVENTS #####
func blMicrositeWillOpen() {
//event called when the microsite will appear but has not yet appeared
}
func blOverlayDidOpen() {
//event called when the overlay opens
}
func blOverlayDidClose() {
//event called when the overlay is closed
}
func blMicrositeDidOpen() {
//event called when microsite opens
//example: if app is entering foreground and microsite was open on enter background, don’t resume the commercial spot
}
func blMicrositeDidClose() {
//event called when microsite closes
}
func blManifestRequested(){
//event called when publisher configuration is requested
}
func blManifestLoaded(){
//event called when publisher configuration is loaded
}
func blManifestUnavailable(){
//event called when publisher configuration is unavailable
}
func blAdRequested(){
//event called when Ad is requested
}
func blAdUnavailable (){
//event called when Ad is unavailable
}
func blAdLoaded (){
//event called when Ad is loaded and showAd can be called
}
func blAdDestroyed (){
//event called when Ad is completely removed from memory and is no longer displayed
}
func blPreferredFocus(_ focusView: UIView!){
// An event called during the spot ad to request focus to the overlay. The hosting application should implement the UIViewController preferredFocusedView or preferredFocusEnviornments. This is required if the hosting applications owns the video player
}
1.5 Compiling your application
Compile your application to ensure no errors occurred. If successful, the SDK is correctly integrated and ready for usage.
1.6 App Transport Security (ATS)
Important:
Apple requires applications to use HTTPS schemes for all data exchange between applications and servers. ATS must NOT be disabled in the hosting application and must NOT allow HTTP schemes. If an HTTP scheme is executed, the request will be blocked.
Step 2: Initializing the BrightLine framework
The BrightLine SDK framework is initialized with the configuration and analytics URL provided by BrightLine during the onboarding process. If you haven't received your configuration URL yet, use the example configuration URL below.
Important:
You must initialize the BrightLine SDK on application load within the didFinishLaunchingWithOptions method. Initializing the BrightLine SDK on application load will give visibility into our network, ability to retrieve audience targeting data, and send analytic data to our servers.
Example configuration URL
https://services.brightline.tv/api/v3/config/1018
Important:
You'll need a production ID from us before pushing your app to production.
The configuration URL is needed to retrieve publisher configuration data, event tracking data, etc. You can use the above URL (1018) to develop and test, but we'll provide you with your own production ID during the onboarding process.
Analytics root URL
https://events.brightline.tv/track
FYI only.
You won't be modifying this URL, but you'll see POSTS from this domain for app and app analytics. This analytics URL provides the mechanism to send the tracking events to the BrightLine servers.
Objective-C
[[BLCore sharedManager]initFramework: @"put the configuration URL here" withAnalytics: @"put the analytics URL here", withDelegate:self];
Swift
BLCore.sharedManager().initFramework("put the configuration URL here", withAnalytics: "put the analytics URL here", withDelegate: self)
Important:
If an error occurs when initializing the framework, the BLInitializedFailed event callback method is invoked. Otherwise, the BLInitialize method is invoked indicating a successful initialization.
The initFramework should only be called multiple times if the BLInitializeFailed was invoked. After BLInitialize is invoked, the hosting application can call the showAd method multiple times for displaying the BrightLine Ad experiences.
Step 3: Displaying BrightLine ads
BrightLine ads are displayed by calling the showAd method.
3.1 VAST trackingEvents ownership
The hosting application will be responsible for displaying the promotional ad, sending playback tracking events (start, firstQuartile, midPoint, thirdQuartile and complete).
The BrightLine SDK is responsible for sending companion ad tracking events (impression, acceptInvitation).
When integrating with a SSAI vendor (mDialog/Google DAI, Uplynk, FreeWheel, etc.), the hosting application will trigger the BrightLine SDK in the appropriate ad break event callback method with a data object that contains the CompanionAds node from the BrightLine VAST tag. Below are the typical steps
when integrating.
- Identify the appropriate ad break event callback method from the SSAI vendor during promotional ad playback
- Once the ad break even callback is invoked, use the data object from the callback method to get access to the VAST CompanionAds node data.
- Use the data object property that relates to the companion ad information and inspect the apiFramework attribute for value brightline.
From the vendor ad break callback, construct a JSON schema (ad definition) indicated below from the vendor ad data object.
Construct JSON ad definition from SSAI vendor ad data object
{
"apiFramework": "brightline",
"companion": {
"url": "",
"trackingEvents": {
"impression": [],
"acceptInvitation": []
}
}
}
Ad definiton attributes
- apiFramework - this attribute should be populated from the vendor ad data object.
- companion.url - this attribute should be populated with the URLs from the StaticResource element.
- companion.trackingEvents.impression - this attribute should be populated with all the URLs for when the overlay is displayed.
- companion.trackingEvents.acceptInvitation - this attribute should be populated with all the URLs for when the overlay is clicked.
3.2 Call the showAd method
Objective-C
// the variable "adResponse" is the constructed ad definition object from the SSAI vendor ad data object
NSString * adResponse;
[[BLCore sharedManager]showAd:@"pass in the view (UIView) that will display the ad" withDefinition:adResponse];
Swift
(BLCore.sharedManager() as AnyObject).showAd("pass in the view (UIView) that will display the ad", withDefinition:adResponse)
Step 4: Removing BrightLine ads
The hideAd method should be called when the promotional ad ends. The hideAd method will remove the ad from memory and display. As a result, the BLAdDestroyed event callback is invoked.
Important:
It's important to call the hideAd method so that our SDK prepares itself for the next ad call. Keep a look out for users that back out of our enhanced commercial spot mid-play and restarts the content. This behavior would cause usually cause a new content and ad request. Although this is an edge case, we advise you to listen and maintain a state of awareness for whether the hideAd method was called after your initial showAd method call.
You can achieve this state of awareness with our callback (see 1.4). When our overlays render after calling the showAd method, you'll get the BLOverlayDidOpen callback. This means at some point, you'll need to plan for edge cases by calling the hideAd method if the user exists out of the experience and restarts the content. If you miss this, our SDK will stay in a state of waiting for the hideAd method to be called and will not render the next ad when you call the showAd method.
In short, unless you're in a fresh session, you shouldn't call the showAd method unless the hideAd method has been called.
Note: It may be necessary to fire hideAd() slightly before the end of the ad duration to ensure the overlay is destroyed before the next ad begins. This will very depending on your stream and app architecture, and should be evaluated in initial testing
Objective-C
[[BLCore sharedManager]hideAd];
Swift
(BLCore.sharedManager() as AnyObject).hideAd();
Step 5: Business logic for promotional ad
Important:
During promotional ad playback, the user should not be able to pause/resume video playback via Siri Remote. In this case, the hosting application should disable this behavior. Below is sample code to serve as guidance for disabling the pause/resume behavior.
TVML/TVJS application
Add this event listener to the player object to prevent the actions from occurring if the microsite is not open. See the TVML sample application for the full source code.
player.addEventListener("shouldHandleStateChange", function(event) {
//console.log('shouldHandleStateChange='+event.state);
if (event.state == "scanning" || (event.state == "paused" && !isMicrositeOpen)) return false;
return true;
});
Objective-C (native) application
Note:
If the standard AVPlayerViewController is used, set the showsPlaybackControls property to false.
Release notes
v1.5.0
- Added support for new product in the BrightLine SDK - CTFS2.0
- Added support for new product in the BrightLine SDK - Bumper End Card
- Added support for new product in the BrightLine SDK - Dynamic Carousel
- Fixed a bug related with the infinite scroll
- Support for enableInfiniteScroll attribute for all carousels
- Added extra information on analytics - page_id
- Fixed tvOS not Respecting X and Y of breadcrumbs in conversion templates
v1.3.7
- General bug fixes and enhancements
v1.3.6
- Adjusted some template definitions to be more platform agnostic
v1.3.5
- Added a guard for invalid url parsing in the SDK
v1.3.4
- Fixed a bug where click to contact products would cause crashes on some versions of Apple TV Devices.
v1.3.3
- Added more guards for invalid objects being passed to the SDK.
v1.3.2
- Added support for new products in the BrightLine SDK.
v1.3.1
- Bug fixes and stability improvement.
v1.3.0
- Fixed a bug with microsites where BLViewController would not remove itself from superview.
v1.2.9
- Fixed an issue where storelocator scroll was still not showing the indexes properly (storelocator can only function using fastscroll only which needs to be enabled from the JSON).
v1.2.8
- Fixed a bug where store locator would keep scrolling multiple indexes but blPageControl would change only 1 index which causes wrong visual interpretation.
v1.2.7
- Stopped AVPlayerViewControllerContainerView from taking over focus when AV Player view is passed to the SDK (Works only in case of eOverlays and passing AV Player view to the SDK is never recommended)
v1.2.6
- Stopped AVPlayerViewControllerContainerView from taking over focus when AV Player view is passed to the SDK (Works only in case of eOverlays and passing AV Player view to the SDK is never recommended)
v1.2.5
- Added blMicrositeDidCloseFromMenuPress() and blOverlayDidCloseFromMenuPress() callbacks that will trigger when menu button is pressed when enabled in the JSON
v1.2.4
- Added manual gesture checker to override tvOS scrolling and enable slow scrolling
v1.2.3
- Added additional checks to XIB parsing to stop crashes when wrong JSON is passed to SDK
v1.2.2
- Added additional checks to XIB parsing to stop crashes when wrong JSON is passed to SDK
v1.2.1
- showAd method now takes a View instead of a ViewController as parameter
- Added checks around receiving an empty Nib name that prevent crashes
- Added blMicrositeWillOpen() callback that gets triggered before the microsite renders (optional, blOverlayDidClose has similar functionality)
v1.0.8
- Fixed SDK issue of not releasing client view controller when the hideAd method is called
v1.0.7
- Added VOD support for extended look blueprint
- No limit on array of images allowed in scrolling overlays
- Fixed bug that did not autoplay video on video and info video galleries when video was in full-screen mode when coming into foreground
v1.0.6
- Removed Reachability.h/.m library from Nexage VAST open source library and use AFNetworking reachability API for network monitoring
- Added x-mpegURL type to CSAI VAST parser
v1.0.5
- Fixed issue with duration value for analytic events being populated as a floating point value instead of an integer
- Added BLOverlayDidClose callback before ad enters the destroyed state when showing overlay only ads (no click to full-screen/microsite)
- Added %DISPLAY_TITLE% macro populated from component node "title" property in the companion banner ad JSON
- Fixed issue with device_model being populated incorrectly
- When retrieving the companion ad JSON, the NSTimer object is set to nil after the call to invalidate
- Fixed platform name being returned as user device name
- Fixed navigation analytics left/right for interactive overlay
- Changed deviceUUID security keychain key from DEVICE_UUID to BL_DEVICE_UUID
- Added support store locator (location API) overlays - request headers determine location server side without using device location
- Updated BLTVOSBundle layout package on CDN for configuration service to support store locator (location API) overlays
v1.0.4
- Added exception handling in case of an empty companion response
- Added extraction of session_id in companion url if it exists from the VAST response and uses session_id in all events to tie all video and interactive analytics
- Added exception handling in case the BrightLine configuration service returns an empty response
- Updated BrightLine configuration service post request JSON
- Fixed application crash when navigating in carousel when video autoplays with more than 5 items.
- Removed subclass of AVPlayerViewController
- Fixed bug with timestamp only being generated once per ad session. Timestamp is now generated for every event
- Fixed issue with overlay asset not stretching to full-screen. Instead of use setImage on ImageView setBackground AspectFit was used
- Fixed callback method of BLOverlayDidClose to host application only if ad is in a non-destroyed state
- Fixed callback method of BLAdUnAvailable to host application
- Configuration service post now includes appSessionID and trackFlag
- Resolved intermittent timeouts when retreiving the companion ad JSON
v1.0.3
- Fixed race condition between hideAd call and showing full-screen/microsite if user clicks overlay about one second before the commercial spot video ends
- Fixed bug of extracting micrositeName and features from the companion ad JSON
- Fixed issue with overlay not disappearing after commercial spot video ends on subsequent ad loads
- Fixed issue with product selection being applied to interactive overlay on subsequent ad loads
- Fixed issue with destroying ad or removing ad from view
- Added preferredFocusView/preferredFocusEnvironment for different tvOS versions support
v1.0.2
- Vertical and horizontal scrolling support. This can be for interactive overlay or the carousel within the full-screen/microsite
- Added support for interactive overlay with scrolling
- Added support for interactive overlay with deep linking to specific features and specific items in carousel based on ordinality position
- Added support for interactive overlay with select to new overlay functionality (basic polling)
- Added interactive overlay analytics
v1.0.1
- Added loading indicator when first time loading full-screen/microsite
- Increased carousel illusion scale factor to 100 of UICollelctionViewCells wrapping (takes the actual number of items in the json and multiples it by 100) and uses mod operator for indexing
- Resolved VAST parser wrapping functionality for analytics during commercial playback (CSAI)
- Fixed ad impression id remainaining the same for subsequent ad loads
- Added delay (0.5 secs) play in BLPlayerViewController to resolve issue with video stopping but audio continuing to play for OS version 10.0.0
- Assets that are baked into images no longer require transparent PNGs
- Minor updates to the Bright:ine configuration service post request/response for JSON attribute names
v1.0.0
- VAST wrapping does not work. Only the last VAST is processed (known bug for CSAI)
- Added a loading indicator for a first time load of assets.
- When loading more than 5 items in the carousel the user can see the load happening. The loading behavior is due to giving the illusion of the carousel wrapping when scrolling. This is also due to reporting more items in the collection data delegate source
- When assets are baked into the background such as header or arrows, a transparent image has to be specified in the companion ad JSON otherwise the SDK will throw null exceptions (fixed in 1.0.1)
BrightLine SDK life cycle flow chart
Server-side ad insertion UML
Server-side ad insertion flow chart