Swift Basic Sample

From Engineering Client Portal

Engineering Portal / Digital / DCR & DTVR / DCR Video iOS SDK / Swift Basic Sample

iPhone 11 Screenshot.jpg

Swift Version 5 Code Example

NielsenInit.swift

// This is sample code of a very basic implementation of the Nielsen API
// This code is for educational purposes only
//
import Foundation
import NielsenAppApi

class NielsenInit : NSObject {
    class func createNielsenApi(delegate: NielsenAppApiDelegate) -> NielsenAppApi?{
        
        let appInformation:[String: String] = [
            
            "appid": "PDA7D5EE6-B1B8-4123-9277-2A788BXXXXXX",
            "appversion": "1.0",
            "sfcode": "dcr",
            "nol_devDebug": "DEBUG"
        ]
        
        return NielsenAppApi(appInfo:appInformation, delegate:delegate)
    }
}

SDKMethods.swift

//
//  SDKMethods.swift
//  VideoPlayerWithSDKSwift
//
//

import Foundation

class SDKMethods : NSObject {
     var url = NSURL(string: "") 
    func setContentUrl() {        
        //Loading Content URL       
        url = NSURL(string: "http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8")
    }
    
    func setAdUrl() {        
        //Loading Ad URL        
        url = NSURL(string: "http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8")
    }
    
    func setDtvrUrl() {      
        //Loading DTVR URL      
        url = NSURL(string: "http://www.nielseninternet.com/VOD/NielsenScienceBehindWhatsNext/prog_index.m3u8")
    }
    
    func loadChannelInfo() -> [String : Any] { 
        //Loading Channel Info.
        let strUrl : String = (url?.absoluteString)!    
        let channel = [ "channelName" : "ChannelTitle",
                               "mediaURL" : strUrl] as [String : Any]     
        return channel
    }
    
    
    
    func loadContent() -> [String : Any] {
        
        //Loading Content data
        
        url = NSURL(string: "http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8")
        
        let content = [
            "type":"content",
            "assetid":"C77664",
            "length":"3600",
            "program":"MyProgram",
            "segB":"CustomSegmentValueB",
            "segC":"segmentC",
            "title":"S2,E3",
            "section":"cloudApi_app",
            "airdate":"20180221 10:00:00",
            "isfullepisode":"y",
            "adloadtype":"2",
            "channelName":"My Channel 1",
            "pipMode":"false" ] as [String : Any]
        
        
        return content
        
    }
    
    func loadPreRollAd() -> [String : Any] {       
        //loading Ad data.        
        url = NSURL(string: "http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8")
        
        let ad = [
            "type":"preroll",
            "assetid":"AD1",
            "title":"ADPreTitle"] as [String : Any]
        
        return ad
        
    }
    
    func loadDtvr() -> [String : Any] {        
        //Loading DTVR data        
        let dtvr = [
        "adModel": "1" ] as [String : Any]        
        return dtvr
        
    }
}

ViewController.swift

//
//  ViewController.swift
//  VideoPlayerWithSDKSwift
//
//

import UIKit
import AVKit
import CoreLocation
import AdSupport
import AVFoundation
import NielsenAppApi

class ViewController: UIViewController, NielsenAppApiDelegate, AVPlayerViewControllerDelegate {
    
    var nielsenApi : NielsenAppApi!
    var videoType : Int!
    var player : AVPlayer!
    var controller : AVPlayerViewController!
    var sdkMethods : SDKMethods!
    
    var data : [String : Any]!
    var timeObserver: Any!
    var totalVideosPlayed = 0
    var totalVideos : Int!
    
    var TimedMetadataObserverContext = 3
    var array : Any!
    let timedMetadataKey = "currentItem.timedMetadata"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //Mark: In NielsenInit class we are initialising the NielsenApi.
        
        //Getting the instance of NielsenApi
        self.nielsenApi = NielsenInit.createNielsenApi(delegate: self)
        
        //Mark: In SDKMethods class we wrote methods which creates content,Ad,DTVR objects
        sdkMethods = SDKMethods()
        
        if(videoType == Constants.onlyContent){
            //loading video content url
            sdkMethods.setContentUrl()
            
        }else if(videoType == Constants.dtvrVideo){
            //loading video DTVR url
            sdkMethods.setDtvrUrl()
            
        }else{
            //loading video Ad url
            sdkMethods.setAdUrl()
        }
        
        
        setPlayer()
        
        if(videoType != Constants.dtvrVideo){
            
            //For DTVR video playHeadPosition is not required
            //For DCR Content,Ad videos only this method will execute.
            setPlayHeadPosition()
        }
        
