Objective-c Basic example
From Engineering Client Portal
Objective-C Code Example
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/NielsenAppApi.h>
@implementation NielsenInit
+ (NielsenAppApi *)createNielsenAppApiWithDelegate:(id<NielsenAppApiDelegate>)delegate
{
//Initialising the NielsenAppApi class by passing app information which returns the instance of NielsenAppApi.
NSDictionary *appInformation = @{ @"appid": @"PDA7D5EE6-B1B8-4123-9277-2A788BC65XXX",
@"appversion": @"1.0",
@"sfcode": @"dcr",
@"nol_devDebug": @"DEBUG" };
return [[NielsenAppApi alloc] initWithAppInfo:appInformation delegate:delegate];
}
@end
NielsenInit.h
#import <Foundation/Foundation.h>
@class NielsenAppApi;
@protocol NielsenAppApiDelegate;
@interface NielsenInit : NSObject
+ (NielsenAppApi *)createNielsenAppApiWithDelegate:(id<NielsenAppApiDelegate>)delegate;
@end
SDKMethods.m
#import <Foundation/Foundation.h>
#import "SDKMethods.h"
@implementation SDKMethods
NSDictionary *content;
-(void)setContentUrl
{
//Loading Content URL
self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8"];
}
-(void)setAdUrl
{
//Loading Ad URL
self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8"];
}
-(void)setDtvrUrl
{
//Loading DTVR URL
self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/VOD/NielsenScienceBehindWhatsNext/prog_index.m3u8"];
}
- (NSDictionary *)loadChannelInfo
{
//Loading Channel Info.
NSString *strUrl = self.url.absoluteString;
NSDictionary *channel = @{ @"channelName" : @"ChannelTitle",
@"mediaURL": strUrl };
return channel;
}
// http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8
- (NSDictionary *)loadContent
{
//Loading Content data
self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8"];
NSDictionary *content = @{ @"type":@"content",
@"assetid":@"C77664",
@"length":@"3600",
@"program":@"MyProgram",
@"segB":@"CustomSegmentValueB",
@"segC":@"segmentC",
@"title":@"S2,E3",
@"section":@"cloudApi_app",
@"airdate":@"20180301 10:00:00",
@"isfullepisode":@"y",
@"adloadtype":@"2",
@"channelName":@"My Channel 1",
@"pipMode":@"false" };
return content;
}
- (NSDictionary *)loadPreRollAd
{
//loading Ad data.
self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8"];
NSDictionary *ad = @{ @"type":@"preroll",
@"assetid":@"AD1",
@"title":@"ADPreTitle" };
return ad;
}
- (NSDictionary *)loadDtvr{
//Loading DTVR data
NSDictionary *dtvr = @{ @"adModel":@"1" };
return dtvr;
}
@end
SDKMethods.h
#import <Foundation/Foundation.h>
@interface SDKMethods : NSObject
@property(nonatomic, strong) NSURL *url;
- (void)setContentUrl;
- (void)setAdUrl;
- (void)setDtvrUrl;
- (NSDictionary *)loadChannelInfo;
- (NSDictionary *)loadContent;
- (NSDictionary *)loadPreRollAd;
- (NSDictionary *)loadDtvr;
@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/NielsenAppApi.h>
NSMutableDictionary *mutableData;
NSDictionary *data;
SDKMethods *sdkMethods;
AVPlayer *player;
AVPlayerViewController *playerController;
NielsenAppApi *nielsenApi;
int totalVideosPlayed;
id timeObserver;
static void *TimedMetadataObserverContext = &TimedMetadataObserverContext;
NSString *timedMetadataKey = @"currentItem.timedMetadata";
id array;
@interface ViewController()<AVPlayerViewControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Setting background image
UIImage *backgroundImage = [UIImage imageNamed:@"bg_image.jpg"];
UIImageView *backgroundImageView=[[UIImageView alloc]initWithFrame:self.view.frame];
backgroundImageView.image=backgroundImage;
[self.view insertSubview:backgroundImageView atIndex:0];
//Mark: In NielsenInit class we are initialising the NielsenEventTracker.
//Getting the instance of NielsenEventTracker
nielsenApi = [NielsenInit createNielsenAppApiWithDelegate:nil];
//Mark: In SDKMethods class we wrote methods which creates content,Ad objects
sdkMethods = [[SDKMethods alloc] init];
if(self.videoType == onlyContent){
//loading video content url
[sdkMethods setContentUrl];
}else if(self.videoType == dtvrVideo){
//loading video DTVR url
[sdkMethods setDtvrUrl];
}else{
//loading video Ad url
[sdkMethods setAdUrl];
}
[self setPlayer];
if(self.videoType != dtvrVideo){
//For DTVR video playHeadPosition is not required
//For DCR Content,Ad videos only this method will execute.
[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;
[player play];
if(totalVideosPlayed == 0){
//For first time sending Channel info to SDK using "play" method.
[nielsenApi play:([sdkMethods loadChannelInfo])];
}
if(self.videoType == dtvrVideo){
//loading DTVR metadata
data = [sdkMethods loadDtvr];
}else{
//loading video content metadata data
data = [sdkMethods loadContent];
}
//Sending metadata to SDK.
[nielsenApi loadMetadata:(data)];
if(self.videoType == contentWithOneAd){
//loading Ad data
data = [sdkMethods loadPreRollAd];
[nielsenApi loadMetadata:(data)];
}
//Adding observer to player to track play,pause and reverse
[player addObserver:self
forKeyPath:@"rate"
options:(NSKeyValueObservingOptionNew)
context:nil];
//Only for DTVR videos we are tracking iD3 Tags and sends to SDK after extracting.
if(self.videoType == dtvrVideo){
//Setting observer to track timedMetadata
[player addObserver:self
forKeyPath: timedMetadataKey
options: (NSKeyValueObservingOptionNew)
context: &TimedMetadataObserverContext];
}
[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;
//Sending data dictionary to SDK with updated playHead position.
[nielsenApi playheadPosition:(intSec)];
}];
}
- (void) setVideoFinishObserver {
//observer fires on completion of Ad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerController.player.currentItem];
}
//rate 0 = Video Pause or stopped
//rate 1 = Video played or resumed
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if(keyPath == timedMetadataKey){
if(context == &TimedMetadataObserverContext){
id newMetadataArray = [change objectForKey:NSKeyValueChangeNewKey];
if (newMetadataArray != [NSNull null])
{
array = newMetadataArray;
for (AVMetadataItem *metadataItem in array)
{
//Handling TimedMetadata
[self handleTimedMetadata: metadataItem];
}
}
}
}
if (object == player && [keyPath isEqualToString:@"rate"]) {
NSNumber * newValue = [change objectForKey:NSKeyValueChangeNewKey];
int intValue = newValue.intValue;
if(intValue == 0){
NSLog(@"playback paused");
//On Video pause calling the "stop" method of SDK.
[nielsenApi stop];
}else if(intValue == 1){
NSLog(@"Normal playback");
//On video Resume calling "loadMetada" method of SDK
[nielsenApi loadMetadata:(data)];
}
}
}
- (void)viewDidDisappear:(BOOL)animated
{
///On moving to other screen calling "stop" method of SDK.
[nielsenApi stop];
player.rate = 0;
[player pause];
[super viewDidDisappear:animated];
}
-(void)playerDidFinishPlaying:(NSNotification *) notification {
[player removeObserver:self forKeyPath:@"rate"];
//As 1 video completed playing, incrementing the variable value.
totalVideosPlayed += 1;
if(self.videoType == onlyContent || totalVideosPlayed == self.totalVideos){
//When content video completes or total videos finishes, call "end" method.
[nielsenApi end];
}else if(self.videoType == contentWithOneAd){
//On completion of "AD" call "stop" method.
[nielsenApi stop];
//After preRoll ad completes, load content video.
data = [sdkMethods loadContent];
}
//Checking if total videos played or not.
if(totalVideosPlayed != self.totalVideos){
[self setPlayer];
[self setPlayHeadPosition];
//Setting observer to know the completion of video
[self setVideoFinishObserver];
}
}
- (void)dealloc {
NSLog(@"Remove NotificationCenter dealloc");
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)handleTimedMetadata:(AVMetadataItem *)timedMetadata
{
// We expect the content to contain plists encoded as timed metadata
// AVPlayer turns these into NSDictionaries
id extraAttributeType = [timedMetadata extraAttributes];
NSString *extraString = nil;
if ([extraAttributeType isKindOfClass:[NSDictionary class]])
{
extraString = [extraAttributeType valueForKey:@"info"];
}
else if ([extraAttributeType isKindOfClass:[NSString class]])
{
extraString = extraAttributeType;
}
NSString *key = [NSString stringWithFormat:@"%@", [timedMetadata key]];
//If tag starts with "www.nielsen.com", then only sending to SDK
if ([key isEqualToString:@"PRIV"] && [extraString rangeOfString:@"www.nielsen.com"].length > 0)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[nielsenApi sendID3:extraString];
});
}
}
@end
ViewController.h
#import <UIKit/UIKit.h>
@class NielsenAppApi;
@protocol NielsenAppApiDelegate;
@interface ViewController : UIViewController
@property (nonatomic) int videoType;
@property (nonatomic) int totalVideos;
@end
OptOutVC.h
#import <UIKit/UIKit.h>
@class NielsenEventTracker;
@protocol NielsenEventTrackerDelegate;
@interface OptOutVC : UIViewController
@property (nonatomic, weak) NielsenEventTracker *nielsenEventTracker;
@end