Simplified SDK API-Objective-C

From Engineering Client Portal

Revision as of 19:24, 28 September 2021 by ColinBrown (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Engineering Portal breadcrumbArrow.png Digital breadcrumbArrow.png DCR & DTVR breadcrumbArrow.png Simplified SDK APIbreadcrumbArrow.png Simplified SDK API-Objective-C

iphonescreenshot.png

Objective-C Code Example

Select the below link to download the sample files
Download Project Files

NielsenInit.m

//  NielsenInit.m
//  VideoPlayerAppObjC
// This is sample code of a very basic implementation of the Nielsen 'Simplified API'
// This code is for educational purposes only


#import "NielsenInit.h"
#import <NielsenAppApi/NielsenEventTracker.h>

@implementation NielsenInit

+ (NielsenEventTracker *)createNielsenEventTrackerWithDelegate:(id<NielsenEventTrackerDelegate>)delegate
{
    //Initialising the NielsenEventTracker class by passing app information which returns the instance of NielsenEventTracker.
    
    NSDictionary *appInformation = @{ @"appid": @"PDA7D5EE6-B1B8-4123-9277-2A788BC6XXX",
                            @"appversion": @"1.0",
                            @"appname": @"Objc Test app",
                            @"sfcode": @"dcr",
                            @"ccode": @"123",
                            @"dma":@"456",
                            @"uoo":@"0",
                            @"nol_devDebug": @"INFO",
                            @"containerId": @"1" };
    
    return [[NielsenEventTracker alloc] initWithAppInfo:appInformation delegate:delegate];
}


@end

NielsenInit.h

#import <Foundation/Foundation.h>

@class NielsenEventTracker;
@protocol NielsenEventTrackerDelegate;

@interface NielsenInit : NSObject

+ (NielsenEventTracker *)createNielsenEventTrackerWithDelegate:(id<NielsenEventTrackerDelegate>)delegate;

@end

SDKMethods.m

#import <Foundation/Foundation.h>
#import "SDKMethods.h"


@implementation SDKMethods

//Loading content Data
- (NSDictionary *)loadContentData
{
    
    self.url = [NSURL URLWithString:@"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"];
    
    NSDictionary *content = @{  @"assetName":@"ChromeCast1",
                                @"assetid":@"C77664",
                                @"length":@"3600",
                                @"program":@"MyProgram",
                                @"segB":@"CustomSegmentValueB",
                                @"segC":@"segmentC",
                                @"title":@"S2,E3",
                                @"type":@"content",
                                @"section":@"cloudApi_app",
                                @"airdate":@"20180120 10:00:00",
                                @"isfullepisode":@"y",
                                @"adloadtype":@"2",
                                @"channelName":@"My Channel 1",
                                @"pipMode":@"false" };
    
    //Ad data,static data should be empty in content video dictionary
    NSDictionary *metadata = @{  @"content" : content,
                               @"ad" : @{},
                               @"static" :  @{} };
    
    NSDictionary *data = @{  @"metadata" : metadata,
                           @"event": @"playhead",
                           @"type": @"content",
                           @"playheadPosition": @"0" };
    
    
    
    return data;
}

//Loading Ad data
- (NSDictionary *)loadPreRollAd
{
    self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8"];
    
    //We should pass content dictionary also in Ad video.
    NSDictionary *content = @{  @"assetName":@"ChromeCast1",
                                @"assetid":@"C77664",
                                @"length":@"3600",
                                @"program":@"MyProgram",
                                @"segB":@"CustomSegmentValueB",
                                @"segC":@"segmentC",
                                @"title":@"S2,E3",
                                @"type":@"content",
                                @"section":@"cloudApi_app",
                                @"airdate":@"20180120 10:00:00",
                                @"isfullepisode":@"y",
                                @"adloadtype":@"2",
                                @"channelName":@"My Channel 1",
                                @"pipMode":@"false" };
    
    NSDictionary *ad = @{ @"assetid":@"AD12345",
                          @"title":@"ADTestTitle",
                          @"type":@"preroll",
                          @"length":@"20" };
    
    //static data should be empty in Ad video
    NSDictionary *metadata = @{  @"content" : content,
                                 @"ad" : ad,
                                 @"static" :  @{} };
    
    NSDictionary *data = @{  @"metadata" : metadata,
                             @"event": @"playhead",
                             @"type": @"ad",
                             @"playheadPosition": @"0" };
    
    return data;
}

@end

SDKMethods.h

#import <Foundation/Foundation.h>

@interface SDKMethods : NSObject

@property(nonatomic, strong) NSURL *url;

- (NSDictionary *)loadContentData;
- (NSDictionary *)loadPreRollAd;

@end

ViewController.m

#import "ViewController.h"
#import "NielsenInit.h"
#import "SDKMethods.h"
#import <MediaPlayer/MediaPlayer.h>
#import <AVKit/AVKit.h>
#import "Constants.h"

#import <NielsenAppApi/NielsenEventTracker.h>

NSMutableDictionary *mutableData;
NSDictionary *data;
SDKMethods *sdkMethods;
AVPlayer  *player;
AVPlayerViewController *playerController;
NielsenEventTracker *nielsenEventTracker;

int totalVideosPlayed = 0;
id timeObserver;

@interface ViewController()<AVPlayerViewControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //Mark: In NielsenInit class we are initialising the NielsenEventTracker.
    
    //Getting the instance of NielsenEventTracker
    nielsenEventTracker = [NielsenInit createNielsenEventTrackerWithDelegate:nil];
    
    //Mark: In SDKMethods class we wrote methods which creates content,Ad objects
    sdkMethods = [[SDKMethods alloc] init];
    
    if(self.videoType == onlyContent){
        //loading video content data
       data = [sdkMethods loadContentData];
    }else{
        //loading Ad data
        data = [sdkMethods loadPreRollAd];
    }
    
    //Converting "data" to mutable dictionary as we have to update playhead, event values.
    mutableData =[data mutableCopy];
    
    [self setPlayer];
    [self setPlayHeadPosition];
    
    //Setting observer to know the completion of video
    [self setVideoFinishObserver];
}