        //Setting observer to know the completion of video
        setVideoFinishObserver()
    }
    
    func setPlayer() {
        
        //creating player
        player  = AVPlayer.init(url: sdkMethods.url! as URL)
        controller = AVPlayerViewController()
        controller.view.frame = CGRect(x:0 , y:100, width: self.view.frame.width, height: 300)
        controller.player = player;
        controller.showsPlaybackControls = true;
        controller.delegate = self;
        
        player.play()
        
        if(totalVideosPlayed == 0){
            //For first time sending Channel info to SDK using "play" method.
            nielsenApi.play(sdkMethods.loadChannelInfo())
        }
        
        if(videoType == Constants.dtvrVideo){
            
            //loading DTVR metadata
            self.data = sdkMethods.loadDtvr()
        }else{
            
            //loading video content metadata data
            self.data = sdkMethods.loadContent()
        }
        //Sending metadata to SDK.
        nielsenApi.loadMetadata(self.data)
        
        if(videoType == Constants.contentWithOneAd){
            //loading Ad data
            self.data = sdkMethods.loadPreRollAd()
            nielsenApi.loadMetadata(self.data)
        }
        
        //Adding observer to player to track play,pause and reverse
        player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.new, context: nil)
        
        //Only for DTVR videos we are tracking iD3 Tags and sends to SDK after extracting.
        if(videoType == Constants.dtvrVideo){
            
            //Setting observer to track timedMetadata
            player.addObserver(self, forKeyPath: timedMetadataKey, options: NSKeyValueObservingOptions.new, context: &TimedMetadataObserverContext)
            
        }
        
        self.addChildViewController(controller)
        self.view .addSubview(controller.view)
    }
    
    func setPlayHeadPosition() {
        //Setting play head position
        let timeInterval : CMTime = CMTimeMakeWithSeconds(1.0, 10)
        controller.player?.addPeriodicTimeObserver(forInterval: timeInterval, queue: DispatchQueue.main) {(elapsedTime: CMTime) -> Void in
            
            let time : Float64 = self.controller.player!.currentTime().seconds;
            let pos = Int64(time);
            //Sending playHeadPosition to SDK.
            self.nielsenApi?.playheadPosition(pos);
        }
    }
    
    func setVideoFinishObserver() {
        //observer fires on completion video.
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: controller.player?.currentItem)
    }
    
    //rate 0.0 = Video Pause or stopped
    //rate 1.0 = Video played or resumed
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        if keyPath == timedMetadataKey {
            if(context == &TimedMetadataObserverContext){
                if change != nil {
                    let timedMetadataArray = change![.newKey]
                    if timedMetadataArray != nil && (timedMetadataArray! as AnyObject) is Array<Any> {
                        for item in timedMetadataArray as! [AVMetadataItem]  {
                            //Handling TimedMetadata
                            self.handleTimedMetadata(metadataItem: item)
                        }
                    }
                }
            }
        }
        
        if keyPath == "rate" {
            if let rate = change?[NSKeyValueChangeKey.newKey] as? Float {
                
                if rate == 0.0 {
                    print("Playback stopped")
                    //On Video pause calling the "stop" method of SDK.
                    nielsenApi.stop()
                }
                if rate == 1.0 {
                    print("normal playback")
                    //On video Resume calling "loadMetada" method of SDK
                    nielsenApi.loadMetadata(self.data)
                }
            }
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        
        //On moving to other screen calling "stop" method of SDK.
        nielsenApi.stop()
        player.rate = 0
        player.pause()
    }
    
    @objc func playerDidFinishPlaying(note: NSNotification) {
        
        self.player?.removeObserver(self, forKeyPath: "rate")
        
        //As 1 video completed playing, incrementing the variable value.
        totalVideosPlayed += 1
        
        if(videoType == Constants.onlyContent || totalVideosPlayed == totalVideos){
             //When content video completes or total videos finishes, call "end" method.
            nielsenApi.end()
            
        }else if(videoType == Constants.contentWithOneAd){
            
            //On completion of "AD" call "stop" method.
            nielsenApi.stop()
            
            //After preRoll ad completes, load content video.
            self.data = sdkMethods.loadContent()
            
        }
        
        //Checking if total videos played or not.
        if(totalVideosPlayed != totalVideos){
            
            setPlayer()
            setPlayHeadPosition()
            
            //Setting observer to know the completion of video
            setVideoFinishObserver()
            
        }
    }
    
    deinit {
        
        print("Remove NotificationCenter Deinit")
        NotificationCenter.default.removeObserver(self)
    }
    
    //######### DTVR code starts here #############//
    
    func handleTimedMetadata(metadataItem: AVMetadataItem) {
        guard let extraAttributeType = metadataItem.extraAttributes else {
            return
        }
        let info : AVMetadataExtraAttributeKey = AVMetadataExtraAttributeKey(rawValue: "info")
        let extraString = extraAttributeType[info] as AnyObject
        let key = metadataItem.key as! String
        
        //If tag starts with "www.nielsen.com", then only sending to SDK
        if key == "PRIV" && extraString.range(of: "www.nielsen.com").length > 0 {
            
            DispatchQueue.global(qos: .default).async { () -> Void in
                self.nielsenApi?.sendID3(extraString as! String)
            }
        }
    }
    
    
}