-(void) setPlayer {
    
    //creating player
    player = [AVPlayer playerWithURL:[sdkMethods url]];
    playerController = [[AVPlayerViewController alloc] init];
    playerController.view.frame = CGRectMake(0,100,self.view.frame.size.width,300);
    playerController.player = player;
    playerController.showsPlaybackControls = YES;
    playerController.delegate = self;
    
    //Adding observer to player to track play,pause and reverse
    [player addObserver:self
              forKeyPath:@"rate"
                 options:(NSKeyValueObservingOptionNew)
                 context:nil];
    
    [player play];
    
    [self addChildViewController:playerController];
    [self.view addSubview:playerController.view];
}

-(void) setPlayHeadPosition {
    
    //Setting play head position
    CMTime timeInterval = CMTimeMakeWithSeconds(1, 1);
    [player addPeriodicTimeObserverForInterval:(timeInterval) queue:dispatch_get_main_queue() usingBlock:^(CMTime time){
        NSTimeInterval seconds = CMTimeGetSeconds(time);
        NSInteger intSec = seconds;
        NSString* strSec = [NSString stringWithFormat:@"%li", intSec];
        
        //updating playHead position in dictionary.
        [mutableData setValue:strSec forKey:@"playheadPosition"];
        
        //Sending data dictionary to SDK with updated playHead position.
        [nielsenEventTracker trackEvent:mutableData];
    }];
}

- (void) setVideoFinishObserver {
    
    //observer fires on completion of Ad
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerController.player.currentItem];
}

//rate 0.0 = Video Pause or stopped
//rate 1.0 = Video played or resumed
//rate -1.0 = Play reversed/rewind.
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (object == player && [keyPath isEqualToString:@"rate"]) {
        NSNumber * newValue = [change objectForKey:NSKeyValueChangeNewKey];
        int intValue = newValue.intValue;
        if(intValue == 0){
            NSLog(@"playback paused");
            
            //on video pause, updating event as pause in dictionary
            [mutableData setValue:@"pause" forKey:@"event"];
            
            //sending the dictionary to SDK with "pause" event.
            [nielsenEventTracker trackEvent:mutableData];
            
        }else if(intValue == 1){
            NSLog(@"Normal playback");
            
            //On Play resume setting event as Playhead
            [mutableData setValue:@"playhead" forKey:@"event"];
            
        }
    }
}

- (void)viewDidDisappear:(BOOL)animated
{
    //on moving to other screen, updating event as pause in dictionary
    [mutableData setValue:@"pause" forKey:@"event"];
    
    //As it is a pause event setting the playheadPosition to empty.
    [mutableData setValue:@"" forKey:@"playheadPosition"];
    
    player.rate = 0;
    [player pause];
    
    [super viewDidDisappear:animated];
}


-(void)itemDidFinishPlaying:(NSNotification *) notification {
    
    [player removeObserver:self forKeyPath:@"rate"];
    
    [self sendCompleteEventToSDK];
    
    //As 1 video completed playing, incrementing the variable value.
    totalVideosPlayed += 1;
    
    //Checking if total videos played or not.
    if(totalVideosPlayed != self.totalVideos){
        
        //Checking if videoType is contentWithAd, then after completion of Ad, will play the content video.
        if(self.videoType == contentWithAd){
            
            //loading video content data
            data = [sdkMethods loadContentData];
            
            mutableData =[data mutableCopy];
            
            [self setPlayer];
            
            //Adding observer to player to check is buffering finished
            CMTime timeInterval = CMTimeMakeWithSeconds(1, 3);
            timeObserver =  [player addPeriodicTimeObserverForInterval:(timeInterval) queue:dispatch_get_main_queue() usingBlock:^(CMTime time){
                
                //checking the video player status
                [self handlePlayerStatus:time];
                [self setPlayHeadPosition];
                //Setting observer to know the completion of video
                [self setVideoFinishObserver];
                
            }];
            
        }
    }
}

- (void) handlePlayerStatus : (CMTime) time {
    
    if(player.status == AVPlayerItemStatusReadyToPlay){
        
        // buffering is finished, setting event as Playhead
        [mutableData setValue:@"playhead" forKey:@"event"];
        [player removeTimeObserver:timeObserver];
    }
}

- (void) sendCompleteEventToSDK {
    
    //onCompletion of video, updating event as complete in dictionary
    [mutableData setValue:@"complete" forKey:@"event"];
    
    //As it is a complete event setting the playheadPosition to empty.
    [mutableData setValue:@"" forKey:@"playheadPosition"];
    
    //sending the dictionary to SDK with "complete" event.
    [nielsenEventTracker trackEvent:mutableData];
}

- (void)dealloc {
    NSLog(@"Remove NotificationCenter dealloc");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end

ViewController.h

#import <UIKit/UIKit.h>

@class NielsenEventTracker;
@protocol NielsenEventTrackerDelegate;


@interface ViewController : UIViewController

@property (nonatomic) int videoType;
@property (nonatomic) int totalVideos;

@end

OptOutVC.m

#import "OptOutVC.h"
#import "NielsenInit.h"


#import <NielsenAppApi/NielsenEventTracker.h>

@interface OptOutVC ()

@property (weak, nonatomic) IBOutlet UIWebView *webView;

@end

@implementation OptOutVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.nielsenEventTracker = [NielsenInit createNielsenEventTrackerWithDelegate:nil];
    
    //Getting the optPut URL from eventTracker
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.nielsenEventTracker.optOutURL]]];
}

@end

OptOutVC.h

#import <UIKit/UIKit.h>

@class NielsenEventTracker;
@protocol NielsenEventTrackerDelegate;

@interface OptOutVC : UIViewController

@property (nonatomic, weak) NielsenEventTracker *nielsenEventTracker;

@end