<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://engineeringportal.nielsen.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=BryanLim</id>
	<title>Engineering Client Portal - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://engineeringportal.nielsen.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=BryanLim"/>
	<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/wiki/Special:Contributions/BryanLim"/>
	<updated>2026-04-06T08:05:32Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.5</generator>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Browser_SDK&amp;diff=5517</id>
		<title>DCR Thailand Video Browser SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Browser_SDK&amp;diff=5517"/>
		<updated>2021-11-25T05:09:18Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The Browser SDK (BSDK) is the framework for website developers to integrate Nielsen Measurement into their media players. Nielsen SDKs are also equipped to measure static content and can track key life cycle events.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 30px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-&lt;br /&gt;
|| ☑ || '''App ID (apid)''' || Unique ID assigned to the player/site and configured by product. During initial implementation, a 'test' apid will be given. Once the implementation has been certified, a 'production' apid will then be generated and needs to be used before 'going live'. || Contact Nielsen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Configure SDK ==&lt;br /&gt;
There are two steps required for configuring the SDK:&lt;br /&gt;
*Add Static Queue Snippet&lt;br /&gt;
*Create SDK Instance&lt;br /&gt;
&lt;br /&gt;
=== Static Queue Snippet ===&lt;br /&gt;
The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the following script tag to the website:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Create SDK Instance===&lt;br /&gt;
To initialize the SDK, create an SDK instance by making the initialization call:&lt;br /&gt;
&lt;br /&gt;
==== Initialization API Call ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
NOLBUNDLE.nlsQ(&amp;quot;&amp;lt;apid&amp;gt;&amp;quot;, &amp;quot;&amp;lt;instanceName&amp;gt;&amp;quot;,{nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
When creating an instance, pass the following values: (&amp;lt;code&amp;gt;nol_sdkDebug&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;optout&amp;lt;/code&amp;gt; are optional)&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter	!! Description	!! Values&lt;br /&gt;
|-&lt;br /&gt;
| apid	|| Unique ID assigned to player/site ||	&lt;br /&gt;
'TXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Test Apid that starts with 'T'&amp;lt;br/&amp;gt;&lt;br /&gt;
'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Production Apid that starts with 'P'&lt;br /&gt;
|-&lt;br /&gt;
|instanceName ||	Name of SDK instance ||	&amp;quot;any string value&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| nol_sdkDebug	|| Enables Nielsen console logging if desired. 	|| &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{nol_sdkDebug: &amp;quot;debug&amp;quot;} &lt;br /&gt;
{nol_sdkDebug: &amp;quot;info&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;warn&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;true&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|optout || Optional: OptOut global parameter. || &amp;lt;code&amp;gt;1/0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;true/false&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example SDK Initialization ====&lt;br /&gt;
When the initialization call is made, a unique static configuration file, &amp;lt;apid&amp;gt;.js, will be downloaded based on the apid and will be cached on the user’s browser.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
    nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
    optout: &amp;quot;false&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.bundle.min.js”. More information on OptOut Parameter under [[DCR Thailand Video Browser SDK#Privacy_and_Opt-Out|Privacy and Opt-Out.]]&lt;br /&gt;
&lt;br /&gt;
=== Example SDK Configuration ===&lt;br /&gt;
&lt;br /&gt;
The configuration should include the Static Queue Snippet and an SDK Instance for an unique App ID as shown in the example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Add Static Queue Snippet&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
// Created SDK Instance&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/script&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create Metadata Objects ===&lt;br /&gt;
There are two types of asset metadata:&lt;br /&gt;
*content: identify video&lt;br /&gt;
*ad: identify each ad&lt;br /&gt;
&lt;br /&gt;
The metadata received for each asset is used for classification and reporting.&lt;br /&gt;
&lt;br /&gt;
Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.&lt;br /&gt;
&lt;br /&gt;
==== Content Metadata ====&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| For VOD: Populate TVContent ID, For livestream: leave blank	|| custom	 || Required for VOD only&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Content Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var contentMetadataObject =&lt;br /&gt;
{  &lt;br /&gt;
  type:           'content',&lt;br /&gt;
  assetid:        'VID-123456',&lt;br /&gt;
  program:        'program name',&lt;br /&gt;
  title:          'episode title',&lt;br /&gt;
  length:         'length in seconds',&lt;br /&gt;
  isfullepisode:  'y',&lt;br /&gt;
  adloadtype:     '2',&lt;br /&gt;
  segB:           'custom segment B', // optional&lt;br /&gt;
  segC:           'custom segment C', // optional&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var adMetadataObject = &lt;br /&gt;
{  &lt;br /&gt;
  type:    'preroll',&lt;br /&gt;
  assetid: 'AD-1'&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt; URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Call Nielsen APIs ====&lt;br /&gt;
The method for calling events is ggPM().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
nSdkInstance.ggPM('event', parameter, ...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt Scenarios ==&lt;br /&gt;
&lt;br /&gt;
=== Pause Event ===&lt;br /&gt;
The setPlayheadPostion event is used for handling pause. To indicate pause, stop passing the playhead position to the SDK. Once the content resumes, begin sending the playhead again with the correct playhead value.&lt;br /&gt;
&lt;br /&gt;
=== Other Interrupt Scenarios ===&lt;br /&gt;
The following possible browser interruption scenarios must be handled:&lt;br /&gt;
&lt;br /&gt;
* Browser/Tab close&lt;br /&gt;
* Leaving the page to another destination&lt;br /&gt;
* Pressing the stop button&lt;br /&gt;
* Network Loss&lt;br /&gt;
&lt;br /&gt;
There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener('beforeunload', function(event) &lt;br /&gt;
{&lt;br /&gt;
  // Only inside a midroll indicate &amp;lt;stop&amp;gt; for the ad&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
  &lt;br /&gt;
  // Indicate &amp;lt;end&amp;gt; and &amp;lt;stop&amp;gt; for the content&lt;br /&gt;
  nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position in seconds	|| Call when content or ads complete playing and pass playhead position&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SDK Playhead Event Sequence ==&lt;br /&gt;
The sample event lifecycles can be used as a reference for identifying the order for calling events.&lt;br /&gt;
&lt;br /&gt;
=== Content Playback ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// CONTENT PLAYS&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Content Playback with Ads ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// PREROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// MIDROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT RESUMES&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// POSTROLL&lt;br /&gt;
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.&lt;br /&gt;
&lt;br /&gt;
* For Ad Pods, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.&lt;br /&gt;
&lt;br /&gt;
* When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are two primary methods for implementing user Opt-out preferences:&lt;br /&gt;
# [[#User Opt Out|User Opt Out]] - Provide a link to the Nielsen Privacy Policy page when a User can make their selection&lt;br /&gt;
# [[#Initialization Opt Out|Initialization Opt Out]] - Global OptOut Parameter&lt;br /&gt;
&lt;br /&gt;
=== User Opt Out === &lt;br /&gt;
The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the User Opt-Out option, include the following two items in your privacy policy.&lt;br /&gt;
*A notice that the player (or page in relation to static measurement) includes proprietary measurement software that allows users to contribute to market research (such as Nielsen Content Ratings).&lt;br /&gt;
*A link to the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&lt;br /&gt;
On the Nielsen Digital Measurement Privacy Policy page, users can click Choices to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen online measurement, click a link to receive an opt-out cookie.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
* Once users have opted out via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=total&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/  link], their browser cookies will contain the value '''TOTAL_OPTOUT'''. This will prevent a redirect to our data provider from occurring&lt;br /&gt;
* Users can opt back in via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=cancel&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/ link].  When a user selects that link, their opt-out cookie will be deleted and they will be able to be measured moving forward.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The following paragraph is a template for a Privacy Statement.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research, such as Nielsen Digital Content Ratings. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== User Opt Back In ====&lt;br /&gt;
Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.&lt;br /&gt;
&lt;br /&gt;
=== Initialization Opt Out ===&lt;br /&gt;
The BSDK600 now supports the ability to optout on initialization of the SDK by allowing an optout global parameter to be passed.  This optout will be maintained through the session of the SDK instance. Specifications and limitations are specified below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type&lt;br /&gt;
! Supported Values&lt;br /&gt;
! Notes&lt;br /&gt;
! Optout&lt;br /&gt;
|-&lt;br /&gt;
||optout||True, Yes, or 1|| Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: true});&lt;br /&gt;
|| Ping parameter will set uoo=true.&lt;br /&gt;
|-&lt;br /&gt;
||optout|| False, No, or 0 || Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: false});&lt;br /&gt;
|| Ping parameter will set uoo to blank.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
==== Example of using OptOut ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
  nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
  optout: &amp;quot;true&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Opt Out Overview ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser Cookie&lt;br /&gt;
! uoo value in session ping&lt;br /&gt;
! Final Optout Status&lt;br /&gt;
|-&lt;br /&gt;
||Default Value || no uoo value or uoo=0|| Not Opted Out&lt;br /&gt;
|-&lt;br /&gt;
||Default Value ||  uoo=1 || Opted Out&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
After the integration has been certified, users will need to make a couple of updates to the initialization call to ensure that player will be measured properly. Ensure that a production apid (starting with 'P') is used after going live.&lt;br /&gt;
Disable debug logging by deleting {nol_sdkDebug: 'DEBUG'} from initialization call.&lt;br /&gt;
&lt;br /&gt;
'''Example Production Initialization Call'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, { optout: &amp;quot;false&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_iOS_SDK&amp;diff=5516</id>
		<title>DCR Thailand Video iOS SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_iOS_SDK&amp;diff=5516"/>
		<updated>2021-11-25T05:07:01Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}} {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
This guide covers implementation steps for iOS using Xcode utilizing the Standard Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{{iOS_SpecialNotes_for_iOS14}}&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[iOS SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
Version 8 of the Nielsen App SDK will come in three versions. One that is enabled to work with the App Tracking Transparency Framework, another version that does not use the Ad Framework, and a version for Kids Apps or where noID is required. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by the [https://developer.apple.com/documentation/apptrackingtransparency AppTrackingTransparency framework] . '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will attempt to collect the IDFA (Id for Advertisers) on the device.&amp;lt;br&amp;gt; * For iOS14+, if the value returned is &amp;lt;code&amp;gt;ATTrackingManager.AuthorizationStatus.authorized&amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;*  If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested.&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the IDFA, so it will attempt to retrieve the '''IDFV'''.&amp;lt;br /&amp;gt;* The [https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor ID for Vendors (IDFV)], may be used for analytics across apps from the same content provider.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Thailand_Video_iOS_SDK#Global_iOS_SDK_No_Ad_Framework_Optout|Privacy Section]].&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Thailand_Video_iOS_SDK#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
=== How to obtain the NielsenAppApi.Framework ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of CocoaPods. We recommend using the CocoaPods-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_iOS_Artifactory_Guide|Select to obtain CocoaPods implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
* [[DCR_Video_iOS_SDK_xcframework|Using the XCFramework bundle]]&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
Prior to SDK Version 6.2.0.0 the  IOS framework has been distributed as a static library packaged into framework bundle format. Apple recommends to use dynamic framework, it has some benefits over static libraries like less executable file size of an app, faster startup time and native support in xCode IDE. Nielsen AppSDK has been transformed into dynamic framework in this release ([[iOS_Static_Framework_Setup|static framework]] is still available).&lt;br /&gt;
&lt;br /&gt;
If migrating from the static library to this new dynamic framework, once implemented, unless your specific application requires, you can remove the following Frameworks that were once required:&amp;lt;code&amp;gt; [AdSupport, JavascriptCore, SystemConfiguration, Security, AVFoundation, libc++] &amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''Dynamic framework''' is created as a fat framework. It means that it contains slices required for devices (armv7, arm64) as well as slices required for simulators (i386, x86_64). Simulator slices are needed to let clients build and debug their app on the simulators, but they should be removed before sending the app to the AppStore. The example of the shell script that should be added as a Run Script phase in the application can be [[DCR_Thailand_Video_iOS_SDK#Removing_Simulators_.28Dynamic_Framework_Only.29|found below]].&lt;br /&gt;
&lt;br /&gt;
'''[[DCR_Video_iOS_SDK_xcframework|XCFramework]]''' is solution for the problems described above Apple recommends to use XCFrameworks. In XCFramework, we no longer build a single framework with multiple architectures. Instead, we build one small framework for each combination of architecture and target and store it in its own folder. The top-level XCFramework folder have folders like ios-arm64, ios-arm64-simulator, etc. Each of these folders is its own framework, complete with headers, modules, and binary.&lt;br /&gt;
&lt;br /&gt;
=== Configuring Xcode Development Environment ===&lt;br /&gt;
Starting with SDK version 6.0.0.0, the Nielsen App SDK is compatible with Apple iOS versions 8.0 and above.  In addition, when using the dynamic framework,  all the required frameworks are linked automatically as the are needed.  More details can be found here: https://stackoverflow.com/questions/24902787/dont-we-need-to-link-framework-to-xcode-project-anymore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': All communications between the SDK and the Census (Collection Facility) use HTTPS.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Download Framework ===&lt;br /&gt;
The first step is to download and copy the [[Special:Downloads|NielsenAppApi.framework]] bundle to the app project directory. (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Framework ===&lt;br /&gt;
In the General tab for app configuration add NielsenAppApi.framework in the list of Embedded Binaries.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Path ===&lt;br /&gt;
Add path to the NielsenAppApi.framework in the Framework Search Paths build setting.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Import Framework ===&lt;br /&gt;
Add NielsenAppApi.framework module in the source file of your app:&lt;br /&gt;
&lt;br /&gt;
==== Using Swift ====&lt;br /&gt;
Add the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using Objective-C ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@import NielsenAppApi;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_SDK_Initialization}}&lt;br /&gt;
&lt;br /&gt;
== Configure Metadata ==&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Nielsen Key names (e.g. appid, program) are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Create channelName Metadata ===&lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| Any string representing the channel/stream	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
=== Create Content Metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
&amp;lt;blockquote&amp;gt; program and title metadata values should be passed to SDK as UTF-8 strings. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| For VOD: Populate TVContent ID, For livestream: leave blank	|| custom	 || Required for VOD only&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Metadata Example ====&lt;br /&gt;
&amp;lt;code&amp;gt;Swift&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
let contentMetadata = [&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
    &amp;quot;assetid&amp;quot;: &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Program S2, E3&amp;quot;,&lt;br /&gt;
    &amp;quot;isfullepisode&amp;quot;: &amp;quot;y&amp;quot;,&lt;br /&gt;
    &amp;quot;program&amp;quot;: &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
    &amp;quot;adloadtype&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
    &amp;quot;segB&amp;quot;: &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    &amp;quot;segC&amp;quot;: &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Objective-C&amp;lt;/code&amp;gt;    &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt; &lt;br /&gt;
NSDictionary * contentMetadata = @ {&lt;br /&gt;
    @ &amp;quot;type&amp;quot;: @ &amp;quot;content&amp;quot;,&lt;br /&gt;
    @ &amp;quot;assetid&amp;quot;: @ &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    @ &amp;quot;title&amp;quot;: @ &amp;quot;S2,E3&amp;quot;,&lt;br /&gt;
    @ &amp;quot;isfullepisode&amp;quot;: @ &amp;quot;y&amp;quot;,  &lt;br /&gt;
    @ &amp;quot;program&amp;quot;: @ &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    @ &amp;quot;length&amp;quot;: @ &amp;quot;3600&amp;quot;,&lt;br /&gt;
    @ &amp;quot;adloadtype&amp;quot;: @ &amp;quot;2&amp;quot;,&lt;br /&gt;
    @ &amp;quot;segB&amp;quot;: @ &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    @ &amp;quot;segC&amp;quot;: @ &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Configure metadata === &lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| ChannelInfo refers to the Channel name. This can be a free-form value&lt;br /&gt;
value such as a friendly name for the content being played. the SDK&amp;lt;br/&amp;gt;&lt;br /&gt;
will pass the application name automatically.&lt;br /&gt;
|| custom	|| No&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create Ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_LifeCycle_of_SDK}}&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&amp;lt;!--[[File:appsdkTimeline-DCR.png|icon|link=]]--&amp;gt;&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;nielsenMeter.play()&amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nielsenMeter.loadMetadata(contentMetadata)&amp;lt;/code&amp;gt; || // MetadataObject contains the JSON metadata&amp;lt;br&amp;gt; for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;nielsenMeter.playheadPosition(pos);&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead &amp;lt;br&amp;gt;while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;nielsenMeter.end()&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'playheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current UNIX timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'PlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the UNIX timestamp, for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Idle state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for an event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position is active.  If a LIVE event, use the current UNIX timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the content or Ad playback is interrupted and at the end of each Ad. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, call &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should begin from 0 at ad start.  When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Sequence_of_Calls}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Foreground_and_Background}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Interuptions_during_Playback}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_NielsenAppSDKJSHandler}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_PreCertification_Checklists}}&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK: &lt;br /&gt;
# '''[[#Global_iOS_SDK_Opt-out|Global iOS SDK Opt-out]]''' - managed by ''AppTracking'' or ''Limit Ad Tracking'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_Ad_Framework_Optout|Global iOS SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without the Ad Framework&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Global iOS SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen iOS &lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the iOS's '''Limit Ad Tracking''' or '''AppTracking''' setting. &lt;br /&gt;
*  If the User's device is running &amp;lt; iOS 13.x, the Nielsen SDK will check the status of '''Limit Ad Tracking'''.&lt;br /&gt;
*  iOS14 modifies the way Apple manages the collection of a User's Opt-In status through '''AppTracking'''. Starting with Version 8.x+, the Nielsen App SDK will check the iOS version during initialization. If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested. If iOS14.x +, then AppTracking is utilized.&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global iOS SDK, this optOutURL informs the user how to deactivate/activate “App Tracking/Limit Ad Tracking”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No Ad Framework Optout ===&lt;br /&gt;
The ''User Choice'' method can be used without the Ad Framework, or in situations where the publisher does not wish to use the [https://developer.apple.com/documentation/apptrackingtransparency App Tracking Transparency Framework]. As this flavor of the Nielsen SDK does not use the Ad Framework, so it is necessary to display an Optout Page to the userand capture their selection.&lt;br /&gt;
&lt;br /&gt;
Similar to the Global iOS SDK Flavor, it is a requirement to display a WebView element whose loadUrl is set to the&lt;br /&gt;
value obtained from optOutURL. This is a special URL that indicates Opt-in, or Opt-out and close the WebView.&lt;br /&gt;
&lt;br /&gt;
==== This opt-out method works as follows: ====&lt;br /&gt;
* Get the Nielsen opt-out URL via [[optOutURL]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[optOutURL]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No ID Optout (Kids Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the [https://nielsendownloads-green.digitalengsdk.com/digital/Nielsen-iOS-App-SDK-GlobalNoId_latest.zip NoID version] of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Opt-out example code ==&lt;br /&gt;
===== Swift =====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
import WebKit&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&lt;br /&gt;
class OptOutVC: UIViewController, NielsenAppApiDelegate, WKNavigationDelegate {&lt;br /&gt;
    var nielsenApi : NielsenAppApi!&lt;br /&gt;
    var webView: WKWebView!&lt;br /&gt;
   &lt;br /&gt;
    override func loadView() {&lt;br /&gt;
        webView = WKWebView()&lt;br /&gt;
        webView.navigationDelegate = self&lt;br /&gt;
        view = webView&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
&lt;br /&gt;
        if let appApi = self.nielsenApi {&lt;br /&gt;
            //Getting the optPut URL from SDK&lt;br /&gt;
            if let url = URL(string: appApi.optOutURL) {&lt;br /&gt;
                webView.load(URLRequest(url: url))&lt;br /&gt;
                webView.allowsBackForwardNavigationGestures = true&lt;br /&gt;
            }}}&lt;br /&gt;
&lt;br /&gt;
        func closeOptOutView() {&lt;br /&gt;
            self.dismiss(animated: true, completion: nil)&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
// Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.  This will receive the user's selection&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*  &lt;br /&gt;
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: &lt;br /&gt;
@escaping (WKNavigationActionPolicy) -&amp;gt; Void) {&lt;br /&gt;
            print(navigationAction.request.url?.absoluteString as Any) //For debugging to check what is being passed from webpage.&lt;br /&gt;
            if navigationAction.request.url?.absoluteString == &amp;quot;nielsen://close&amp;quot; {&lt;br /&gt;
                closeOptOutView()&lt;br /&gt;
                decisionHandler(.cancel)&lt;br /&gt;
            } else {&lt;br /&gt;
                if let url = navigationAction.request.url?.absoluteString, url.hasPrefix(&amp;quot;nielsen&amp;quot;) {&lt;br /&gt;
                    nielsenApi?.userOptOut(url). //either nielsenappsdk://1 or nielsenappsdk://0&lt;br /&gt;
                    decisionHandler(.cancel)&lt;br /&gt;
                } else {&lt;br /&gt;
                    if navigationAction.navigationType == .linkActivated {&lt;br /&gt;
                        if let url = navigationAction.request.url?.absoluteString, url.hasSuffix(&amp;quot;#&amp;quot;) {&lt;br /&gt;
                            decisionHandler(.allow)&lt;br /&gt;
                        } else {&lt;br /&gt;
                            decisionHandler(.cancel)&lt;br /&gt;
                            webView.load(navigationAction.request)&lt;br /&gt;
                        }&lt;br /&gt;
                    } else {&lt;br /&gt;
                        decisionHandler(.allow)&lt;br /&gt;
                    }}}}&lt;br /&gt;
  */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===== Objective-C =====&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#import &amp;quot;OptOutVC.h&amp;quot;&lt;br /&gt;
#import &amp;quot;NielsenInit.h&amp;quot;&lt;br /&gt;
#import &amp;lt;NielsenAppApi/NielsenAppApi.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@interface OptOutVC ()&lt;br /&gt;
&lt;br /&gt;
@property (weak, nonatomic) IBOutlet UIWebView *webView;&lt;br /&gt;
@end&lt;br /&gt;
&lt;br /&gt;
@implementation OptOutVC&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
    //Getting the optPut URL from eventTracker&lt;br /&gt;
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL&lt;br /&gt;
 URLWithString:self.nielsenApi.optOutURL]]];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*     &lt;br /&gt;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction&lt;br /&gt;
 decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler&lt;br /&gt;
{&lt;br /&gt;
    if ([navigationAction.request.URL.absoluteString isEqualToString:kNielsenWebClose])&lt;br /&gt;
    {   [self performSelector:@selector(closeOptOutView) withObject:nil afterDelay:0];&lt;br /&gt;
        decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
     } else {&lt;br /&gt;
        if ([navigationAction.request.URL.absoluteString hasPrefix:@&amp;quot;nielsen&amp;quot;])&lt;br /&gt;
        {[self.nielsenAppApi userOptOut:navigationAction.request.URL.absoluteString];&lt;br /&gt;
            decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
        } else {&lt;br /&gt;
            if (navigationAction.navigationType == WKNavigationTypeLinkActivated) &lt;br /&gt;
            { if ([navigationAction.request.URL.absoluteString hasSuffix:@&amp;quot;#&amp;quot;]) &lt;br /&gt;
                      {decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
                } else {&lt;br /&gt;
                    decisionHandler(WKNavigationActionPolicyCancel);&lt;br /&gt;
                    [webView loadRequest:[NSURLRequest requestWithURL:navigationAction.request.URL]];&lt;br /&gt;
                }} else {&lt;br /&gt;
                 decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
            }}}&lt;br /&gt;
*/&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via User Choice Opt-out, the current Opt-Out status as detected by the SDK is available via the [[optOutStatus]] property in the Nielsen SDK API&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@property (readonly) BOOL optOutStatus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Airplay}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Going_Live}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Removing_Simulator_Slices}}&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the Simplified API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen Simplified API using a standard no-frills player.&lt;br /&gt;
** [[Swift Basic Sample|Swift 5.0 Sample]]&lt;br /&gt;
** [[Objective-c Basic example|Objective-C Sample]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen Simplified API integrated into a custom video player.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Android_SDK&amp;diff=5515</id>
		<title>DCR Thailand Video Android SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Android_SDK&amp;diff=5515"/>
		<updated>2021-11-25T05:02:58Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[Android SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
This guide covers implementation steps for Android Studio utilizing the Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''Android Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by Opt out of Ads Personlization setting on device. '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will collect the [https://developer.android.com/training/articles/ad-id Google Advertising ID] unless the user Opts Out.&amp;lt;br&amp;gt;* If the Google Play Service is unavailable, (ie: Amazon and Huawei devices) the Nielsen sdk will secure the Android ID.&amp;lt;br&amp;gt; * There are 3 versions available starting with the Nielsen SDK 8.1.0.0.&lt;br /&gt;
|-&lt;br /&gt;
| '''Android No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the Google Advertising ID, so will retrieve the '''AndroidID'''.&amp;lt;br /&amp;gt;* The AndroidID is a 64-bit number (expressed as a hexadecimal string), unique to each combination of app-signing key, user and device.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Thailand_Video_Android_SDK#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Opt-out]].&lt;br /&gt;
|-&lt;br /&gt;
| '''Android SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Thailand_Video_Android_SDK#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== How to obtain the NielsenAppApi ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of Gradle. We recommend using the Gradle-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_Android_Artifactory_Guide|Select to obtain Gradle implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
&lt;br /&gt;
=== Configuring Android Development Environment ===&lt;br /&gt;
*The Nielsen App SDK (located in the [https://engineeringportal.nielsen.com/docs/Special:Downloads Downloads section] of the website) class is the primary application interface to the Nielsen App SDK on Android.&lt;br /&gt;
*The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.&lt;br /&gt;
*The Nielsen App SDK can also be added as a [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Android_Artifactory_Guide Artifact Repository]. If implemented this way, you do not need to download the appsdk from the Nielsen Portal.&lt;br /&gt;
&lt;br /&gt;
'''Nielsen App SDK is compatible with Android OS versions 2.3+. Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.'''&lt;br /&gt;
&lt;br /&gt;
The requirement for the Java ''AppSdk.jar'' library and the ''libAppSdk.so'' native library will depend on the type of host application that will make use of them.&lt;br /&gt;
* '''For Video player applications'''&lt;br /&gt;
** The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 3.0 and later will support it natively).&lt;br /&gt;
** If the player application uses a 3rd party media player implementing its own HLS, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.&lt;br /&gt;
&lt;br /&gt;
Once SDK is downloaded ensure to unzip the Nielsen SDK and copy the AppSdk.jar in your app (Android Studio) libs folder, then right click the AppSdk.jar and select '''Add As Library'''.&lt;br /&gt;
Ensure the AppSdk.jar file is added in 'build.grade (App Level) file.&lt;br /&gt;
* App SDK 1.2 provides support for x86, mips, and armeabi-7a architecture.&lt;br /&gt;
&lt;br /&gt;
==== Google Play Services ====&lt;br /&gt;
Add the Google Play Services in the project,&lt;br /&gt;
Steps: Android Studio -&amp;gt; File -&amp;gt; Project Structure -&amp;gt;(In module selection) select App -&amp;gt; Dependencies (tab) -&amp;gt; Click &amp;quot;+&amp;quot; button and search for &amp;lt;code&amp;gt;&amp;quot;*play-services*&amp;quot;&amp;lt;/code&amp;gt;.  Then select the most recent version of the [https://developers.google.com/admob/android/quick-start play-services Artifact].&lt;br /&gt;
Ensure it is added in build.gradle (App level) file&lt;br /&gt;
&lt;br /&gt;
==== Manifest File ==== &lt;br /&gt;
* Add the following permissions on the project’s ''AndroidManifest.xml'' file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more details to handle runtime permissions in Android versions, please visit [https://developer.android.com/training/permissions/requesting.html].   &lt;br /&gt;
&lt;br /&gt;
* In &amp;lt;code&amp;gt;AndroidManifest.xml &amp;lt;/code&amp;gt;under &amp;lt;application&amp;gt; node add the following metadata&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;manifest&amp;gt;&lt;br /&gt;
    &amp;lt;application&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 --&amp;gt;&lt;br /&gt;
        &amp;lt;meta-data&lt;br /&gt;
            android:name=&amp;quot;com.google.android.gms.ads.APPLICATION_ID&amp;quot;&lt;br /&gt;
            android:value=&amp;quot;ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/application&amp;gt;&lt;br /&gt;
&amp;lt;/manifest&amp;gt;&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* App SDK checks to see if there is a Google service available and updated.&lt;br /&gt;
* If not available or updated, App SDK will not use this service when executing its functions and will make reference to missing imports and the app will not be compiled.&lt;br /&gt;
&lt;br /&gt;
==== Library ====&lt;br /&gt;
Nielsen App SDK uses the following packages/classes from the [https://developers.google.com/android/guides/setup Google Play service].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;coffeescript&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
  implementation 'com.google.android.gms:play-services-ads:xx.x.x'&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Classes/package ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;&lt;br /&gt;
import com.google.android.gms.common.ConnectionResult;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesUtil;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesRepairableException;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SDK Initialization ==&lt;br /&gt;
The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object, which can be used simultaneously without any issue. The sharedInstance API that creates a singleton object was deprecated prior to version 5.1.1. (Version 4.0 for Android)&lt;br /&gt;
&lt;br /&gt;
The following table contains the list of arguments that can be passed via the AppInfo JSON schema.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter / Argument !! Description !! Source !! Required? !! Example&lt;br /&gt;
|-&lt;br /&gt;
| appid || Unique Nielsen ID for the application. The ID is a GUID data type. If you did not receive your App ID, let us know and we will provide you. || Nielsen-specified || Yes || PXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;br /&gt;
|-&lt;br /&gt;
| nol_devDebug || Enables Nielsen console logging. Only required for testing&lt;br /&gt;
|| Nielsen-specified || Optional || &amp;quot;DEBUG&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debug flag for development environment ==&lt;br /&gt;
Player application developers / integrators can use Debug flag to check whether an App SDK API call made is successful. To activate the Debug flag,&lt;br /&gt;
Pass the argument &amp;lt;code&amp;gt;@&amp;quot;nol_devDebug&amp;quot;:@&amp;quot;INFO&amp;quot;&amp;lt;/code&amp;gt;, in the JSON string . The permitted values are:&lt;br /&gt;
&lt;br /&gt;
* '''INFO''': Displays the API calls and the input data from the application (validate player name, app ID, etc.). It can be used as certification Aid.&lt;br /&gt;
* '''WARN''': Indicates potential integration / configuration errors or SDK issues.&lt;br /&gt;
* '''ERROR''': Indicates important integration errors or non-recoverable SDK issues.&lt;br /&gt;
* '''DEBUG''': Debug logs, used by the developers to debug more complex issues.&lt;br /&gt;
&lt;br /&gt;
Once the flag is active, it logs each API call made and the data passed. The log created by this flag is minimal.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': DO NOT activate the Debug flag in a production environment.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Sample SDK Initialization Code ====&lt;br /&gt;
[[AppSDK()]] is no longer a singleton object and should be initialized as below.&lt;br /&gt;
&lt;br /&gt;
'''Initialization of App SDK object through a JSON object'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;try&lt;br /&gt;
{&lt;br /&gt;
  // Prepare AppSdk configuration object (JSONObject)&lt;br /&gt;
  JSONObject appSdkConfig = new JSONObject()&lt;br /&gt;
          .put(&amp;quot;appid&amp;quot;, &amp;quot;PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA&amp;quot;)&lt;br /&gt;
          .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;); // only for debug builds&lt;br /&gt;
&lt;br /&gt;
// Pass appSdkConfig to the AppSdk constructor&lt;br /&gt;
mAppSdk = new AppSdk(appContext, appSdkConfig, appSdkListener);&lt;br /&gt;
}&lt;br /&gt;
catch (JSONException e)&lt;br /&gt;
{&lt;br /&gt;
  Log.e(TAG, &amp;quot;Couldn’t prepare JSONObject for appSdkConfig&amp;quot;, e);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, &amp;lt;code&amp;gt;appContext&amp;lt;/code&amp;gt; is the App context object and &amp;lt;code&amp;gt;appSdkConfig&amp;lt;/code&amp;gt; is JSON object for holding the parameters (&amp;lt;code&amp;gt;appid&amp;lt;/code&amp;gt;) the App passes to the Nielsen App SDK via a JSON string. The appid is obtained from Nielsen operational support and is unique to the app.&lt;br /&gt;
&lt;br /&gt;
The integration of Nielsen App SDK will depend on type of client app.&amp;lt;br /&amp;gt;&lt;br /&gt;
* Ensure that SDK files (AppSdk.jar and libAppSdk.so [App SDK 1.2 Only]) are included under the App’s project and the App SDK is linked to the App (the setting to link App SDK to the App can be found on property page of the App’s project).&lt;br /&gt;
&lt;br /&gt;
== APP SDK Error &amp;amp; Event Codes ==&lt;br /&gt;
To view the Error and Event codes for iOS and Android, please review the [[APP SDK Event Codes|App SDK Event Code]] Reference page.&lt;br /&gt;
&lt;br /&gt;
== Configure Payload ==&lt;br /&gt;
=== Handling JSON Metadata ===&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Variable Names like appid, appname, sfcode, dataSrc, title, type etc. are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
JSONObject contentMetadata = new JSONObject()&lt;br /&gt;
//SDK Metadata&lt;br /&gt;
    .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;assetid&amp;quot;, &amp;quot;vid345-67483&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;title&amp;quot;, &amp;quot;Program S3, EP1&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;isfullepisode&amp;quot;, &amp;quot;y&amp;quot;) &lt;br /&gt;
    .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentValueB&amp;quot;)  //optional&lt;br /&gt;
    .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentValueC&amp;quot;)  //optional   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Content metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| For VOD: Populate TVContent ID, For livestream: leave blank	|| custom	 || Required for VOD only&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Example Ad Object ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sequence of Calls ==&lt;br /&gt;
=== play ===&lt;br /&gt;
Use [[DCR_Video_APP_SDK#play|play]] to pass the channel descriptor information through channelName parameter when the user taps the '''Play''' button on the player.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    public void play(JSONObject channelInfo);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== loadMetadata ===&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void loadMetadata(JSONObject contentMetadata);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== playheadPosition ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void setPlayheadPosition(long position)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stop ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void stop()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== end ===&lt;br /&gt;
When content stop is initiated and content cannot be resumed from the same position (it can only be restarted from the beginning of stream).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void end()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;[nielsenMeter play];&amp;lt;/code&amp;gt; || // call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[nielsenMeter loadMetadata: contentMetadataObject];&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;[nielsenMeter setplayheadPosition: position];&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;[nielsenMeter end];&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the Unix timestamp; for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Initial state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''setplayheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position timer is fired.  If a LIVE event, use the current Unix timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the playback is paused, switches between content and ad (within the same content playback) or encounters interruptions.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.&lt;br /&gt;
## Initialization fails&lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop()]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- &lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] &lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad-123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
'''Ad Content'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    long pos = mAdPlayer.videoPosition() / 1000;&lt;br /&gt;
   if (mAppSdk != null)&lt;br /&gt;
   {&lt;br /&gt;
     mAppSdk.setPlayheadPosition(pos);&lt;br /&gt;
   }&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: The playhead positions for ad and content should be maintained separately.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
|  rowspan=&amp;quot;1&amp;quot; | End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should reset or begin from 0 at ad start. When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handling Foreground and Background states ==&lt;br /&gt;
There are a few approaches to managing the Foreground and Background states of an app available to use for state measurement.&lt;br /&gt;
* Utilizing the Androidx LifeCycleObserver (The recommended approach starting sdk version 7.1.0.0+)&lt;br /&gt;
* Utilizing the [[DCR_Video_Android_SDK#The_SdkBgFgDetectionUtility_class|SdkBgFgDetectionUtility]] class&lt;br /&gt;
* Adding a tag to the Manifest XML&lt;br /&gt;
* Manual Management&lt;br /&gt;
=== The LifeCycleObserver ===&lt;br /&gt;
AndroidX replaces the original support library APIs with packages in the androidx namespace, and Android Studio 3.2 and higher provides an automated migration tool. (Select '''Refactor&amp;gt; Migrate to AndroidX''' from the menu bar.)&lt;br /&gt;
&lt;br /&gt;
Starting with version 7.1.0, with AndroidX support, an additional utility is provided in the AppSDK - application background/foreground state detection by the AppSdk leveraging the Android Architecture component &amp;quot;LifeCycleObserver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The AppSdk is now capable of detecting the application UI visibility state transitions between background and foreground, without forcing the applications to register for AppSdk's AppSdkApplication class, which is responsible for handling the detection of application background/foreground state transitions at present.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Please note, that if you already have an app designed that utilizes the depreciated SdkBgFgDetectionUtility Class, the AppSDK will ignore any calls to these methods if it can utilize the LifeCycleObserver.  LifeCycleObserver based auto detection will take precedence. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
==== Adding the AndroidX dependency ====&lt;br /&gt;
In order to make use of the app background/foreground state transition auto detection feature of AndroidX AppSdk, the app gradle file needs the androidx dependency. The AppSdk API calls - &amp;lt;code&amp;gt;appInForeground()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;appInBackground()&amp;lt;/code&amp;gt;  will still be respected by AppSdk by executing the old AppSdk flow of handling &amp;quot;app in foreground&amp;quot; and &amp;quot;app in background&amp;quot; states as is.&lt;br /&gt;
&lt;br /&gt;
==== Using the LifeCycle Extension ====&lt;br /&gt;
The following androidx dependency is required in the app gradle file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
implementation &amp;quot;androidx.lifecycle:lifecycle-extensions:2.1.0&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
If you would like to take advantage of this auto detection feature of AppSdk at the very initial stage (e.g. splash screen or at of app launch time), before the AppSdk is initialized, can do so by calling the following newly introduced AppSdk public api, passing the application context :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void registerLifeCycleObserver(Context applicationContext)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Log messages for the new auto detection ====&lt;br /&gt;
&lt;br /&gt;
When the AppSdk app successfully registers for the LifeCycleObserver : &amp;lt;code&amp;gt;Registered LifeCycleObserver for App Background/Foreground auto-detection&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When the app enters the foreground state :&amp;lt;code&amp;gt;App is in foreground, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the app enters the background state :&amp;lt;code&amp;gt;App is in background, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the client app doesn't have the &amp;quot;androidx&amp;quot; gradle dependency and AppSdk fails to register LifeCycleObserver :&amp;lt;code&amp;gt;AndroidX LifecycleObserver can not be observed. Please use androidx dependency to activate SDK auto-detection of app background/foreground state.&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInForeground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - foreground&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInBackground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - background&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The SdkBgFgDetectionUtility class ===&lt;br /&gt;
Foreground/Background state measurement is a requirement of Nielsen AppSDK implementation which is especially crucial for static measurement. It may be implemented in multiple ways for Android. This includes&lt;br /&gt;
* Enable the Nielsen SDK to measure background/foreground state by makingthe relevant update to the AndroidManifest.&lt;br /&gt;
* Integrate Nielsen’s SdkBgFgDetectionUtility class within your Custom Application Class.&lt;br /&gt;
* Custom implementation of the required methods within your application.&lt;br /&gt;
&lt;br /&gt;
==== ForeGround/Background Measurement via AndroidManifest ====&lt;br /&gt;
The simplest way to measure the app background/foreground state is to add the following application tag to the Manifest XML. Integrating this into the Manifest XML will enable the SDK to measure app state directly. This approach is supported for Android 4.0 and up only; it requires that the application class is not in use for some other purpose.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;application android:name=&amp;quot;com.nielsen.app.sdk.AppSdkApplication&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using the Android SdkBgFbDetectionUtility Class ====&lt;br /&gt;
For developers who are already using the application class, it is recommended that background/foreground state is implemented using the  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class].  The  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] is compatible with Android 4+ and has been made available to Nielsen clients. (You will need to copy/paste the code provided into a file).&lt;br /&gt;
&lt;br /&gt;
==== Manual Background/ForeGround State Management ====&lt;br /&gt;
In cases where the developer is not able to use the AndroidManifest.xml solution nor the Nielsen provided   [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] the developer will need to manually identify the change of state through the application and call the respective API (appInForeground() or appInBackground()) to inform the SDK regarding the change of state from background to foreground or foreground to background.&lt;br /&gt;
&lt;br /&gt;
The SDK is informed about app state using the below methods.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
AppLaunchMeasurementManager.appInForeground(getApplicationContext());&lt;br /&gt;
AppLaunchMeasurementManager.appInBackground(getApplicationContext());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Within the lifecycle of individual activities, onResume() and onPause() are best suited to providing indication of the app state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Correct measurement of the foreground/background state is crucial to Static App measurement within Nielsen Digital Content Ratings (DCR).&lt;br /&gt;
== Using the NielsenAppSDKJSHandler ==&lt;br /&gt;
There could be a scenario in which a browser page, that is already tagged with the Nielsen BSDK, needs to be loaded via a webview.  In this situation it is recommended to use the '''NielsenAppSDKJSHandler''' which will allow communication between the AppSDK and the BSDK. &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''This feature is supported in versions 7.2 and above.'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
* Make sure you have the latest AppSdk.jar from Nielsen&lt;br /&gt;
* Enable the javascript on webview using below lines&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
 &amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
WebSettings webSetting = webView.getSettings();&lt;br /&gt;
webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Add  NielsenAppSDKJSHandler instance as javascript interface to webview with name “NielsenAppSDK” like below snippet&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext()), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This will enable listening to BSDK api calls within the APPSDK.  Please make sure your Technical Account Manager is aware that you wish to implement this method so a configuration file can be modified on the Nielsen servers; however, there are '''no changes required to the Browser page'''.&lt;br /&gt;
&lt;br /&gt;
==== Example:====&lt;br /&gt;
The below is an example of opening a webview with the NielsenAppSDKJSHandler&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
      WebSettings webSetting = webView.getSettings();&lt;br /&gt;
      webView.getSettings().setDomStorageEnabled(true); &lt;br /&gt;
      webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
      webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
      String url = &amp;quot;https://nielsen.com.index.htm&amp;quot;;&lt;br /&gt;
      webView.loadUrl(url);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;AndroidManifest.xml&amp;lt;/code&amp;gt; may need the following permissions set:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Closing NielsenAppSDKJSHandler ===&lt;br /&gt;
NielsenAppSDKJSHandler should be closed or cleaned up in below scenarios&lt;br /&gt;
* Before WebView is getting destructed&lt;br /&gt;
* Before loading new page&lt;br /&gt;
* Before closing application&lt;br /&gt;
NielsenAppSDKJSHandler provides a public interface with name &amp;quot;close()&amp;quot; and this function should be called on NielsenAppSDKJSHandler's instance in all above scenarios.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
// get your webview&lt;br /&gt;
WebView webView = findViewById(R.id.webView);&lt;br /&gt;
 &lt;br /&gt;
//Added JS Handler instance as java script interface for ggpm api type&lt;br /&gt;
NielsenAppSDKJSHandler jshandler = new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;);&lt;br /&gt;
webView.addJavascriptInterface(jshandler, &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
//Close JS Handler before making webview as null&lt;br /&gt;
jshandler.close();&lt;br /&gt;
webView = null;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interruptions during playback ==&lt;br /&gt;
As part of integrating Nielsen App SDK with the player application, the Video app developer needs to handle the following possible interruption scenarios:&lt;br /&gt;
* Pause / Play&lt;br /&gt;
* Network Loss (Wi-Fi / Airplane / Cellular)&lt;br /&gt;
* Call Interrupt (SIM or Third party Skype / Hangout call)&lt;br /&gt;
* Alarm Interrupt&lt;br /&gt;
* Content Buffering&lt;br /&gt;
* Device Lock / Unlock &lt;br /&gt;
* App going in the Background/Foreground&lt;br /&gt;
* Channel / Station Change Scenario&lt;br /&gt;
* Unplugging of headphone&lt;br /&gt;
In case of encountering one of the above interruptions, the player application needs to&lt;br /&gt;
* Call [[stop()]] immediately (except when content is buffering) and withhold sending playhead position.&lt;br /&gt;
* Start sending pings – &amp;lt;code&amp;gt;'loadMetadata'&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'playheadPosition'&amp;lt;/code&amp;gt; for the new viewing session, once the playback resumes.&lt;br /&gt;
Please see the [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Interruption_Scenarios Interruption Scenarios Page] for more details&lt;br /&gt;
&lt;br /&gt;
== Pre-Certification Checklists ==&lt;br /&gt;
After the application is ready to be sent for Nielsen Certification, please go through the [[Digital Pre-Certification Checklist App SDK]] and ensure the app behaves as expected, before submitting to Nielsen.&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK:&lt;br /&gt;
# '''[[#Global_Android_SDK_Opt-out|Global Android SDK Opt-out]]''' - managed by ''Opt out of Ads Personalization'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without Google Play Services or when using the noAd version of the SDK.&lt;br /&gt;
# '''[[#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Global Android SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen Android when the [https://developers.google.com/android/guides/setup Google Play services APIs] have been setup in your project.&lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the Android's '''Opt out of Ads Personalization''' setting. The user is opted out of demographic measurement if the OS-level '''Opt out of Ads Personalization''' setting is ''enabled''. As a publisher, you cannot override this setting.&lt;br /&gt;
&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global Android SDK, this optOutURL informs the user how to deactivate/activate “Out of Ads Personalization”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;'''Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/ for more information'''&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No Ad Framework Optout ===&lt;br /&gt;
The ''No Ad Framework Optout'' can be used when the host application does not leverage Google Play Services such as when using the noAd version or the NoID version.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Nielsen Android SDK 5.1.1.18 and above will check for ''OS-level opt-out'' first, if available. The user will be opted out if indicated at the OS-level '''OR''' the App-level.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The No Ad Framework Optout method works as follows: ====&lt;br /&gt;
* Get the current Nielsen opt-out URL via [[userOptOutURLString()]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[userOptOutURLString()]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut()]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No ID Optout (Kids_Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the NoID version of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OptOut Example Code ==&lt;br /&gt;
Below you will find some sample code for the:&lt;br /&gt;
* [[#Global OptOut Example|Global Android SDK]] - managed by Opt out of Ads Personalization setting on device '''(preferred approach)'''.&lt;br /&gt;
* [[#No_Ad_Framework_Optout_Sample_Code|Global Android noAd Framework]] - Use if Google Play APIs are unavailable or running noAd version.&lt;br /&gt;
*  It is currently not required to display an OptOut page for the NoID/Kids Build of the SDK.&lt;br /&gt;
===&amp;lt;span id=&amp;quot;Global OptOut Example&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Global OptOut Example ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user.  Please see the next section if using the No Ad Framework build&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;span id=&amp;quot;No Ad Framework Optout Sample Code&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;No Ad Framework Optout Sample Code ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user with the No Ad Framework SDK Build.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
            @Override&lt;br /&gt;
            public boolean shouldOverrideUrlLoading(WebView view, String url) {&lt;br /&gt;
&lt;br /&gt;
                if(url.contains(&amp;quot;nielsen&amp;quot;)){&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://1 it means the user selected Opt Out&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://0&amp;quot; it means the user selected Opt-In&lt;br /&gt;
                    appSdk.userOptOut(url);&lt;br /&gt;
                }&lt;br /&gt;
                return true;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Required Privacy Links ===&lt;br /&gt;
Users must either have access to the &amp;quot;About Nielsen Measurement&amp;quot; page, or have similar text available within the native app. Include &amp;quot;About Nielsen Measurement&amp;quot; and &amp;quot;Your Choices&amp;quot; link in the Privacy Policy / EULA or as a button near the link to the app's Privacy Policy.&lt;br /&gt;
&lt;br /&gt;
In addition, the following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
'''&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;'''&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via App-level Opt-out, the current Opt-Out status as detected by the SDK is available via the [[getOptOutStatus()]] property in the Nielsen Android SDK API. &amp;lt;code&amp;gt;appSdk.getOptOutStatus()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
Following Nielsen testing, you will need to:&lt;br /&gt;
&lt;br /&gt;
# '''Disable Debug Logging''': Disable logging by deleting &amp;lt;code&amp;gt;{nol_devDebug: 'DEBUG'}&amp;lt;/code&amp;gt; from initialization call.&lt;br /&gt;
# '''Notify Nielsen''': Once you are ready to go live, let us know so we can enable you for reporting. We will not be able to collect or report data prior to receiving notification from you.&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen  API using a standard no-frills player.&lt;br /&gt;
** [[Android Basic example|Android Studio Example]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen API integrated into a custom video player is bundled with the SDK.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Android_SDK&amp;diff=5512</id>
		<title>DCR Thailand Video Android SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Android_SDK&amp;diff=5512"/>
		<updated>2021-11-24T06:27:55Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[Android SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
This guide covers implementation steps for Android Studio utilizing the Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''Android Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by Opt out of Ads Personlization setting on device. '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will collect the [https://developer.android.com/training/articles/ad-id Google Advertising ID] unless the user Opts Out.&amp;lt;br&amp;gt;* If the Google Play Service is unavailable, (ie: Amazon and Huawei devices) the Nielsen sdk will secure the Android ID.&amp;lt;br&amp;gt; * There are 3 versions available starting with the Nielsen SDK 8.1.0.0.&lt;br /&gt;
|-&lt;br /&gt;
| '''Android No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the Google Advertising ID, so will retrieve the '''AndroidID'''.&amp;lt;br /&amp;gt;* The AndroidID is a 64-bit number (expressed as a hexadecimal string), unique to each combination of app-signing key, user and device.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Thailand_Video_Android_SDK#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Opt-out]].&lt;br /&gt;
|-&lt;br /&gt;
| '''Android SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Thailand_Video_Android_SDK#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== How to obtain the NielsenAppApi ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of Gradle. We recommend using the Gradle-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_Android_Artifactory_Guide|Select to obtain Gradle implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
&lt;br /&gt;
=== Configuring Android Development Environment ===&lt;br /&gt;
*The Nielsen App SDK (located in the [https://engineeringportal.nielsen.com/docs/Special:Downloads Downloads section] of the website) class is the primary application interface to the Nielsen App SDK on Android.&lt;br /&gt;
*The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.&lt;br /&gt;
*The Nielsen App SDK can also be added as a [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Android_Artifactory_Guide Artifact Repository]. If implemented this way, you do not need to download the appsdk from the Nielsen Portal.&lt;br /&gt;
&lt;br /&gt;
'''Nielsen App SDK is compatible with Android OS versions 2.3+. Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.'''&lt;br /&gt;
&lt;br /&gt;
The requirement for the Java ''AppSdk.jar'' library and the ''libAppSdk.so'' native library will depend on the type of host application that will make use of them.&lt;br /&gt;
* '''For Video player applications'''&lt;br /&gt;
** The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 3.0 and later will support it natively).&lt;br /&gt;
** If the player application uses a 3rd party media player implementing its own HLS, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.&lt;br /&gt;
&lt;br /&gt;
Once SDK is downloaded ensure to unzip the Nielsen SDK and copy the AppSdk.jar in your app (Android Studio) libs folder, then right click the AppSdk.jar and select '''Add As Library'''.&lt;br /&gt;
Ensure the AppSdk.jar file is added in 'build.grade (App Level) file.&lt;br /&gt;
* App SDK 1.2 provides support for x86, mips, and armeabi-7a architecture.&lt;br /&gt;
&lt;br /&gt;
==== Google Play Services ====&lt;br /&gt;
Add the Google Play Services in the project,&lt;br /&gt;
Steps: Android Studio -&amp;gt; File -&amp;gt; Project Structure -&amp;gt;(In module selection) select App -&amp;gt; Dependencies (tab) -&amp;gt; Click &amp;quot;+&amp;quot; button and search for &amp;lt;code&amp;gt;&amp;quot;*play-services*&amp;quot;&amp;lt;/code&amp;gt;.  Then select the most recent version of the [https://developers.google.com/admob/android/quick-start play-services Artifact].&lt;br /&gt;
Ensure it is added in build.gradle (App level) file&lt;br /&gt;
&lt;br /&gt;
==== Manifest File ==== &lt;br /&gt;
* Add the following permissions on the project’s ''AndroidManifest.xml'' file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more details to handle runtime permissions in Android versions, please visit [https://developer.android.com/training/permissions/requesting.html].   &lt;br /&gt;
&lt;br /&gt;
* In &amp;lt;code&amp;gt;AndroidManifest.xml &amp;lt;/code&amp;gt;under &amp;lt;application&amp;gt; node add the following metadata&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;manifest&amp;gt;&lt;br /&gt;
    &amp;lt;application&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 --&amp;gt;&lt;br /&gt;
        &amp;lt;meta-data&lt;br /&gt;
            android:name=&amp;quot;com.google.android.gms.ads.APPLICATION_ID&amp;quot;&lt;br /&gt;
            android:value=&amp;quot;ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/application&amp;gt;&lt;br /&gt;
&amp;lt;/manifest&amp;gt;&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* App SDK checks to see if there is a Google service available and updated.&lt;br /&gt;
* If not available or updated, App SDK will not use this service when executing its functions and will make reference to missing imports and the app will not be compiled.&lt;br /&gt;
&lt;br /&gt;
==== Library ====&lt;br /&gt;
Nielsen App SDK uses the following packages/classes from the [https://developers.google.com/android/guides/setup Google Play service].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;coffeescript&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
  implementation 'com.google.android.gms:play-services-ads:xx.x.x'&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Classes/package ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;&lt;br /&gt;
import com.google.android.gms.common.ConnectionResult;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesUtil;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesRepairableException;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SDK Initialization ==&lt;br /&gt;
The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object, which can be used simultaneously without any issue. The sharedInstance API that creates a singleton object was deprecated prior to version 5.1.1. (Version 4.0 for Android)&lt;br /&gt;
&lt;br /&gt;
The following table contains the list of arguments that can be passed via the AppInfo JSON schema.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter / Argument !! Description !! Source !! Required? !! Example&lt;br /&gt;
|-&lt;br /&gt;
| appid || Unique Nielsen ID for the application. The ID is a GUID data type. If you did not receive your App ID, let us know and we will provide you. || Nielsen-specified || Yes || PXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;br /&gt;
|-&lt;br /&gt;
| nol_devDebug || Enables Nielsen console logging. Only required for testing&lt;br /&gt;
|| Nielsen-specified || Optional || &amp;quot;DEBUG&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debug flag for development environment ==&lt;br /&gt;
Player application developers / integrators can use Debug flag to check whether an App SDK API call made is successful. To activate the Debug flag,&lt;br /&gt;
Pass the argument &amp;lt;code&amp;gt;@&amp;quot;nol_devDebug&amp;quot;:@&amp;quot;INFO&amp;quot;&amp;lt;/code&amp;gt;, in the JSON string . The permitted values are:&lt;br /&gt;
&lt;br /&gt;
* '''INFO''': Displays the API calls and the input data from the application (validate player name, app ID, etc.). It can be used as certification Aid.&lt;br /&gt;
* '''WARN''': Indicates potential integration / configuration errors or SDK issues.&lt;br /&gt;
* '''ERROR''': Indicates important integration errors or non-recoverable SDK issues.&lt;br /&gt;
* '''DEBUG''': Debug logs, used by the developers to debug more complex issues.&lt;br /&gt;
&lt;br /&gt;
Once the flag is active, it logs each API call made and the data passed. The log created by this flag is minimal.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': DO NOT activate the Debug flag in a production environment.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Sample SDK Initialization Code ====&lt;br /&gt;
[[AppSDK()]] is no longer a singleton object and should be initialized as below.&lt;br /&gt;
&lt;br /&gt;
'''Initialization of App SDK object through a JSON object'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;try&lt;br /&gt;
{&lt;br /&gt;
  // Prepare AppSdk configuration object (JSONObject)&lt;br /&gt;
  JSONObject appSdkConfig = new JSONObject()&lt;br /&gt;
          .put(&amp;quot;appid&amp;quot;, &amp;quot;PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA&amp;quot;)&lt;br /&gt;
          .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;); // only for debug builds&lt;br /&gt;
&lt;br /&gt;
// Pass appSdkConfig to the AppSdk constructor&lt;br /&gt;
mAppSdk = new AppSdk(appContext, appSdkConfig, appSdkListener);&lt;br /&gt;
}&lt;br /&gt;
catch (JSONException e)&lt;br /&gt;
{&lt;br /&gt;
  Log.e(TAG, &amp;quot;Couldn’t prepare JSONObject for appSdkConfig&amp;quot;, e);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, &amp;lt;code&amp;gt;appContext&amp;lt;/code&amp;gt; is the App context object and &amp;lt;code&amp;gt;appSdkConfig&amp;lt;/code&amp;gt; is JSON object for holding the parameters (&amp;lt;code&amp;gt;appid&amp;lt;/code&amp;gt;) the App passes to the Nielsen App SDK via a JSON string. The appid is obtained from Nielsen operational support and is unique to the app.&lt;br /&gt;
&lt;br /&gt;
The integration of Nielsen App SDK will depend on type of client app.&amp;lt;br /&amp;gt;&lt;br /&gt;
* Ensure that SDK files (AppSdk.jar and libAppSdk.so [App SDK 1.2 Only]) are included under the App’s project and the App SDK is linked to the App (the setting to link App SDK to the App can be found on property page of the App’s project).&lt;br /&gt;
&lt;br /&gt;
== APP SDK Error &amp;amp; Event Codes ==&lt;br /&gt;
To view the Error and Event codes for iOS and Android, please review the [[APP SDK Event Codes|App SDK Event Code]] Reference page.&lt;br /&gt;
&lt;br /&gt;
== Configure Payload ==&lt;br /&gt;
=== Handling JSON Metadata ===&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Variable Names like appid, appname, sfcode, dataSrc, title, type etc. are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
JSONObject contentMetadata = new JSONObject()&lt;br /&gt;
//SDK Metadata&lt;br /&gt;
    .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;assetid&amp;quot;, &amp;quot;vid345-67483&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;title&amp;quot;, &amp;quot;Program S3, EP1&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;isfullepisode&amp;quot;, &amp;quot;y&amp;quot;) &lt;br /&gt;
    .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentValueB&amp;quot;)  //optional&lt;br /&gt;
    .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentValueC&amp;quot;)  //optional   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Content metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Example Ad Object ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sequence of Calls ==&lt;br /&gt;
=== play ===&lt;br /&gt;
Use [[DCR_Video_APP_SDK#play|play]] to pass the channel descriptor information through channelName parameter when the user taps the '''Play''' button on the player.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    public void play(JSONObject channelInfo);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== loadMetadata ===&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void loadMetadata(JSONObject contentMetadata);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== playheadPosition ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void setPlayheadPosition(long position)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stop ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void stop()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== end ===&lt;br /&gt;
When content stop is initiated and content cannot be resumed from the same position (it can only be restarted from the beginning of stream).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void end()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;[nielsenMeter play];&amp;lt;/code&amp;gt; || // call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[nielsenMeter loadMetadata: contentMetadataObject];&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;[nielsenMeter setplayheadPosition: position];&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;[nielsenMeter end];&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the Unix timestamp; for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Initial state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''setplayheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position timer is fired.  If a LIVE event, use the current Unix timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the playback is paused, switches between content and ad (within the same content playback) or encounters interruptions.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.&lt;br /&gt;
## Initialization fails&lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop()]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- &lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] &lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad-123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
'''Ad Content'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    long pos = mAdPlayer.videoPosition() / 1000;&lt;br /&gt;
   if (mAppSdk != null)&lt;br /&gt;
   {&lt;br /&gt;
     mAppSdk.setPlayheadPosition(pos);&lt;br /&gt;
   }&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: The playhead positions for ad and content should be maintained separately.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
|  rowspan=&amp;quot;1&amp;quot; | End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should reset or begin from 0 at ad start. When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handling Foreground and Background states ==&lt;br /&gt;
There are a few approaches to managing the Foreground and Background states of an app available to use for state measurement.&lt;br /&gt;
* Utilizing the Androidx LifeCycleObserver (The recommended approach starting sdk version 7.1.0.0+)&lt;br /&gt;
* Utilizing the [[DCR_Video_Android_SDK#The_SdkBgFgDetectionUtility_class|SdkBgFgDetectionUtility]] class&lt;br /&gt;
* Adding a tag to the Manifest XML&lt;br /&gt;
* Manual Management&lt;br /&gt;
=== The LifeCycleObserver ===&lt;br /&gt;
AndroidX replaces the original support library APIs with packages in the androidx namespace, and Android Studio 3.2 and higher provides an automated migration tool. (Select '''Refactor&amp;gt; Migrate to AndroidX''' from the menu bar.)&lt;br /&gt;
&lt;br /&gt;
Starting with version 7.1.0, with AndroidX support, an additional utility is provided in the AppSDK - application background/foreground state detection by the AppSdk leveraging the Android Architecture component &amp;quot;LifeCycleObserver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The AppSdk is now capable of detecting the application UI visibility state transitions between background and foreground, without forcing the applications to register for AppSdk's AppSdkApplication class, which is responsible for handling the detection of application background/foreground state transitions at present.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Please note, that if you already have an app designed that utilizes the depreciated SdkBgFgDetectionUtility Class, the AppSDK will ignore any calls to these methods if it can utilize the LifeCycleObserver.  LifeCycleObserver based auto detection will take precedence. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
==== Adding the AndroidX dependency ====&lt;br /&gt;
In order to make use of the app background/foreground state transition auto detection feature of AndroidX AppSdk, the app gradle file needs the androidx dependency. The AppSdk API calls - &amp;lt;code&amp;gt;appInForeground()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;appInBackground()&amp;lt;/code&amp;gt;  will still be respected by AppSdk by executing the old AppSdk flow of handling &amp;quot;app in foreground&amp;quot; and &amp;quot;app in background&amp;quot; states as is.&lt;br /&gt;
&lt;br /&gt;
==== Using the LifeCycle Extension ====&lt;br /&gt;
The following androidx dependency is required in the app gradle file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
implementation &amp;quot;androidx.lifecycle:lifecycle-extensions:2.1.0&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
If you would like to take advantage of this auto detection feature of AppSdk at the very initial stage (e.g. splash screen or at of app launch time), before the AppSdk is initialized, can do so by calling the following newly introduced AppSdk public api, passing the application context :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void registerLifeCycleObserver(Context applicationContext)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Log messages for the new auto detection ====&lt;br /&gt;
&lt;br /&gt;
When the AppSdk app successfully registers for the LifeCycleObserver : &amp;lt;code&amp;gt;Registered LifeCycleObserver for App Background/Foreground auto-detection&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When the app enters the foreground state :&amp;lt;code&amp;gt;App is in foreground, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the app enters the background state :&amp;lt;code&amp;gt;App is in background, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the client app doesn't have the &amp;quot;androidx&amp;quot; gradle dependency and AppSdk fails to register LifeCycleObserver :&amp;lt;code&amp;gt;AndroidX LifecycleObserver can not be observed. Please use androidx dependency to activate SDK auto-detection of app background/foreground state.&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInForeground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - foreground&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInBackground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - background&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The SdkBgFgDetectionUtility class ===&lt;br /&gt;
Foreground/Background state measurement is a requirement of Nielsen AppSDK implementation which is especially crucial for static measurement. It may be implemented in multiple ways for Android. This includes&lt;br /&gt;
* Enable the Nielsen SDK to measure background/foreground state by makingthe relevant update to the AndroidManifest.&lt;br /&gt;
* Integrate Nielsen’s SdkBgFgDetectionUtility class within your Custom Application Class.&lt;br /&gt;
* Custom implementation of the required methods within your application.&lt;br /&gt;
&lt;br /&gt;
==== ForeGround/Background Measurement via AndroidManifest ====&lt;br /&gt;
The simplest way to measure the app background/foreground state is to add the following application tag to the Manifest XML. Integrating this into the Manifest XML will enable the SDK to measure app state directly. This approach is supported for Android 4.0 and up only; it requires that the application class is not in use for some other purpose.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;application android:name=&amp;quot;com.nielsen.app.sdk.AppSdkApplication&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using the Android SdkBgFbDetectionUtility Class ====&lt;br /&gt;
For developers who are already using the application class, it is recommended that background/foreground state is implemented using the  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class].  The  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] is compatible with Android 4+ and has been made available to Nielsen clients. (You will need to copy/paste the code provided into a file).&lt;br /&gt;
&lt;br /&gt;
==== Manual Background/ForeGround State Management ====&lt;br /&gt;
In cases where the developer is not able to use the AndroidManifest.xml solution nor the Nielsen provided   [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] the developer will need to manually identify the change of state through the application and call the respective API (appInForeground() or appInBackground()) to inform the SDK regarding the change of state from background to foreground or foreground to background.&lt;br /&gt;
&lt;br /&gt;
The SDK is informed about app state using the below methods.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
AppLaunchMeasurementManager.appInForeground(getApplicationContext());&lt;br /&gt;
AppLaunchMeasurementManager.appInBackground(getApplicationContext());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Within the lifecycle of individual activities, onResume() and onPause() are best suited to providing indication of the app state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Correct measurement of the foreground/background state is crucial to Static App measurement within Nielsen Digital Content Ratings (DCR).&lt;br /&gt;
== Using the NielsenAppSDKJSHandler ==&lt;br /&gt;
There could be a scenario in which a browser page, that is already tagged with the Nielsen BSDK, needs to be loaded via a webview.  In this situation it is recommended to use the '''NielsenAppSDKJSHandler''' which will allow communication between the AppSDK and the BSDK. &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''This feature is supported in versions 7.2 and above.'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
* Make sure you have the latest AppSdk.jar from Nielsen&lt;br /&gt;
* Enable the javascript on webview using below lines&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
 &amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
WebSettings webSetting = webView.getSettings();&lt;br /&gt;
webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Add  NielsenAppSDKJSHandler instance as javascript interface to webview with name “NielsenAppSDK” like below snippet&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext()), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This will enable listening to BSDK api calls within the APPSDK.  Please make sure your Technical Account Manager is aware that you wish to implement this method so a configuration file can be modified on the Nielsen servers; however, there are '''no changes required to the Browser page'''.&lt;br /&gt;
&lt;br /&gt;
==== Example:====&lt;br /&gt;
The below is an example of opening a webview with the NielsenAppSDKJSHandler&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
      WebSettings webSetting = webView.getSettings();&lt;br /&gt;
      webView.getSettings().setDomStorageEnabled(true); &lt;br /&gt;
      webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
      webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
      String url = &amp;quot;https://nielsen.com.index.htm&amp;quot;;&lt;br /&gt;
      webView.loadUrl(url);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;AndroidManifest.xml&amp;lt;/code&amp;gt; may need the following permissions set:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Closing NielsenAppSDKJSHandler ===&lt;br /&gt;
NielsenAppSDKJSHandler should be closed or cleaned up in below scenarios&lt;br /&gt;
* Before WebView is getting destructed&lt;br /&gt;
* Before loading new page&lt;br /&gt;
* Before closing application&lt;br /&gt;
NielsenAppSDKJSHandler provides a public interface with name &amp;quot;close()&amp;quot; and this function should be called on NielsenAppSDKJSHandler's instance in all above scenarios.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
// get your webview&lt;br /&gt;
WebView webView = findViewById(R.id.webView);&lt;br /&gt;
 &lt;br /&gt;
//Added JS Handler instance as java script interface for ggpm api type&lt;br /&gt;
NielsenAppSDKJSHandler jshandler = new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;);&lt;br /&gt;
webView.addJavascriptInterface(jshandler, &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
//Close JS Handler before making webview as null&lt;br /&gt;
jshandler.close();&lt;br /&gt;
webView = null;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interruptions during playback ==&lt;br /&gt;
As part of integrating Nielsen App SDK with the player application, the Video app developer needs to handle the following possible interruption scenarios:&lt;br /&gt;
* Pause / Play&lt;br /&gt;
* Network Loss (Wi-Fi / Airplane / Cellular)&lt;br /&gt;
* Call Interrupt (SIM or Third party Skype / Hangout call)&lt;br /&gt;
* Alarm Interrupt&lt;br /&gt;
* Content Buffering&lt;br /&gt;
* Device Lock / Unlock &lt;br /&gt;
* App going in the Background/Foreground&lt;br /&gt;
* Channel / Station Change Scenario&lt;br /&gt;
* Unplugging of headphone&lt;br /&gt;
In case of encountering one of the above interruptions, the player application needs to&lt;br /&gt;
* Call [[stop()]] immediately (except when content is buffering) and withhold sending playhead position.&lt;br /&gt;
* Start sending pings – &amp;lt;code&amp;gt;'loadMetadata'&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'playheadPosition'&amp;lt;/code&amp;gt; for the new viewing session, once the playback resumes.&lt;br /&gt;
Please see the [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Interruption_Scenarios Interruption Scenarios Page] for more details&lt;br /&gt;
&lt;br /&gt;
== Pre-Certification Checklists ==&lt;br /&gt;
After the application is ready to be sent for Nielsen Certification, please go through the [[Digital Pre-Certification Checklist App SDK]] and ensure the app behaves as expected, before submitting to Nielsen.&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK:&lt;br /&gt;
# '''[[#Global_Android_SDK_Opt-out|Global Android SDK Opt-out]]''' - managed by ''Opt out of Ads Personalization'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without Google Play Services or when using the noAd version of the SDK.&lt;br /&gt;
# '''[[#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Global Android SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen Android when the [https://developers.google.com/android/guides/setup Google Play services APIs] have been setup in your project.&lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the Android's '''Opt out of Ads Personalization''' setting. The user is opted out of demographic measurement if the OS-level '''Opt out of Ads Personalization''' setting is ''enabled''. As a publisher, you cannot override this setting.&lt;br /&gt;
&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global Android SDK, this optOutURL informs the user how to deactivate/activate “Out of Ads Personalization”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;'''Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/ for more information'''&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No Ad Framework Optout ===&lt;br /&gt;
The ''No Ad Framework Optout'' can be used when the host application does not leverage Google Play Services such as when using the noAd version or the NoID version.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Nielsen Android SDK 5.1.1.18 and above will check for ''OS-level opt-out'' first, if available. The user will be opted out if indicated at the OS-level '''OR''' the App-level.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The No Ad Framework Optout method works as follows: ====&lt;br /&gt;
* Get the current Nielsen opt-out URL via [[userOptOutURLString()]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[userOptOutURLString()]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut()]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No ID Optout (Kids_Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the NoID version of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OptOut Example Code ==&lt;br /&gt;
Below you will find some sample code for the:&lt;br /&gt;
* [[#Global OptOut Example|Global Android SDK]] - managed by Opt out of Ads Personalization setting on device '''(preferred approach)'''.&lt;br /&gt;
* [[#No_Ad_Framework_Optout_Sample_Code|Global Android noAd Framework]] - Use if Google Play APIs are unavailable or running noAd version.&lt;br /&gt;
*  It is currently not required to display an OptOut page for the NoID/Kids Build of the SDK.&lt;br /&gt;
===&amp;lt;span id=&amp;quot;Global OptOut Example&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Global OptOut Example ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user.  Please see the next section if using the No Ad Framework build&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;span id=&amp;quot;No Ad Framework Optout Sample Code&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;No Ad Framework Optout Sample Code ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user with the No Ad Framework SDK Build.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
            @Override&lt;br /&gt;
            public boolean shouldOverrideUrlLoading(WebView view, String url) {&lt;br /&gt;
&lt;br /&gt;
                if(url.contains(&amp;quot;nielsen&amp;quot;)){&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://1 it means the user selected Opt Out&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://0&amp;quot; it means the user selected Opt-In&lt;br /&gt;
                    appSdk.userOptOut(url);&lt;br /&gt;
                }&lt;br /&gt;
                return true;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Required Privacy Links ===&lt;br /&gt;
Users must either have access to the &amp;quot;About Nielsen Measurement&amp;quot; page, or have similar text available within the native app. Include &amp;quot;About Nielsen Measurement&amp;quot; and &amp;quot;Your Choices&amp;quot; link in the Privacy Policy / EULA or as a button near the link to the app's Privacy Policy.&lt;br /&gt;
&lt;br /&gt;
In addition, the following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
'''&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;'''&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via App-level Opt-out, the current Opt-Out status as detected by the SDK is available via the [[getOptOutStatus()]] property in the Nielsen Android SDK API. &amp;lt;code&amp;gt;appSdk.getOptOutStatus()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
Following Nielsen testing, you will need to:&lt;br /&gt;
&lt;br /&gt;
# '''Disable Debug Logging''': Disable logging by deleting &amp;lt;code&amp;gt;{nol_devDebug: 'DEBUG'}&amp;lt;/code&amp;gt; from initialization call.&lt;br /&gt;
# '''Notify Nielsen''': Once you are ready to go live, let us know so we can enable you for reporting. We will not be able to collect or report data prior to receiving notification from you.&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen  API using a standard no-frills player.&lt;br /&gt;
** [[Android Basic example|Android Studio Example]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen API integrated into a custom video player is bundled with the SDK.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_iOS_SDK&amp;diff=5511</id>
		<title>DCR Thailand Video iOS SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_iOS_SDK&amp;diff=5511"/>
		<updated>2021-11-24T05:50:15Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}} {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
This guide covers implementation steps for iOS using Xcode utilizing the Standard Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{{iOS_SpecialNotes_for_iOS14}}&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[iOS SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
Version 8 of the Nielsen App SDK will come in three versions. One that is enabled to work with the App Tracking Transparency Framework, another version that does not use the Ad Framework, and a version for Kids Apps or where noID is required. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by the [https://developer.apple.com/documentation/apptrackingtransparency AppTrackingTransparency framework] . '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will attempt to collect the IDFA (Id for Advertisers) on the device.&amp;lt;br&amp;gt; * For iOS14+, if the value returned is &amp;lt;code&amp;gt;ATTrackingManager.AuthorizationStatus.authorized&amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;*  If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested.&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the IDFA, so it will attempt to retrieve the '''IDFV'''.&amp;lt;br /&amp;gt;* The [https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor ID for Vendors (IDFV)], may be used for analytics across apps from the same content provider.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Thailand_Video_iOS_SDK#Global_iOS_SDK_No_Ad_Framework_Optout|Privacy Section]].&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Thailand_Video_iOS_SDK#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
=== How to obtain the NielsenAppApi.Framework ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of CocoaPods. We recommend using the CocoaPods-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_iOS_Artifactory_Guide|Select to obtain CocoaPods implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
* [[DCR_Video_iOS_SDK_xcframework|Using the XCFramework bundle]]&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
Prior to SDK Version 6.2.0.0 the  IOS framework has been distributed as a static library packaged into framework bundle format. Apple recommends to use dynamic framework, it has some benefits over static libraries like less executable file size of an app, faster startup time and native support in xCode IDE. Nielsen AppSDK has been transformed into dynamic framework in this release ([[iOS_Static_Framework_Setup|static framework]] is still available).&lt;br /&gt;
&lt;br /&gt;
If migrating from the static library to this new dynamic framework, once implemented, unless your specific application requires, you can remove the following Frameworks that were once required:&amp;lt;code&amp;gt; [AdSupport, JavascriptCore, SystemConfiguration, Security, AVFoundation, libc++] &amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''Dynamic framework''' is created as a fat framework. It means that it contains slices required for devices (armv7, arm64) as well as slices required for simulators (i386, x86_64). Simulator slices are needed to let clients build and debug their app on the simulators, but they should be removed before sending the app to the AppStore. The example of the shell script that should be added as a Run Script phase in the application can be [[DCR_Thailand_Video_iOS_SDK#Removing_Simulators_.28Dynamic_Framework_Only.29|found below]].&lt;br /&gt;
&lt;br /&gt;
'''[[DCR_Video_iOS_SDK_xcframework|XCFramework]]''' is solution for the problems described above Apple recommends to use XCFrameworks. In XCFramework, we no longer build a single framework with multiple architectures. Instead, we build one small framework for each combination of architecture and target and store it in its own folder. The top-level XCFramework folder have folders like ios-arm64, ios-arm64-simulator, etc. Each of these folders is its own framework, complete with headers, modules, and binary.&lt;br /&gt;
&lt;br /&gt;
=== Configuring Xcode Development Environment ===&lt;br /&gt;
Starting with SDK version 6.0.0.0, the Nielsen App SDK is compatible with Apple iOS versions 8.0 and above.  In addition, when using the dynamic framework,  all the required frameworks are linked automatically as the are needed.  More details can be found here: https://stackoverflow.com/questions/24902787/dont-we-need-to-link-framework-to-xcode-project-anymore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': All communications between the SDK and the Census (Collection Facility) use HTTPS.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Download Framework ===&lt;br /&gt;
The first step is to download and copy the [[Special:Downloads|NielsenAppApi.framework]] bundle to the app project directory. (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Framework ===&lt;br /&gt;
In the General tab for app configuration add NielsenAppApi.framework in the list of Embedded Binaries.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Path ===&lt;br /&gt;
Add path to the NielsenAppApi.framework in the Framework Search Paths build setting.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Import Framework ===&lt;br /&gt;
Add NielsenAppApi.framework module in the source file of your app:&lt;br /&gt;
&lt;br /&gt;
==== Using Swift ====&lt;br /&gt;
Add the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using Objective-C ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@import NielsenAppApi;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_SDK_Initialization}}&lt;br /&gt;
&lt;br /&gt;
== Configure Metadata ==&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Nielsen Key names (e.g. appid, program) are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Create channelName Metadata ===&lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| Any string representing the channel/stream	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
=== Create Content Metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
&amp;lt;blockquote&amp;gt; program and title metadata values should be passed to SDK as UTF-8 strings. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Metadata Example ====&lt;br /&gt;
&amp;lt;code&amp;gt;Swift&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
let contentMetadata = [&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
    &amp;quot;assetid&amp;quot;: &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Program S2, E3&amp;quot;,&lt;br /&gt;
    &amp;quot;isfullepisode&amp;quot;: &amp;quot;y&amp;quot;,&lt;br /&gt;
    &amp;quot;program&amp;quot;: &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
    &amp;quot;adloadtype&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
    &amp;quot;segB&amp;quot;: &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    &amp;quot;segC&amp;quot;: &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Objective-C&amp;lt;/code&amp;gt;    &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt; &lt;br /&gt;
NSDictionary * contentMetadata = @ {&lt;br /&gt;
    @ &amp;quot;type&amp;quot;: @ &amp;quot;content&amp;quot;,&lt;br /&gt;
    @ &amp;quot;assetid&amp;quot;: @ &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    @ &amp;quot;title&amp;quot;: @ &amp;quot;S2,E3&amp;quot;,&lt;br /&gt;
    @ &amp;quot;isfullepisode&amp;quot;: @ &amp;quot;y&amp;quot;,  &lt;br /&gt;
    @ &amp;quot;program&amp;quot;: @ &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    @ &amp;quot;length&amp;quot;: @ &amp;quot;3600&amp;quot;,&lt;br /&gt;
    @ &amp;quot;adloadtype&amp;quot;: @ &amp;quot;2&amp;quot;,&lt;br /&gt;
    @ &amp;quot;segB&amp;quot;: @ &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    @ &amp;quot;segC&amp;quot;: @ &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Configure metadata === &lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| ChannelInfo refers to the Channel name. This can be a free-form value&lt;br /&gt;
value such as a friendly name for the content being played. the SDK&amp;lt;br/&amp;gt;&lt;br /&gt;
will pass the application name automatically.&lt;br /&gt;
|| custom	|| No&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create Ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_LifeCycle_of_SDK}}&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&amp;lt;!--[[File:appsdkTimeline-DCR.png|icon|link=]]--&amp;gt;&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;nielsenMeter.play()&amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nielsenMeter.loadMetadata(contentMetadata)&amp;lt;/code&amp;gt; || // MetadataObject contains the JSON metadata&amp;lt;br&amp;gt; for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;nielsenMeter.playheadPosition(pos);&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead &amp;lt;br&amp;gt;while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;nielsenMeter.end()&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'playheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current UNIX timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'PlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the UNIX timestamp, for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Idle state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for an event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position is active.  If a LIVE event, use the current UNIX timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the content or Ad playback is interrupted and at the end of each Ad. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, call &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should begin from 0 at ad start.  When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Sequence_of_Calls}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Foreground_and_Background}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Interuptions_during_Playback}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_NielsenAppSDKJSHandler}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_PreCertification_Checklists}}&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK: &lt;br /&gt;
# '''[[#Global_iOS_SDK_Opt-out|Global iOS SDK Opt-out]]''' - managed by ''AppTracking'' or ''Limit Ad Tracking'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_Ad_Framework_Optout|Global iOS SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without the Ad Framework&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Global iOS SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen iOS &lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the iOS's '''Limit Ad Tracking''' or '''AppTracking''' setting. &lt;br /&gt;
*  If the User's device is running &amp;lt; iOS 13.x, the Nielsen SDK will check the status of '''Limit Ad Tracking'''.&lt;br /&gt;
*  iOS14 modifies the way Apple manages the collection of a User's Opt-In status through '''AppTracking'''. Starting with Version 8.x+, the Nielsen App SDK will check the iOS version during initialization. If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested. If iOS14.x +, then AppTracking is utilized.&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global iOS SDK, this optOutURL informs the user how to deactivate/activate “App Tracking/Limit Ad Tracking”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No Ad Framework Optout ===&lt;br /&gt;
The ''User Choice'' method can be used without the Ad Framework, or in situations where the publisher does not wish to use the [https://developer.apple.com/documentation/apptrackingtransparency App Tracking Transparency Framework]. As this flavor of the Nielsen SDK does not use the Ad Framework, so it is necessary to display an Optout Page to the userand capture their selection.&lt;br /&gt;
&lt;br /&gt;
Similar to the Global iOS SDK Flavor, it is a requirement to display a WebView element whose loadUrl is set to the&lt;br /&gt;
value obtained from optOutURL. This is a special URL that indicates Opt-in, or Opt-out and close the WebView.&lt;br /&gt;
&lt;br /&gt;
==== This opt-out method works as follows: ====&lt;br /&gt;
* Get the Nielsen opt-out URL via [[optOutURL]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[optOutURL]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No ID Optout (Kids Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the [https://nielsendownloads-green.digitalengsdk.com/digital/Nielsen-iOS-App-SDK-GlobalNoId_latest.zip NoID version] of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Opt-out example code ==&lt;br /&gt;
===== Swift =====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
import WebKit&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&lt;br /&gt;
class OptOutVC: UIViewController, NielsenAppApiDelegate, WKNavigationDelegate {&lt;br /&gt;
    var nielsenApi : NielsenAppApi!&lt;br /&gt;
    var webView: WKWebView!&lt;br /&gt;
   &lt;br /&gt;
    override func loadView() {&lt;br /&gt;
        webView = WKWebView()&lt;br /&gt;
        webView.navigationDelegate = self&lt;br /&gt;
        view = webView&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
&lt;br /&gt;
        if let appApi = self.nielsenApi {&lt;br /&gt;
            //Getting the optPut URL from SDK&lt;br /&gt;
            if let url = URL(string: appApi.optOutURL) {&lt;br /&gt;
                webView.load(URLRequest(url: url))&lt;br /&gt;
                webView.allowsBackForwardNavigationGestures = true&lt;br /&gt;
            }}}&lt;br /&gt;
&lt;br /&gt;
        func closeOptOutView() {&lt;br /&gt;
            self.dismiss(animated: true, completion: nil)&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
// Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.  This will receive the user's selection&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*  &lt;br /&gt;
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: &lt;br /&gt;
@escaping (WKNavigationActionPolicy) -&amp;gt; Void) {&lt;br /&gt;
            print(navigationAction.request.url?.absoluteString as Any) //For debugging to check what is being passed from webpage.&lt;br /&gt;
            if navigationAction.request.url?.absoluteString == &amp;quot;nielsen://close&amp;quot; {&lt;br /&gt;
                closeOptOutView()&lt;br /&gt;
                decisionHandler(.cancel)&lt;br /&gt;
            } else {&lt;br /&gt;
                if let url = navigationAction.request.url?.absoluteString, url.hasPrefix(&amp;quot;nielsen&amp;quot;) {&lt;br /&gt;
                    nielsenApi?.userOptOut(url). //either nielsenappsdk://1 or nielsenappsdk://0&lt;br /&gt;
                    decisionHandler(.cancel)&lt;br /&gt;
                } else {&lt;br /&gt;
                    if navigationAction.navigationType == .linkActivated {&lt;br /&gt;
                        if let url = navigationAction.request.url?.absoluteString, url.hasSuffix(&amp;quot;#&amp;quot;) {&lt;br /&gt;
                            decisionHandler(.allow)&lt;br /&gt;
                        } else {&lt;br /&gt;
                            decisionHandler(.cancel)&lt;br /&gt;
                            webView.load(navigationAction.request)&lt;br /&gt;
                        }&lt;br /&gt;
                    } else {&lt;br /&gt;
                        decisionHandler(.allow)&lt;br /&gt;
                    }}}}&lt;br /&gt;
  */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===== Objective-C =====&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#import &amp;quot;OptOutVC.h&amp;quot;&lt;br /&gt;
#import &amp;quot;NielsenInit.h&amp;quot;&lt;br /&gt;
#import &amp;lt;NielsenAppApi/NielsenAppApi.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@interface OptOutVC ()&lt;br /&gt;
&lt;br /&gt;
@property (weak, nonatomic) IBOutlet UIWebView *webView;&lt;br /&gt;
@end&lt;br /&gt;
&lt;br /&gt;
@implementation OptOutVC&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
    //Getting the optPut URL from eventTracker&lt;br /&gt;
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL&lt;br /&gt;
 URLWithString:self.nielsenApi.optOutURL]]];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*     &lt;br /&gt;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction&lt;br /&gt;
 decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler&lt;br /&gt;
{&lt;br /&gt;
    if ([navigationAction.request.URL.absoluteString isEqualToString:kNielsenWebClose])&lt;br /&gt;
    {   [self performSelector:@selector(closeOptOutView) withObject:nil afterDelay:0];&lt;br /&gt;
        decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
     } else {&lt;br /&gt;
        if ([navigationAction.request.URL.absoluteString hasPrefix:@&amp;quot;nielsen&amp;quot;])&lt;br /&gt;
        {[self.nielsenAppApi userOptOut:navigationAction.request.URL.absoluteString];&lt;br /&gt;
            decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
        } else {&lt;br /&gt;
            if (navigationAction.navigationType == WKNavigationTypeLinkActivated) &lt;br /&gt;
            { if ([navigationAction.request.URL.absoluteString hasSuffix:@&amp;quot;#&amp;quot;]) &lt;br /&gt;
                      {decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
                } else {&lt;br /&gt;
                    decisionHandler(WKNavigationActionPolicyCancel);&lt;br /&gt;
                    [webView loadRequest:[NSURLRequest requestWithURL:navigationAction.request.URL]];&lt;br /&gt;
                }} else {&lt;br /&gt;
                 decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
            }}}&lt;br /&gt;
*/&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via User Choice Opt-out, the current Opt-Out status as detected by the SDK is available via the [[optOutStatus]] property in the Nielsen SDK API&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@property (readonly) BOOL optOutStatus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Airplay}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Going_Live}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Removing_Simulator_Slices}}&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the Simplified API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen Simplified API using a standard no-frills player.&lt;br /&gt;
** [[Swift Basic Sample|Swift 5.0 Sample]]&lt;br /&gt;
** [[Objective-c Basic example|Objective-C Sample]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen Simplified API integrated into a custom video player.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Browser_SDK&amp;diff=5510</id>
		<title>DCR Thailand Video Browser SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Thailand_Video_Browser_SDK&amp;diff=5510"/>
		<updated>2021-11-24T05:45:12Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The Browser SDK (BSDK) is the framework for website developers to integrate Nielsen Measurement into their media players. Nielsen SDKs are also equipped to measure static content and can track key life cycle events.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 30px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-&lt;br /&gt;
|| ☑ || '''App ID (apid)''' || Unique ID assigned to the player/site and configured by product. During initial implementation, a 'test' apid will be given. Once the implementation has been certified, a 'production' apid will then be generated and needs to be used before 'going live'. || Contact Nielsen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Configure SDK ==&lt;br /&gt;
There are two steps required for configuring the SDK:&lt;br /&gt;
*Add Static Queue Snippet&lt;br /&gt;
*Create SDK Instance&lt;br /&gt;
&lt;br /&gt;
=== Static Queue Snippet ===&lt;br /&gt;
The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the following script tag to the website:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Create SDK Instance===&lt;br /&gt;
To initialize the SDK, create an SDK instance by making the initialization call:&lt;br /&gt;
&lt;br /&gt;
==== Initialization API Call ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
NOLBUNDLE.nlsQ(&amp;quot;&amp;lt;apid&amp;gt;&amp;quot;, &amp;quot;&amp;lt;instanceName&amp;gt;&amp;quot;,{nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
When creating an instance, pass the following values: (&amp;lt;code&amp;gt;nol_sdkDebug&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;optout&amp;lt;/code&amp;gt; are optional)&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter	!! Description	!! Values&lt;br /&gt;
|-&lt;br /&gt;
| apid	|| Unique ID assigned to player/site ||	&lt;br /&gt;
'TXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Test Apid that starts with 'T'&amp;lt;br/&amp;gt;&lt;br /&gt;
'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Production Apid that starts with 'P'&lt;br /&gt;
|-&lt;br /&gt;
|instanceName ||	Name of SDK instance ||	&amp;quot;any string value&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| nol_sdkDebug	|| Enables Nielsen console logging if desired. 	|| &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{nol_sdkDebug: &amp;quot;debug&amp;quot;} &lt;br /&gt;
{nol_sdkDebug: &amp;quot;info&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;warn&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;true&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|optout || Optional: OptOut global parameter. || &amp;lt;code&amp;gt;1/0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;true/false&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example SDK Initialization ====&lt;br /&gt;
When the initialization call is made, a unique static configuration file, &amp;lt;apid&amp;gt;.js, will be downloaded based on the apid and will be cached on the user’s browser.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
    nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
    optout: &amp;quot;false&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.bundle.min.js”. More information on OptOut Parameter under [[DCR Thailand Video Browser SDK#Privacy_and_Opt-Out|Privacy and Opt-Out.]]&lt;br /&gt;
&lt;br /&gt;
=== Example SDK Configuration ===&lt;br /&gt;
&lt;br /&gt;
The configuration should include the Static Queue Snippet and an SDK Instance for an unique App ID as shown in the example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Add Static Queue Snippet&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
// Created SDK Instance&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/script&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create Metadata Objects ===&lt;br /&gt;
There are two types of asset metadata:&lt;br /&gt;
*content: identify video&lt;br /&gt;
*ad: identify each ad&lt;br /&gt;
&lt;br /&gt;
The metadata received for each asset is used for classification and reporting.&lt;br /&gt;
&lt;br /&gt;
Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.&lt;br /&gt;
&lt;br /&gt;
==== Content Metadata ====&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Content Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var contentMetadataObject =&lt;br /&gt;
{  &lt;br /&gt;
  type:           'content',&lt;br /&gt;
  assetid:        'VID-123456',&lt;br /&gt;
  program:        'program name',&lt;br /&gt;
  title:          'episode title',&lt;br /&gt;
  length:         'length in seconds',&lt;br /&gt;
  isfullepisode:  'y',&lt;br /&gt;
  adloadtype:     '2',&lt;br /&gt;
  segB:           'custom segment B', // optional&lt;br /&gt;
  segC:           'custom segment C', // optional&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var adMetadataObject = &lt;br /&gt;
{  &lt;br /&gt;
  type:    'preroll',&lt;br /&gt;
  assetid: 'AD-1'&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt; URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Call Nielsen APIs ====&lt;br /&gt;
The method for calling events is ggPM().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
nSdkInstance.ggPM('event', parameter, ...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt Scenarios ==&lt;br /&gt;
&lt;br /&gt;
=== Pause Event ===&lt;br /&gt;
The setPlayheadPostion event is used for handling pause. To indicate pause, stop passing the playhead position to the SDK. Once the content resumes, begin sending the playhead again with the correct playhead value.&lt;br /&gt;
&lt;br /&gt;
=== Other Interrupt Scenarios ===&lt;br /&gt;
The following possible browser interruption scenarios must be handled:&lt;br /&gt;
&lt;br /&gt;
* Browser/Tab close&lt;br /&gt;
* Leaving the page to another destination&lt;br /&gt;
* Pressing the stop button&lt;br /&gt;
* Network Loss&lt;br /&gt;
&lt;br /&gt;
There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener('beforeunload', function(event) &lt;br /&gt;
{&lt;br /&gt;
  // Only inside a midroll indicate &amp;lt;stop&amp;gt; for the ad&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
  &lt;br /&gt;
  // Indicate &amp;lt;end&amp;gt; and &amp;lt;stop&amp;gt; for the content&lt;br /&gt;
  nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position in seconds	|| Call when content or ads complete playing and pass playhead position&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SDK Playhead Event Sequence ==&lt;br /&gt;
The sample event lifecycles can be used as a reference for identifying the order for calling events.&lt;br /&gt;
&lt;br /&gt;
=== Content Playback ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// CONTENT PLAYS&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Content Playback with Ads ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// PREROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// MIDROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT RESUMES&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// POSTROLL&lt;br /&gt;
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.&lt;br /&gt;
&lt;br /&gt;
* For Ad Pods, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.&lt;br /&gt;
&lt;br /&gt;
* When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are two primary methods for implementing user Opt-out preferences:&lt;br /&gt;
# [[#User Opt Out|User Opt Out]] - Provide a link to the Nielsen Privacy Policy page when a User can make their selection&lt;br /&gt;
# [[#Initialization Opt Out|Initialization Opt Out]] - Global OptOut Parameter&lt;br /&gt;
&lt;br /&gt;
=== User Opt Out === &lt;br /&gt;
The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the User Opt-Out option, include the following two items in your privacy policy.&lt;br /&gt;
*A notice that the player (or page in relation to static measurement) includes proprietary measurement software that allows users to contribute to market research (such as Nielsen Content Ratings).&lt;br /&gt;
*A link to the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&lt;br /&gt;
On the Nielsen Digital Measurement Privacy Policy page, users can click Choices to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen online measurement, click a link to receive an opt-out cookie.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
* Once users have opted out via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=total&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/  link], their browser cookies will contain the value '''TOTAL_OPTOUT'''. This will prevent a redirect to our data provider from occurring&lt;br /&gt;
* Users can opt back in via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=cancel&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/ link].  When a user selects that link, their opt-out cookie will be deleted and they will be able to be measured moving forward.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The following paragraph is a template for a Privacy Statement.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research, such as Nielsen Digital Content Ratings. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/th/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== User Opt Back In ====&lt;br /&gt;
Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.&lt;br /&gt;
&lt;br /&gt;
=== Initialization Opt Out ===&lt;br /&gt;
The BSDK600 now supports the ability to optout on initialization of the SDK by allowing an optout global parameter to be passed.  This optout will be maintained through the session of the SDK instance. Specifications and limitations are specified below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type&lt;br /&gt;
! Supported Values&lt;br /&gt;
! Notes&lt;br /&gt;
! Optout&lt;br /&gt;
|-&lt;br /&gt;
||optout||True, Yes, or 1|| Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: true});&lt;br /&gt;
|| Ping parameter will set uoo=true.&lt;br /&gt;
|-&lt;br /&gt;
||optout|| False, No, or 0 || Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: false});&lt;br /&gt;
|| Ping parameter will set uoo to blank.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
==== Example of using OptOut ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
  nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
  optout: &amp;quot;true&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Opt Out Overview ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser Cookie&lt;br /&gt;
! uoo value in session ping&lt;br /&gt;
! Final Optout Status&lt;br /&gt;
|-&lt;br /&gt;
||Default Value || no uoo value or uoo=0|| Not Opted Out&lt;br /&gt;
|-&lt;br /&gt;
||Default Value ||  uoo=1 || Opted Out&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
After the integration has been certified, users will need to make a couple of updates to the initialization call to ensure that player will be measured properly. Ensure that a production apid (starting with 'P') is used after going live.&lt;br /&gt;
Disable debug logging by deleting {nol_sdkDebug: 'DEBUG'} from initialization call.&lt;br /&gt;
&lt;br /&gt;
'''Example Production Initialization Call'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, { optout: &amp;quot;false&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Browser_SDK&amp;diff=5498</id>
		<title>DCR Taiwan Video Browser SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Browser_SDK&amp;diff=5498"/>
		<updated>2021-11-10T05:20:21Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The Browser SDK (BSDK) is the framework for website developers to integrate Nielsen Measurement into their media players. Nielsen SDKs are also equipped to measure static content and can track key life cycle events.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 30px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-&lt;br /&gt;
|| ☑ || '''App ID (apid)''' || Unique ID assigned to the player/site and configured by product. During initial implementation, a 'test' apid will be given. Once the implementation has been certified, a 'production' apid will then be generated and needs to be used before 'going live'. || Contact Nielsen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Configure SDK ==&lt;br /&gt;
There are two steps required for configuring the SDK:&lt;br /&gt;
*Add Static Queue Snippet&lt;br /&gt;
*Create SDK Instance&lt;br /&gt;
&lt;br /&gt;
=== Static Queue Snippet ===&lt;br /&gt;
The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the following script tag to the website:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Create SDK Instance===&lt;br /&gt;
To initialize the SDK, create an SDK instance by making the initialization call:&lt;br /&gt;
&lt;br /&gt;
==== Initialization API Call ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
NOLBUNDLE.nlsQ(&amp;quot;&amp;lt;apid&amp;gt;&amp;quot;, &amp;quot;&amp;lt;instanceName&amp;gt;&amp;quot;,{nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
When creating an instance, pass the following values: (&amp;lt;code&amp;gt;nol_sdkDebug&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;optout&amp;lt;/code&amp;gt; are optional)&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter	!! Description	!! Values&lt;br /&gt;
|-&lt;br /&gt;
| apid	|| Unique ID assigned to player/site ||	&lt;br /&gt;
'TXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Test Apid that starts with 'T'&amp;lt;br/&amp;gt;&lt;br /&gt;
'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Production Apid that starts with 'P'&lt;br /&gt;
|-&lt;br /&gt;
|instanceName ||	Name of SDK instance ||	&amp;quot;any string value&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| nol_sdkDebug	|| Enables Nielsen console logging if desired. 	|| &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{nol_sdkDebug: &amp;quot;debug&amp;quot;} &lt;br /&gt;
{nol_sdkDebug: &amp;quot;info&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;warn&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;true&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|optout || Optional: OptOut global parameter. || &amp;lt;code&amp;gt;1/0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;true/false&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example SDK Initialization ====&lt;br /&gt;
When the initialization call is made, a unique static configuration file, &amp;lt;apid&amp;gt;.js, will be downloaded based on the apid and will be cached on the user’s browser.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
    nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
    optout: &amp;quot;false&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.bundle.min.js”. More information on OptOut Parameter under [[DCR Taiwan Video Browser SDK#Privacy_and_Opt-Out|Privacy and Opt-Out.]]&lt;br /&gt;
&lt;br /&gt;
=== Example SDK Configuration ===&lt;br /&gt;
&lt;br /&gt;
The configuration should include the Static Queue Snippet and an SDK Instance for an unique App ID as shown in the example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Add Static Queue Snippet&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
// Created SDK Instance&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/script&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create Metadata Objects ===&lt;br /&gt;
There are two types of asset metadata:&lt;br /&gt;
*content: identify video&lt;br /&gt;
*ad: identify each ad&lt;br /&gt;
&lt;br /&gt;
The metadata received for each asset is used for classification and reporting.&lt;br /&gt;
&lt;br /&gt;
Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.&lt;br /&gt;
&lt;br /&gt;
==== Content Metadata ====&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Content Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var contentMetadataObject =&lt;br /&gt;
{  &lt;br /&gt;
  type:           'content',&lt;br /&gt;
  assetid:        'VID-123456',&lt;br /&gt;
  program:        'program name',&lt;br /&gt;
  title:          'episode title',&lt;br /&gt;
  length:         'length in seconds',&lt;br /&gt;
  isfullepisode:  'y',&lt;br /&gt;
  adloadtype:     '2',&lt;br /&gt;
  segB:           'custom segment B', // optional&lt;br /&gt;
  segC:           'custom segment C', // optional&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var adMetadataObject = &lt;br /&gt;
{  &lt;br /&gt;
  type:    'preroll',&lt;br /&gt;
  assetid: 'AD-1'&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt; URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Call Nielsen APIs ====&lt;br /&gt;
The method for calling events is ggPM().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
nSdkInstance.ggPM('event', parameter, ...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt Scenarios ==&lt;br /&gt;
&lt;br /&gt;
=== Pause Event ===&lt;br /&gt;
The setPlayheadPostion event is used for handling pause. To indicate pause, stop passing the playhead position to the SDK. Once the content resumes, begin sending the playhead again with the correct playhead value.&lt;br /&gt;
&lt;br /&gt;
=== Other Interrupt Scenarios ===&lt;br /&gt;
The following possible browser interruption scenarios must be handled:&lt;br /&gt;
&lt;br /&gt;
* Browser/Tab close&lt;br /&gt;
* Leaving the page to another destination&lt;br /&gt;
* Pressing the stop button&lt;br /&gt;
* Network Loss&lt;br /&gt;
&lt;br /&gt;
There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener('beforeunload', function(event) &lt;br /&gt;
{&lt;br /&gt;
  // Only inside a midroll indicate &amp;lt;stop&amp;gt; for the ad&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
  &lt;br /&gt;
  // Indicate &amp;lt;end&amp;gt; and &amp;lt;stop&amp;gt; for the content&lt;br /&gt;
  nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position in seconds	|| Call when content or ads complete playing and pass playhead position&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SDK Playhead Event Sequence ==&lt;br /&gt;
The sample event lifecycles can be used as a reference for identifying the order for calling events.&lt;br /&gt;
&lt;br /&gt;
=== Content Playback ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// CONTENT PLAYS&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Content Playback with Ads ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// PREROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// MIDROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT RESUMES&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// POSTROLL&lt;br /&gt;
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.&lt;br /&gt;
&lt;br /&gt;
* For Ad Pods, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.&lt;br /&gt;
&lt;br /&gt;
* When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are two primary methods for implementing user Opt-out preferences:&lt;br /&gt;
# [[#User Opt Out|User Opt Out]] - Provide a link to the Nielsen Privacy Policy page when a User can make their selection&lt;br /&gt;
# [[#Initialization Opt Out|Initialization Opt Out]] - Global OptOut Parameter&lt;br /&gt;
&lt;br /&gt;
=== User Opt Out === &lt;br /&gt;
The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the User Opt-Out option, include the following two items in your privacy policy.&lt;br /&gt;
*A notice that the player (or page in relation to static measurement) includes proprietary measurement software that allows users to contribute to market research (such as Nielsen Content Ratings).&lt;br /&gt;
*A link to the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&lt;br /&gt;
On the Nielsen Digital Measurement Privacy Policy page, users can click Choices to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen online measurement, click a link to receive an opt-out cookie.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
* Once users have opted out via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=total&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/  link], their browser cookies will contain the value '''TOTAL_OPTOUT'''. This will prevent a redirect to our data provider from occurring&lt;br /&gt;
* Users can opt back in via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=cancel&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/ link].  When a user selects that link, their opt-out cookie will be deleted and they will be able to be measured moving forward.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The following paragraph is a template for a Privacy Statement.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research, such as Nielsen Digital Content Ratings. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== User Opt Back In ====&lt;br /&gt;
Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.&lt;br /&gt;
&lt;br /&gt;
=== Initialization Opt Out ===&lt;br /&gt;
The BSDK600 now supports the ability to optout on initialization of the SDK by allowing an optout global parameter to be passed.  This optout will be maintained through the session of the SDK instance. Specifications and limitations are specified below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type&lt;br /&gt;
! Supported Values&lt;br /&gt;
! Notes&lt;br /&gt;
! Optout&lt;br /&gt;
|-&lt;br /&gt;
||optout||True, Yes, or 1|| Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: true});&lt;br /&gt;
|| Ping parameter will set uoo=true.&lt;br /&gt;
|-&lt;br /&gt;
||optout|| False, No, or 0 || Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: false});&lt;br /&gt;
|| Ping parameter will set uoo to blank.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
==== Example of using OptOut ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
  nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
  optout: &amp;quot;true&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Opt Out Overview ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser Cookie&lt;br /&gt;
! uoo value in session ping&lt;br /&gt;
! Final Optout Status&lt;br /&gt;
|-&lt;br /&gt;
||Default Value || no uoo value or uoo=0|| Not Opted Out&lt;br /&gt;
|-&lt;br /&gt;
||Default Value ||  uoo=1 || Opted Out&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
After the integration has been certified, users will need to make a couple of updates to the initialization call to ensure that player will be measured properly. Ensure that a production apid (starting with 'P') is used after going live.&lt;br /&gt;
Disable debug logging by deleting {nol_sdkDebug: 'DEBUG'} from initialization call.&lt;br /&gt;
&lt;br /&gt;
'''Example Production Initialization Call'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, { optout: &amp;quot;false&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Android_SDK&amp;diff=5490</id>
		<title>DCR Taiwan Video Android SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Android_SDK&amp;diff=5490"/>
		<updated>2021-11-08T07:02:18Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[Android SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
This guide covers implementation steps for Android Studio utilizing the Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''Android Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by Opt out of Ads Personlization setting on device. '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will collect the [https://developer.android.com/training/articles/ad-id Google Advertising ID] unless the user Opts Out.&amp;lt;br&amp;gt;* If the Google Play Service is unavailable, (ie: Amazon and Huawei devices) the Nielsen sdk will secure the Android ID.&amp;lt;br&amp;gt; * There are 3 versions available starting with the Nielsen SDK 8.1.0.0.&lt;br /&gt;
|-&lt;br /&gt;
| '''Android No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the Google Advertising ID, so will retrieve the '''AndroidID'''.&amp;lt;br /&amp;gt;* The AndroidID is a 64-bit number (expressed as a hexadecimal string), unique to each combination of app-signing key, user and device.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Taiwan_Video_Android_SDK#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Opt-out]].&lt;br /&gt;
|-&lt;br /&gt;
| '''Android SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Taiwan_Video_Android_SDK#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== How to obtain the NielsenAppApi ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of Gradle. We recommend using the Gradle-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_Android_Artifactory_Guide|Select to obtain Gradle implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
&lt;br /&gt;
=== Configuring Android Development Environment ===&lt;br /&gt;
*The Nielsen App SDK (located in the [https://engineeringportal.nielsen.com/docs/Special:Downloads Downloads section] of the website) class is the primary application interface to the Nielsen App SDK on Android.&lt;br /&gt;
*The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.&lt;br /&gt;
*The Nielsen App SDK can also be added as a [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Android_Artifactory_Guide Artifact Repository]. If implemented this way, you do not need to download the appsdk from the Nielsen Portal.&lt;br /&gt;
&lt;br /&gt;
'''Nielsen App SDK is compatible with Android OS versions 2.3+. Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.'''&lt;br /&gt;
&lt;br /&gt;
The requirement for the Java ''AppSdk.jar'' library and the ''libAppSdk.so'' native library will depend on the type of host application that will make use of them.&lt;br /&gt;
* '''For Video player applications'''&lt;br /&gt;
** The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 3.0 and later will support it natively).&lt;br /&gt;
** If the player application uses a 3rd party media player implementing its own HLS, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.&lt;br /&gt;
&lt;br /&gt;
Once SDK is downloaded ensure to unzip the Nielsen SDK and copy the AppSdk.jar in your app (Android Studio) libs folder, then right click the AppSdk.jar and select '''Add As Library'''.&lt;br /&gt;
Ensure the AppSdk.jar file is added in 'build.grade (App Level) file.&lt;br /&gt;
* App SDK 1.2 provides support for x86, mips, and armeabi-7a architecture.&lt;br /&gt;
&lt;br /&gt;
==== Google Play Services ====&lt;br /&gt;
Add the Google Play Services in the project,&lt;br /&gt;
Steps: Android Studio -&amp;gt; File -&amp;gt; Project Structure -&amp;gt;(In module selection) select App -&amp;gt; Dependencies (tab) -&amp;gt; Click &amp;quot;+&amp;quot; button and search for &amp;lt;code&amp;gt;&amp;quot;*play-services*&amp;quot;&amp;lt;/code&amp;gt;.  Then select the most recent version of the [https://developers.google.com/admob/android/quick-start play-services Artifact].&lt;br /&gt;
Ensure it is added in build.gradle (App level) file&lt;br /&gt;
&lt;br /&gt;
==== Manifest File ==== &lt;br /&gt;
* Add the following permissions on the project’s ''AndroidManifest.xml'' file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more details to handle runtime permissions in Android versions, please visit [https://developer.android.com/training/permissions/requesting.html].   &lt;br /&gt;
&lt;br /&gt;
* In &amp;lt;code&amp;gt;AndroidManifest.xml &amp;lt;/code&amp;gt;under &amp;lt;application&amp;gt; node add the following metadata&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;manifest&amp;gt;&lt;br /&gt;
    &amp;lt;application&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 --&amp;gt;&lt;br /&gt;
        &amp;lt;meta-data&lt;br /&gt;
            android:name=&amp;quot;com.google.android.gms.ads.APPLICATION_ID&amp;quot;&lt;br /&gt;
            android:value=&amp;quot;ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/application&amp;gt;&lt;br /&gt;
&amp;lt;/manifest&amp;gt;&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* App SDK checks to see if there is a Google service available and updated.&lt;br /&gt;
* If not available or updated, App SDK will not use this service when executing its functions and will make reference to missing imports and the app will not be compiled.&lt;br /&gt;
&lt;br /&gt;
==== Library ====&lt;br /&gt;
Nielsen App SDK uses the following packages/classes from the [https://developers.google.com/android/guides/setup Google Play service].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;coffeescript&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
  implementation 'com.google.android.gms:play-services-ads:xx.x.x'&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Classes/package ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;&lt;br /&gt;
import com.google.android.gms.common.ConnectionResult;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesUtil;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesRepairableException;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SDK Initialization ==&lt;br /&gt;
The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object, which can be used simultaneously without any issue. The sharedInstance API that creates a singleton object was deprecated prior to version 5.1.1. (Version 4.0 for Android)&lt;br /&gt;
&lt;br /&gt;
The following table contains the list of arguments that can be passed via the AppInfo JSON schema.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter / Argument !! Description !! Source !! Required? !! Example&lt;br /&gt;
|-&lt;br /&gt;
| appid || Unique Nielsen ID for the application. The ID is a GUID data type. If you did not receive your App ID, let us know and we will provide you. || Nielsen-specified || Yes || PXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;br /&gt;
|-&lt;br /&gt;
| nol_devDebug || Enables Nielsen console logging. Only required for testing&lt;br /&gt;
|| Nielsen-specified || Optional || &amp;quot;DEBUG&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debug flag for development environment ==&lt;br /&gt;
Player application developers / integrators can use Debug flag to check whether an App SDK API call made is successful. To activate the Debug flag,&lt;br /&gt;
Pass the argument &amp;lt;code&amp;gt;@&amp;quot;nol_devDebug&amp;quot;:@&amp;quot;INFO&amp;quot;&amp;lt;/code&amp;gt;, in the JSON string . The permitted values are:&lt;br /&gt;
&lt;br /&gt;
* '''INFO''': Displays the API calls and the input data from the application (validate player name, app ID, etc.). It can be used as certification Aid.&lt;br /&gt;
* '''WARN''': Indicates potential integration / configuration errors or SDK issues.&lt;br /&gt;
* '''ERROR''': Indicates important integration errors or non-recoverable SDK issues.&lt;br /&gt;
* '''DEBUG''': Debug logs, used by the developers to debug more complex issues.&lt;br /&gt;
&lt;br /&gt;
Once the flag is active, it logs each API call made and the data passed. The log created by this flag is minimal.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': DO NOT activate the Debug flag in a production environment.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Sample SDK Initialization Code ====&lt;br /&gt;
[[AppSDK()]] is no longer a singleton object and should be initialized as below.&lt;br /&gt;
&lt;br /&gt;
'''Initialization of App SDK object through a JSON object'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;try&lt;br /&gt;
{&lt;br /&gt;
  // Prepare AppSdk configuration object (JSONObject)&lt;br /&gt;
  JSONObject appSdkConfig = new JSONObject()&lt;br /&gt;
          .put(&amp;quot;appid&amp;quot;, &amp;quot;PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA&amp;quot;)&lt;br /&gt;
          .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;); // only for debug builds&lt;br /&gt;
&lt;br /&gt;
// Pass appSdkConfig to the AppSdk constructor&lt;br /&gt;
mAppSdk = new AppSdk(appContext, appSdkConfig, appSdkListener);&lt;br /&gt;
}&lt;br /&gt;
catch (JSONException e)&lt;br /&gt;
{&lt;br /&gt;
  Log.e(TAG, &amp;quot;Couldn’t prepare JSONObject for appSdkConfig&amp;quot;, e);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, &amp;lt;code&amp;gt;appContext&amp;lt;/code&amp;gt; is the App context object and &amp;lt;code&amp;gt;appSdkConfig&amp;lt;/code&amp;gt; is JSON object for holding the parameters (&amp;lt;code&amp;gt;appid&amp;lt;/code&amp;gt;) the App passes to the Nielsen App SDK via a JSON string. The appid is obtained from Nielsen operational support and is unique to the app.&lt;br /&gt;
&lt;br /&gt;
The integration of Nielsen App SDK will depend on type of client app.&amp;lt;br /&amp;gt;&lt;br /&gt;
* Ensure that SDK files (AppSdk.jar and libAppSdk.so [App SDK 1.2 Only]) are included under the App’s project and the App SDK is linked to the App (the setting to link App SDK to the App can be found on property page of the App’s project).&lt;br /&gt;
&lt;br /&gt;
== APP SDK Error &amp;amp; Event Codes ==&lt;br /&gt;
To view the Error and Event codes for iOS and Android, please review the [[APP SDK Event Codes|App SDK Event Code]] Reference page.&lt;br /&gt;
&lt;br /&gt;
== Configure Payload ==&lt;br /&gt;
=== Handling JSON Metadata ===&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Variable Names like appid, appname, sfcode, dataSrc, title, type etc. are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
JSONObject contentMetadata = new JSONObject()&lt;br /&gt;
//SDK Metadata&lt;br /&gt;
    .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;assetid&amp;quot;, &amp;quot;vid345-67483&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;title&amp;quot;, &amp;quot;Program S3, EP1&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;isfullepisode&amp;quot;, &amp;quot;y&amp;quot;) &lt;br /&gt;
    .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentValueB&amp;quot;)  //optional&lt;br /&gt;
    .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentValueC&amp;quot;)  //optional   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Content metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Example Ad Object ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sequence of Calls ==&lt;br /&gt;
=== play ===&lt;br /&gt;
Use [[DCR_Video_APP_SDK#play|play]] to pass the channel descriptor information through channelName parameter when the user taps the '''Play''' button on the player.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    public void play(JSONObject channelInfo);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== loadMetadata ===&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void loadMetadata(JSONObject contentMetadata);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== playheadPosition ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void setPlayheadPosition(long position)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stop ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void stop()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== end ===&lt;br /&gt;
When content stop is initiated and content cannot be resumed from the same position (it can only be restarted from the beginning of stream).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void end()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;[nielsenMeter play];&amp;lt;/code&amp;gt; || // call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[nielsenMeter loadMetadata: contentMetadataObject];&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;[nielsenMeter setplayheadPosition: position];&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;[nielsenMeter end];&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the Unix timestamp; for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Initial state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''setplayheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position timer is fired.  If a LIVE event, use the current Unix timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the playback is paused, switches between content and ad (within the same content playback) or encounters interruptions.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.&lt;br /&gt;
## Initialization fails&lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop()]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- &lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] &lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad-123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
'''Ad Content'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    long pos = mAdPlayer.videoPosition() / 1000;&lt;br /&gt;
   if (mAppSdk != null)&lt;br /&gt;
   {&lt;br /&gt;
     mAppSdk.setPlayheadPosition(pos);&lt;br /&gt;
   }&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: The playhead positions for ad and content should be maintained separately.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
|  rowspan=&amp;quot;1&amp;quot; | End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should reset or begin from 0 at ad start. When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handling Foreground and Background states ==&lt;br /&gt;
There are a few approaches to managing the Foreground and Background states of an app available to use for state measurement.&lt;br /&gt;
* Utilizing the Androidx LifeCycleObserver (The recommended approach starting sdk version 7.1.0.0+)&lt;br /&gt;
* Utilizing the [[DCR_Video_Android_SDK#The_SdkBgFgDetectionUtility_class|SdkBgFgDetectionUtility]] class&lt;br /&gt;
* Adding a tag to the Manifest XML&lt;br /&gt;
* Manual Management&lt;br /&gt;
=== The LifeCycleObserver ===&lt;br /&gt;
AndroidX replaces the original support library APIs with packages in the androidx namespace, and Android Studio 3.2 and higher provides an automated migration tool. (Select '''Refactor&amp;gt; Migrate to AndroidX''' from the menu bar.)&lt;br /&gt;
&lt;br /&gt;
Starting with version 7.1.0, with AndroidX support, an additional utility is provided in the AppSDK - application background/foreground state detection by the AppSdk leveraging the Android Architecture component &amp;quot;LifeCycleObserver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The AppSdk is now capable of detecting the application UI visibility state transitions between background and foreground, without forcing the applications to register for AppSdk's AppSdkApplication class, which is responsible for handling the detection of application background/foreground state transitions at present.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Please note, that if you already have an app designed that utilizes the depreciated SdkBgFgDetectionUtility Class, the AppSDK will ignore any calls to these methods if it can utilize the LifeCycleObserver.  LifeCycleObserver based auto detection will take precedence. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
==== Adding the AndroidX dependency ====&lt;br /&gt;
In order to make use of the app background/foreground state transition auto detection feature of AndroidX AppSdk, the app gradle file needs the androidx dependency. The AppSdk API calls - &amp;lt;code&amp;gt;appInForeground()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;appInBackground()&amp;lt;/code&amp;gt;  will still be respected by AppSdk by executing the old AppSdk flow of handling &amp;quot;app in foreground&amp;quot; and &amp;quot;app in background&amp;quot; states as is.&lt;br /&gt;
&lt;br /&gt;
==== Using the LifeCycle Extension ====&lt;br /&gt;
The following androidx dependency is required in the app gradle file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
implementation &amp;quot;androidx.lifecycle:lifecycle-extensions:2.1.0&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
If you would like to take advantage of this auto detection feature of AppSdk at the very initial stage (e.g. splash screen or at of app launch time), before the AppSdk is initialized, can do so by calling the following newly introduced AppSdk public api, passing the application context :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void registerLifeCycleObserver(Context applicationContext)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Log messages for the new auto detection ====&lt;br /&gt;
&lt;br /&gt;
When the AppSdk app successfully registers for the LifeCycleObserver : &amp;lt;code&amp;gt;Registered LifeCycleObserver for App Background/Foreground auto-detection&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When the app enters the foreground state :&amp;lt;code&amp;gt;App is in foreground, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the app enters the background state :&amp;lt;code&amp;gt;App is in background, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the client app doesn't have the &amp;quot;androidx&amp;quot; gradle dependency and AppSdk fails to register LifeCycleObserver :&amp;lt;code&amp;gt;AndroidX LifecycleObserver can not be observed. Please use androidx dependency to activate SDK auto-detection of app background/foreground state.&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInForeground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - foreground&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInBackground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - background&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The SdkBgFgDetectionUtility class ===&lt;br /&gt;
Foreground/Background state measurement is a requirement of Nielsen AppSDK implementation which is especially crucial for static measurement. It may be implemented in multiple ways for Android. This includes&lt;br /&gt;
* Enable the Nielsen SDK to measure background/foreground state by makingthe relevant update to the AndroidManifest.&lt;br /&gt;
* Integrate Nielsen’s SdkBgFgDetectionUtility class within your Custom Application Class.&lt;br /&gt;
* Custom implementation of the required methods within your application.&lt;br /&gt;
&lt;br /&gt;
==== ForeGround/Background Measurement via AndroidManifest ====&lt;br /&gt;
The simplest way to measure the app background/foreground state is to add the following application tag to the Manifest XML. Integrating this into the Manifest XML will enable the SDK to measure app state directly. This approach is supported for Android 4.0 and up only; it requires that the application class is not in use for some other purpose.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;application android:name=&amp;quot;com.nielsen.app.sdk.AppSdkApplication&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using the Android SdkBgFbDetectionUtility Class ====&lt;br /&gt;
For developers who are already using the application class, it is recommended that background/foreground state is implemented using the  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class].  The  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] is compatible with Android 4+ and has been made available to Nielsen clients. (You will need to copy/paste the code provided into a file).&lt;br /&gt;
&lt;br /&gt;
==== Manual Background/ForeGround State Management ====&lt;br /&gt;
In cases where the developer is not able to use the AndroidManifest.xml solution nor the Nielsen provided   [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] the developer will need to manually identify the change of state through the application and call the respective API (appInForeground() or appInBackground()) to inform the SDK regarding the change of state from background to foreground or foreground to background.&lt;br /&gt;
&lt;br /&gt;
The SDK is informed about app state using the below methods.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
AppLaunchMeasurementManager.appInForeground(getApplicationContext());&lt;br /&gt;
AppLaunchMeasurementManager.appInBackground(getApplicationContext());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Within the lifecycle of individual activities, onResume() and onPause() are best suited to providing indication of the app state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Correct measurement of the foreground/background state is crucial to Static App measurement within Nielsen Digital Content Ratings (DCR).&lt;br /&gt;
== Using the NielsenAppSDKJSHandler ==&lt;br /&gt;
There could be a scenario in which a browser page, that is already tagged with the Nielsen BSDK, needs to be loaded via a webview.  In this situation it is recommended to use the '''NielsenAppSDKJSHandler''' which will allow communication between the AppSDK and the BSDK. &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''This feature is supported in versions 7.2 and above.'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
* Make sure you have the latest AppSdk.jar from Nielsen&lt;br /&gt;
* Enable the javascript on webview using below lines&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
 &amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
WebSettings webSetting = webView.getSettings();&lt;br /&gt;
webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Add  NielsenAppSDKJSHandler instance as javascript interface to webview with name “NielsenAppSDK” like below snippet&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext()), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This will enable listening to BSDK api calls within the APPSDK.  Please make sure your Technical Account Manager is aware that you wish to implement this method so a configuration file can be modified on the Nielsen servers; however, there are '''no changes required to the Browser page'''.&lt;br /&gt;
&lt;br /&gt;
==== Example:====&lt;br /&gt;
The below is an example of opening a webview with the NielsenAppSDKJSHandler&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
      WebSettings webSetting = webView.getSettings();&lt;br /&gt;
      webView.getSettings().setDomStorageEnabled(true); &lt;br /&gt;
      webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
      webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
      String url = &amp;quot;https://nielsen.com.index.htm&amp;quot;;&lt;br /&gt;
      webView.loadUrl(url);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;AndroidManifest.xml&amp;lt;/code&amp;gt; may need the following permissions set:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Closing NielsenAppSDKJSHandler ===&lt;br /&gt;
NielsenAppSDKJSHandler should be closed or cleaned up in below scenarios&lt;br /&gt;
* Before WebView is getting destructed&lt;br /&gt;
* Before loading new page&lt;br /&gt;
* Before closing application&lt;br /&gt;
NielsenAppSDKJSHandler provides a public interface with name &amp;quot;close()&amp;quot; and this function should be called on NielsenAppSDKJSHandler's instance in all above scenarios.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
// get your webview&lt;br /&gt;
WebView webView = findViewById(R.id.webView);&lt;br /&gt;
 &lt;br /&gt;
//Added JS Handler instance as java script interface for ggpm api type&lt;br /&gt;
NielsenAppSDKJSHandler jshandler = new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;);&lt;br /&gt;
webView.addJavascriptInterface(jshandler, &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
//Close JS Handler before making webview as null&lt;br /&gt;
jshandler.close();&lt;br /&gt;
webView = null;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interruptions during playback ==&lt;br /&gt;
As part of integrating Nielsen App SDK with the player application, the Video app developer needs to handle the following possible interruption scenarios:&lt;br /&gt;
* Pause / Play&lt;br /&gt;
* Network Loss (Wi-Fi / Airplane / Cellular)&lt;br /&gt;
* Call Interrupt (SIM or Third party Skype / Hangout call)&lt;br /&gt;
* Alarm Interrupt&lt;br /&gt;
* Content Buffering&lt;br /&gt;
* Device Lock / Unlock &lt;br /&gt;
* App going in the Background/Foreground&lt;br /&gt;
* Channel / Station Change Scenario&lt;br /&gt;
* Unplugging of headphone&lt;br /&gt;
In case of encountering one of the above interruptions, the player application needs to&lt;br /&gt;
* Call [[stop()]] immediately (except when content is buffering) and withhold sending playhead position.&lt;br /&gt;
* Start sending pings – &amp;lt;code&amp;gt;'loadMetadata'&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'playheadPosition'&amp;lt;/code&amp;gt; for the new viewing session, once the playback resumes.&lt;br /&gt;
Please see the [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Interruption_Scenarios Interruption Scenarios Page] for more details&lt;br /&gt;
&lt;br /&gt;
== Pre-Certification Checklists ==&lt;br /&gt;
After the application is ready to be sent for Nielsen Certification, please go through the [[Digital Pre-Certification Checklist App SDK]] and ensure the app behaves as expected, before submitting to Nielsen.&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK:&lt;br /&gt;
# '''[[#Global_Android_SDK_Opt-out|Global Android SDK Opt-out]]''' - managed by ''Opt out of Ads Personalization'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without Google Play Services or when using the noAd version of the SDK.&lt;br /&gt;
# '''[[#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Global Android SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen Android when the [https://developers.google.com/android/guides/setup Google Play services APIs] have been setup in your project.&lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the Android's '''Opt out of Ads Personalization''' setting. The user is opted out of demographic measurement if the OS-level '''Opt out of Ads Personalization''' setting is ''enabled''. As a publisher, you cannot override this setting.&lt;br /&gt;
&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global Android SDK, this optOutURL informs the user how to deactivate/activate “Out of Ads Personalization”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;'''Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information'''&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No Ad Framework Optout ===&lt;br /&gt;
The ''No Ad Framework Optout'' can be used when the host application does not leverage Google Play Services such as when using the noAd version or the NoID version.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Nielsen Android SDK 5.1.1.18 and above will check for ''OS-level opt-out'' first, if available. The user will be opted out if indicated at the OS-level '''OR''' the App-level.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The No Ad Framework Optout method works as follows: ====&lt;br /&gt;
* Get the current Nielsen opt-out URL via [[userOptOutURLString()]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[userOptOutURLString()]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut()]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No ID Optout (Kids_Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the NoID version of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OptOut Example Code ==&lt;br /&gt;
Below you will find some sample code for the:&lt;br /&gt;
* [[#Global OptOut Example|Global Android SDK]] - managed by Opt out of Ads Personalization setting on device '''(preferred approach)'''.&lt;br /&gt;
* [[#No_Ad_Framework_Optout_Sample_Code|Global Android noAd Framework]] - Use if Google Play APIs are unavailable or running noAd version.&lt;br /&gt;
*  It is currently not required to display an OptOut page for the NoID/Kids Build of the SDK.&lt;br /&gt;
===&amp;lt;span id=&amp;quot;Global OptOut Example&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Global OptOut Example ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user.  Please see the next section if using the No Ad Framework build&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;span id=&amp;quot;No Ad Framework Optout Sample Code&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;No Ad Framework Optout Sample Code ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user with the No Ad Framework SDK Build.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
            @Override&lt;br /&gt;
            public boolean shouldOverrideUrlLoading(WebView view, String url) {&lt;br /&gt;
&lt;br /&gt;
                if(url.contains(&amp;quot;nielsen&amp;quot;)){&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://1 it means the user selected Opt Out&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://0&amp;quot; it means the user selected Opt-In&lt;br /&gt;
                    appSdk.userOptOut(url);&lt;br /&gt;
                }&lt;br /&gt;
                return true;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Required Privacy Links ===&lt;br /&gt;
Users must either have access to the &amp;quot;About Nielsen Measurement&amp;quot; page, or have similar text available within the native app. Include &amp;quot;About Nielsen Measurement&amp;quot; and &amp;quot;Your Choices&amp;quot; link in the Privacy Policy / EULA or as a button near the link to the app's Privacy Policy.&lt;br /&gt;
&lt;br /&gt;
In addition, the following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
'''&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;'''&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via App-level Opt-out, the current Opt-Out status as detected by the SDK is available via the [[getOptOutStatus()]] property in the Nielsen Android SDK API. &amp;lt;code&amp;gt;appSdk.getOptOutStatus()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
Following Nielsen testing, you will need to:&lt;br /&gt;
&lt;br /&gt;
# '''Disable Debug Logging''': Disable logging by deleting &amp;lt;code&amp;gt;{nol_devDebug: 'DEBUG'}&amp;lt;/code&amp;gt; from initialization call.&lt;br /&gt;
# '''Notify Nielsen''': Once you are ready to go live, let us know so we can enable you for reporting. We will not be able to collect or report data prior to receiving notification from you.&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen  API using a standard no-frills player.&lt;br /&gt;
** [[Android Basic example|Android Studio Example]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen API integrated into a custom video player is bundled with the SDK.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_iOS_SDK&amp;diff=5489</id>
		<title>DCR Taiwan Video iOS SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_iOS_SDK&amp;diff=5489"/>
		<updated>2021-11-08T06:52:46Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}} {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
This guide covers implementation steps for iOS using Xcode utilizing the Standard Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{{iOS_SpecialNotes_for_iOS14}}&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[iOS SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
Version 8 of the Nielsen App SDK will come in three versions. One that is enabled to work with the App Tracking Transparency Framework, another version that does not use the Ad Framework, and a version for Kids Apps or where noID is required. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by the [https://developer.apple.com/documentation/apptrackingtransparency AppTrackingTransparency framework] . '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will attempt to collect the IDFA (Id for Advertisers) on the device.&amp;lt;br&amp;gt; * For iOS14+, if the value returned is &amp;lt;code&amp;gt;ATTrackingManager.AuthorizationStatus.authorized&amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;*  If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested.&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the IDFA, so it will attempt to retrieve the '''IDFV'''.&amp;lt;br /&amp;gt;* The [https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor ID for Vendors (IDFV)], may be used for analytics across apps from the same content provider.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Taiwan_Video_iOS_SDK#Global_iOS_SDK_No_Ad_Framework_Optout|Privacy Section]].&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Taiwan_Video_iOS_SDK#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
=== How to obtain the NielsenAppApi.Framework ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of CocoaPods. We recommend using the CocoaPods-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_iOS_Artifactory_Guide|Select to obtain CocoaPods implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
* [[DCR_Video_iOS_SDK_xcframework|Using the XCFramework bundle]]&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
Prior to SDK Version 6.2.0.0 the  IOS framework has been distributed as a static library packaged into framework bundle format. Apple recommends to use dynamic framework, it has some benefits over static libraries like less executable file size of an app, faster startup time and native support in xCode IDE. Nielsen AppSDK has been transformed into dynamic framework in this release ([[iOS_Static_Framework_Setup|static framework]] is still available).&lt;br /&gt;
&lt;br /&gt;
If migrating from the static library to this new dynamic framework, once implemented, unless your specific application requires, you can remove the following Frameworks that were once required:&amp;lt;code&amp;gt; [AdSupport, JavascriptCore, SystemConfiguration, Security, AVFoundation, libc++] &amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''Dynamic framework''' is created as a fat framework. It means that it contains slices required for devices (armv7, arm64) as well as slices required for simulators (i386, x86_64). Simulator slices are needed to let clients build and debug their app on the simulators, but they should be removed before sending the app to the AppStore. The example of the shell script that should be added as a Run Script phase in the application can be [[DCR_Taiwan_Video_iOS_SDK#Removing_Simulators_.28Dynamic_Framework_Only.29|found below]].&lt;br /&gt;
&lt;br /&gt;
'''[[DCR_Video_iOS_SDK_xcframework|XCFramework]]''' is solution for the problems described above Apple recommends to use XCFrameworks. In XCFramework, we no longer build a single framework with multiple architectures. Instead, we build one small framework for each combination of architecture and target and store it in its own folder. The top-level XCFramework folder have folders like ios-arm64, ios-arm64-simulator, etc. Each of these folders is its own framework, complete with headers, modules, and binary.&lt;br /&gt;
&lt;br /&gt;
=== Configuring Xcode Development Environment ===&lt;br /&gt;
Starting with SDK version 6.0.0.0, the Nielsen App SDK is compatible with Apple iOS versions 8.0 and above.  In addition, when using the dynamic framework,  all the required frameworks are linked automatically as the are needed.  More details can be found here: https://stackoverflow.com/questions/24902787/dont-we-need-to-link-framework-to-xcode-project-anymore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': All communications between the SDK and the Census (Collection Facility) use HTTPS.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Download Framework ===&lt;br /&gt;
The first step is to download and copy the [[Special:Downloads|NielsenAppApi.framework]] bundle to the app project directory. (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Framework ===&lt;br /&gt;
In the General tab for app configuration add NielsenAppApi.framework in the list of Embedded Binaries.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Path ===&lt;br /&gt;
Add path to the NielsenAppApi.framework in the Framework Search Paths build setting.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Import Framework ===&lt;br /&gt;
Add NielsenAppApi.framework module in the source file of your app:&lt;br /&gt;
&lt;br /&gt;
==== Using Swift ====&lt;br /&gt;
Add the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using Objective-C ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@import NielsenAppApi;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_SDK_Initialization}}&lt;br /&gt;
&lt;br /&gt;
== Configure Metadata ==&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Nielsen Key names (e.g. appid, program) are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Create channelName Metadata ===&lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| Any string representing the channel/stream	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
=== Create Content Metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
&amp;lt;blockquote&amp;gt; program and title metadata values should be passed to SDK as UTF-8 strings. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Metadata Example ====&lt;br /&gt;
&amp;lt;code&amp;gt;Swift&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
let contentMetadata = [&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
    &amp;quot;assetid&amp;quot;: &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Program S2, E3&amp;quot;,&lt;br /&gt;
    &amp;quot;isfullepisode&amp;quot;: &amp;quot;y&amp;quot;,&lt;br /&gt;
    &amp;quot;program&amp;quot;: &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
    &amp;quot;adloadtype&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
    &amp;quot;segB&amp;quot;: &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    &amp;quot;segC&amp;quot;: &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Objective-C&amp;lt;/code&amp;gt;    &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt; &lt;br /&gt;
NSDictionary * contentMetadata = @ {&lt;br /&gt;
    @ &amp;quot;type&amp;quot;: @ &amp;quot;content&amp;quot;,&lt;br /&gt;
    @ &amp;quot;assetid&amp;quot;: @ &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    @ &amp;quot;title&amp;quot;: @ &amp;quot;S2,E3&amp;quot;,&lt;br /&gt;
    @ &amp;quot;isfullepisode&amp;quot;: @ &amp;quot;y&amp;quot;,  &lt;br /&gt;
    @ &amp;quot;program&amp;quot;: @ &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    @ &amp;quot;length&amp;quot;: @ &amp;quot;3600&amp;quot;,&lt;br /&gt;
    @ &amp;quot;adloadtype&amp;quot;: @ &amp;quot;2&amp;quot;,&lt;br /&gt;
    @ &amp;quot;segB&amp;quot;: @ &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    @ &amp;quot;segC&amp;quot;: @ &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Configure metadata === &lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| ChannelInfo refers to the Channel name. This can be a free-form value&lt;br /&gt;
value such as a friendly name for the content being played. the SDK&amp;lt;br/&amp;gt;&lt;br /&gt;
will pass the application name automatically.&lt;br /&gt;
|| custom	|| No&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create Ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_LifeCycle_of_SDK}}&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&amp;lt;!--[[File:appsdkTimeline-DCR.png|icon|link=]]--&amp;gt;&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;nielsenMeter.play()&amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nielsenMeter.loadMetadata(contentMetadata)&amp;lt;/code&amp;gt; || // MetadataObject contains the JSON metadata&amp;lt;br&amp;gt; for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;nielsenMeter.playheadPosition(pos);&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead &amp;lt;br&amp;gt;while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;nielsenMeter.end()&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'playheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current UNIX timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'PlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the UNIX timestamp, for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Idle state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for an event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position is active.  If a LIVE event, use the current UNIX timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the content or Ad playback is interrupted and at the end of each Ad. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, call &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should begin from 0 at ad start.  When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Sequence_of_Calls}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Foreground_and_Background}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Interuptions_during_Playback}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_NielsenAppSDKJSHandler}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_PreCertification_Checklists}}&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK: &lt;br /&gt;
# '''[[#Global_iOS_SDK_Opt-out|Global iOS SDK Opt-out]]''' - managed by ''AppTracking'' or ''Limit Ad Tracking'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_Ad_Framework_Optout|Global iOS SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without the Ad Framework&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Global iOS SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen iOS &lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the iOS's '''Limit Ad Tracking''' or '''AppTracking''' setting. &lt;br /&gt;
*  If the User's device is running &amp;lt; iOS 13.x, the Nielsen SDK will check the status of '''Limit Ad Tracking'''.&lt;br /&gt;
*  iOS14 modifies the way Apple manages the collection of a User's Opt-In status through '''AppTracking'''. Starting with Version 8.x+, the Nielsen App SDK will check the iOS version during initialization. If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested. If iOS14.x +, then AppTracking is utilized.&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global iOS SDK, this optOutURL informs the user how to deactivate/activate “App Tracking/Limit Ad Tracking”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No Ad Framework Optout ===&lt;br /&gt;
The ''User Choice'' method can be used without the Ad Framework, or in situations where the publisher does not wish to use the [https://developer.apple.com/documentation/apptrackingtransparency App Tracking Transparency Framework]. As this flavor of the Nielsen SDK does not use the Ad Framework, so it is necessary to display an Optout Page to the userand capture their selection.&lt;br /&gt;
&lt;br /&gt;
Similar to the Global iOS SDK Flavor, it is a requirement to display a WebView element whose loadUrl is set to the&lt;br /&gt;
value obtained from optOutURL. This is a special URL that indicates Opt-in, or Opt-out and close the WebView.&lt;br /&gt;
&lt;br /&gt;
==== This opt-out method works as follows: ====&lt;br /&gt;
* Get the Nielsen opt-out URL via [[optOutURL]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[optOutURL]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No ID Optout (Kids Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the [https://nielsendownloads-green.digitalengsdk.com/digital/Nielsen-iOS-App-SDK-GlobalNoId_latest.zip NoID version] of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Opt-out example code ==&lt;br /&gt;
===== Swift =====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
import WebKit&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&lt;br /&gt;
class OptOutVC: UIViewController, NielsenAppApiDelegate, WKNavigationDelegate {&lt;br /&gt;
    var nielsenApi : NielsenAppApi!&lt;br /&gt;
    var webView: WKWebView!&lt;br /&gt;
   &lt;br /&gt;
    override func loadView() {&lt;br /&gt;
        webView = WKWebView()&lt;br /&gt;
        webView.navigationDelegate = self&lt;br /&gt;
        view = webView&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
&lt;br /&gt;
        if let appApi = self.nielsenApi {&lt;br /&gt;
            //Getting the optPut URL from SDK&lt;br /&gt;
            if let url = URL(string: appApi.optOutURL) {&lt;br /&gt;
                webView.load(URLRequest(url: url))&lt;br /&gt;
                webView.allowsBackForwardNavigationGestures = true&lt;br /&gt;
            }}}&lt;br /&gt;
&lt;br /&gt;
        func closeOptOutView() {&lt;br /&gt;
            self.dismiss(animated: true, completion: nil)&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
// Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.  This will receive the user's selection&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*  &lt;br /&gt;
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: &lt;br /&gt;
@escaping (WKNavigationActionPolicy) -&amp;gt; Void) {&lt;br /&gt;
            print(navigationAction.request.url?.absoluteString as Any) //For debugging to check what is being passed from webpage.&lt;br /&gt;
            if navigationAction.request.url?.absoluteString == &amp;quot;nielsen://close&amp;quot; {&lt;br /&gt;
                closeOptOutView()&lt;br /&gt;
                decisionHandler(.cancel)&lt;br /&gt;
            } else {&lt;br /&gt;
                if let url = navigationAction.request.url?.absoluteString, url.hasPrefix(&amp;quot;nielsen&amp;quot;) {&lt;br /&gt;
                    nielsenApi?.userOptOut(url). //either nielsenappsdk://1 or nielsenappsdk://0&lt;br /&gt;
                    decisionHandler(.cancel)&lt;br /&gt;
                } else {&lt;br /&gt;
                    if navigationAction.navigationType == .linkActivated {&lt;br /&gt;
                        if let url = navigationAction.request.url?.absoluteString, url.hasSuffix(&amp;quot;#&amp;quot;) {&lt;br /&gt;
                            decisionHandler(.allow)&lt;br /&gt;
                        } else {&lt;br /&gt;
                            decisionHandler(.cancel)&lt;br /&gt;
                            webView.load(navigationAction.request)&lt;br /&gt;
                        }&lt;br /&gt;
                    } else {&lt;br /&gt;
                        decisionHandler(.allow)&lt;br /&gt;
                    }}}}&lt;br /&gt;
  */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===== Objective-C =====&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#import &amp;quot;OptOutVC.h&amp;quot;&lt;br /&gt;
#import &amp;quot;NielsenInit.h&amp;quot;&lt;br /&gt;
#import &amp;lt;NielsenAppApi/NielsenAppApi.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@interface OptOutVC ()&lt;br /&gt;
&lt;br /&gt;
@property (weak, nonatomic) IBOutlet UIWebView *webView;&lt;br /&gt;
@end&lt;br /&gt;
&lt;br /&gt;
@implementation OptOutVC&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
    //Getting the optPut URL from eventTracker&lt;br /&gt;
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL&lt;br /&gt;
 URLWithString:self.nielsenApi.optOutURL]]];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*     &lt;br /&gt;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction&lt;br /&gt;
 decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler&lt;br /&gt;
{&lt;br /&gt;
    if ([navigationAction.request.URL.absoluteString isEqualToString:kNielsenWebClose])&lt;br /&gt;
    {   [self performSelector:@selector(closeOptOutView) withObject:nil afterDelay:0];&lt;br /&gt;
        decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
     } else {&lt;br /&gt;
        if ([navigationAction.request.URL.absoluteString hasPrefix:@&amp;quot;nielsen&amp;quot;])&lt;br /&gt;
        {[self.nielsenAppApi userOptOut:navigationAction.request.URL.absoluteString];&lt;br /&gt;
            decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
        } else {&lt;br /&gt;
            if (navigationAction.navigationType == WKNavigationTypeLinkActivated) &lt;br /&gt;
            { if ([navigationAction.request.URL.absoluteString hasSuffix:@&amp;quot;#&amp;quot;]) &lt;br /&gt;
                      {decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
                } else {&lt;br /&gt;
                    decisionHandler(WKNavigationActionPolicyCancel);&lt;br /&gt;
                    [webView loadRequest:[NSURLRequest requestWithURL:navigationAction.request.URL]];&lt;br /&gt;
                }} else {&lt;br /&gt;
                 decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
            }}}&lt;br /&gt;
*/&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via User Choice Opt-out, the current Opt-Out status as detected by the SDK is available via the [[optOutStatus]] property in the Nielsen SDK API&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@property (readonly) BOOL optOutStatus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Airplay}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Going_Live}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Removing_Simulator_Slices}}&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the Simplified API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen Simplified API using a standard no-frills player.&lt;br /&gt;
** [[Swift Basic Sample|Swift 5.0 Sample]]&lt;br /&gt;
** [[Objective-c Basic example|Objective-C Sample]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen Simplified API integrated into a custom video player.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_iOS_SDK&amp;diff=5488</id>
		<title>DCR Taiwan Video iOS SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_iOS_SDK&amp;diff=5488"/>
		<updated>2021-11-08T06:50:28Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International_DCR}} {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
This guide covers implementation steps for iOS using Xcode utilizing the Standard Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{{iOS_SpecialNotes_for_iOS14}}&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[iOS SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
Version 8 of the Nielsen App SDK will come in three versions. One that is enabled to work with the App Tracking Transparency Framework, another version that does not use the Ad Framework, and a version for Kids Apps or where noID is required. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by the [https://developer.apple.com/documentation/apptrackingtransparency AppTrackingTransparency framework] . '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will attempt to collect the IDFA (Id for Advertisers) on the device.&amp;lt;br&amp;gt; * For iOS14+, if the value returned is &amp;lt;code&amp;gt;ATTrackingManager.AuthorizationStatus.authorized&amp;lt;/code&amp;gt;.&amp;lt;br&amp;gt;*  If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested.&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the IDFA, so it will attempt to retrieve the '''IDFV'''.&amp;lt;br /&amp;gt;* The [https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor ID for Vendors (IDFV)], may be used for analytics across apps from the same content provider.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Taiwan_Video_iOS_SDK#Global_iOS_SDK_No_Ad_Framework_Optout|Privacy Section]].&lt;br /&gt;
|-&lt;br /&gt;
| '''iOS SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [[DCR_Taiwan_Video_iOS_SDK#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29|Opt Out Requirement]].&lt;br /&gt;
|}&lt;br /&gt;
=== How to obtain the NielsenAppApi.Framework ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of CocoaPods. We recommend using the CocoaPods-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_iOS_Artifactory_Guide|Select to obtain CocoaPods implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
* [[DCR_Video_iOS_SDK_xcframework|Using the XCFramework bundle]]&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
Prior to SDK Version 6.2.0.0 the  IOS framework has been distributed as a static library packaged into framework bundle format. Apple recommends to use dynamic framework, it has some benefits over static libraries like less executable file size of an app, faster startup time and native support in xCode IDE. Nielsen AppSDK has been transformed into dynamic framework in this release ([[iOS_Static_Framework_Setup|static framework]] is still available).&lt;br /&gt;
&lt;br /&gt;
If migrating from the static library to this new dynamic framework, once implemented, unless your specific application requires, you can remove the following Frameworks that were once required:&amp;lt;code&amp;gt; [AdSupport, JavascriptCore, SystemConfiguration, Security, AVFoundation, libc++] &amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''Dynamic framework''' is created as a fat framework. It means that it contains slices required for devices (armv7, arm64) as well as slices required for simulators (i386, x86_64). Simulator slices are needed to let clients build and debug their app on the simulators, but they should be removed before sending the app to the AppStore. The example of the shell script that should be added as a Run Script phase in the application can be [[DCR_Taiwan_Video_iOS_SDK#Removing_Simulators_.28Dynamic_Framework_Only.29|found below]].&lt;br /&gt;
&lt;br /&gt;
'''[[DCR_Video_iOS_SDK_xcframework|XCFramework]]''' is solution for the problems described above Apple recommends to use XCFrameworks. In XCFramework, we no longer build a single framework with multiple architectures. Instead, we build one small framework for each combination of architecture and target and store it in its own folder. The top-level XCFramework folder have folders like ios-arm64, ios-arm64-simulator, etc. Each of these folders is its own framework, complete with headers, modules, and binary.&lt;br /&gt;
&lt;br /&gt;
=== Configuring Xcode Development Environment ===&lt;br /&gt;
Starting with SDK version 6.0.0.0, the Nielsen App SDK is compatible with Apple iOS versions 8.0 and above.  In addition, when using the dynamic framework,  all the required frameworks are linked automatically as the are needed.  More details can be found here: https://stackoverflow.com/questions/24902787/dont-we-need-to-link-framework-to-xcode-project-anymore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': All communications between the SDK and the Census (Collection Facility) use HTTPS.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Download Framework ===&lt;br /&gt;
The first step is to download and copy the [[Special:Downloads|NielsenAppApi.framework]] bundle to the app project directory. (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Framework ===&lt;br /&gt;
In the General tab for app configuration add NielsenAppApi.framework in the list of Embedded Binaries.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Path ===&lt;br /&gt;
Add path to the NielsenAppApi.framework in the Framework Search Paths build setting.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Import Framework ===&lt;br /&gt;
Add NielsenAppApi.framework module in the source file of your app:&lt;br /&gt;
&lt;br /&gt;
==== Using Swift ====&lt;br /&gt;
Add the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using Objective-C ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@import NielsenAppApi;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_SDK_Initialization}}&lt;br /&gt;
&lt;br /&gt;
== Configure Metadata ==&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Nielsen Key names (e.g. appid, program) are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Create channelName Metadata ===&lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| Any string representing the channel/stream	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
=== Create Content Metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
&amp;lt;blockquote&amp;gt; program and title metadata values should be passed to SDK as UTF-8 strings. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Metadata Example ====&lt;br /&gt;
&amp;lt;code&amp;gt;Swift&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
let contentMetadata = [&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
    &amp;quot;assetid&amp;quot;: &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Program S2, E3&amp;quot;,&lt;br /&gt;
    &amp;quot;isfullepisode&amp;quot;: &amp;quot;y&amp;quot;,&lt;br /&gt;
    &amp;quot;program&amp;quot;: &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
    &amp;quot;adloadtype&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
    &amp;quot;segB&amp;quot;: &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    &amp;quot;segC&amp;quot;: &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Objective-C&amp;lt;/code&amp;gt;    &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt; &lt;br /&gt;
NSDictionary * contentMetadata = @ {&lt;br /&gt;
    @ &amp;quot;type&amp;quot;: @ &amp;quot;content&amp;quot;,&lt;br /&gt;
    @ &amp;quot;assetid&amp;quot;: @ &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    @ &amp;quot;title&amp;quot;: @ &amp;quot;S2,E3&amp;quot;,&lt;br /&gt;
    @ &amp;quot;isfullepisode&amp;quot;: @ &amp;quot;y&amp;quot;,  &lt;br /&gt;
    @ &amp;quot;program&amp;quot;: @ &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    @ &amp;quot;length&amp;quot;: @ &amp;quot;3600&amp;quot;,&lt;br /&gt;
    @ &amp;quot;adloadtype&amp;quot;: @ &amp;quot;2&amp;quot;,&lt;br /&gt;
    @ &amp;quot;segB&amp;quot;: @ &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    @ &amp;quot;segC&amp;quot;: @ &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Configure metadata === &lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| ChannelInfo refers to the Channel name. This can be a free-form value&lt;br /&gt;
value such as a friendly name for the content being played. the SDK&amp;lt;br/&amp;gt;&lt;br /&gt;
will pass the application name automatically.&lt;br /&gt;
|| custom	|| No&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create Ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_LifeCycle_of_SDK}}&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&amp;lt;!--[[File:appsdkTimeline-DCR.png|icon|link=]]--&amp;gt;&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;nielsenMeter.play()&amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nielsenMeter.loadMetadata(contentMetadata)&amp;lt;/code&amp;gt; || // MetadataObject contains the JSON metadata&amp;lt;br&amp;gt; for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;nielsenMeter.playheadPosition(pos);&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead &amp;lt;br&amp;gt;while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;nielsenMeter.end()&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'playheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current UNIX timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'PlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the UNIX timestamp, for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Idle state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for an event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position is active.  If a LIVE event, use the current UNIX timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the content or Ad playback is interrupted and at the end of each Ad. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, call &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should begin from 0 at ad start.  When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Sequence_of_Calls}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Foreground_and_Background}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Interuptions_during_Playback}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_NielsenAppSDKJSHandler}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_PreCertification_Checklists}}&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK: &lt;br /&gt;
# '''[[#Global_iOS_SDK_Opt-out|Global iOS SDK Opt-out]]''' - managed by ''AppTracking'' or ''Limit Ad Tracking'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_Ad_Framework_Optout|Global iOS SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without the Ad Framework&lt;br /&gt;
# '''[[#Global_iOS_SDK_No_ID_Optout_.28Kids_Category.29]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen iOS &lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the iOS's '''Limit Ad Tracking''' or '''AppTracking''' setting. &lt;br /&gt;
*  If the User's device is running &amp;lt; iOS 13.x, the Nielsen SDK will check the status of '''Limit Ad Tracking'''.&lt;br /&gt;
*  iOS14 modifies the way Apple manages the collection of a User's Opt-In status through '''AppTracking'''. Starting with Version 8.x+, the Nielsen App SDK will check the iOS version during initialization. If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested. If iOS14.x +, then AppTracking is utilized.&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global iOS SDK, this optOutURL informs the user how to deactivate/activate “App Tracking/Limit Ad Tracking”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No Ad Framework Optout ===&lt;br /&gt;
The ''User Choice'' method can be used without the Ad Framework, or in situations where the publisher does not wish to use the [https://developer.apple.com/documentation/apptrackingtransparency App Tracking Transparency Framework]. As this flavor of the Nielsen SDK does not use the Ad Framework, so it is necessary to display an Optout Page to the userand capture their selection.&lt;br /&gt;
&lt;br /&gt;
Similar to the Global iOS SDK Flavor, it is a requirement to display a WebView element whose loadUrl is set to the&lt;br /&gt;
value obtained from optOutURL. This is a special URL that indicates Opt-in, or Opt-out and close the WebView.&lt;br /&gt;
&lt;br /&gt;
==== This opt-out method works as follows: ====&lt;br /&gt;
* Get the Nielsen opt-out URL via [[optOutURL]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[optOutURL]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No ID Optout (Kids Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the [https://nielsendownloads-green.digitalengsdk.com/digital/Nielsen-iOS-App-SDK-GlobalNoId_latest.zip NoID version] of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Opt-out example code ==&lt;br /&gt;
===== Swift =====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
import WebKit&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&lt;br /&gt;
class OptOutVC: UIViewController, NielsenAppApiDelegate, WKNavigationDelegate {&lt;br /&gt;
    var nielsenApi : NielsenAppApi!&lt;br /&gt;
    var webView: WKWebView!&lt;br /&gt;
   &lt;br /&gt;
    override func loadView() {&lt;br /&gt;
        webView = WKWebView()&lt;br /&gt;
        webView.navigationDelegate = self&lt;br /&gt;
        view = webView&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
&lt;br /&gt;
        if let appApi = self.nielsenApi {&lt;br /&gt;
            //Getting the optPut URL from SDK&lt;br /&gt;
            if let url = URL(string: appApi.optOutURL) {&lt;br /&gt;
                webView.load(URLRequest(url: url))&lt;br /&gt;
                webView.allowsBackForwardNavigationGestures = true&lt;br /&gt;
            }}}&lt;br /&gt;
&lt;br /&gt;
        func closeOptOutView() {&lt;br /&gt;
            self.dismiss(animated: true, completion: nil)&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
// Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.  This will receive the user's selection&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*  &lt;br /&gt;
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: &lt;br /&gt;
@escaping (WKNavigationActionPolicy) -&amp;gt; Void) {&lt;br /&gt;
            print(navigationAction.request.url?.absoluteString as Any) //For debugging to check what is being passed from webpage.&lt;br /&gt;
            if navigationAction.request.url?.absoluteString == &amp;quot;nielsen://close&amp;quot; {&lt;br /&gt;
                closeOptOutView()&lt;br /&gt;
                decisionHandler(.cancel)&lt;br /&gt;
            } else {&lt;br /&gt;
                if let url = navigationAction.request.url?.absoluteString, url.hasPrefix(&amp;quot;nielsen&amp;quot;) {&lt;br /&gt;
                    nielsenApi?.userOptOut(url). //either nielsenappsdk://1 or nielsenappsdk://0&lt;br /&gt;
                    decisionHandler(.cancel)&lt;br /&gt;
                } else {&lt;br /&gt;
                    if navigationAction.navigationType == .linkActivated {&lt;br /&gt;
                        if let url = navigationAction.request.url?.absoluteString, url.hasSuffix(&amp;quot;#&amp;quot;) {&lt;br /&gt;
                            decisionHandler(.allow)&lt;br /&gt;
                        } else {&lt;br /&gt;
                            decisionHandler(.cancel)&lt;br /&gt;
                            webView.load(navigationAction.request)&lt;br /&gt;
                        }&lt;br /&gt;
                    } else {&lt;br /&gt;
                        decisionHandler(.allow)&lt;br /&gt;
                    }}}}&lt;br /&gt;
  */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===== Objective-C =====&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#import &amp;quot;OptOutVC.h&amp;quot;&lt;br /&gt;
#import &amp;quot;NielsenInit.h&amp;quot;&lt;br /&gt;
#import &amp;lt;NielsenAppApi/NielsenAppApi.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@interface OptOutVC ()&lt;br /&gt;
&lt;br /&gt;
@property (weak, nonatomic) IBOutlet UIWebView *webView;&lt;br /&gt;
@end&lt;br /&gt;
&lt;br /&gt;
@implementation OptOutVC&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
    //Getting the optPut URL from eventTracker&lt;br /&gt;
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL&lt;br /&gt;
 URLWithString:self.nielsenApi.optOutURL]]];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*     &lt;br /&gt;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction&lt;br /&gt;
 decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler&lt;br /&gt;
{&lt;br /&gt;
    if ([navigationAction.request.URL.absoluteString isEqualToString:kNielsenWebClose])&lt;br /&gt;
    {   [self performSelector:@selector(closeOptOutView) withObject:nil afterDelay:0];&lt;br /&gt;
        decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
     } else {&lt;br /&gt;
        if ([navigationAction.request.URL.absoluteString hasPrefix:@&amp;quot;nielsen&amp;quot;])&lt;br /&gt;
        {[self.nielsenAppApi userOptOut:navigationAction.request.URL.absoluteString];&lt;br /&gt;
            decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
        } else {&lt;br /&gt;
            if (navigationAction.navigationType == WKNavigationTypeLinkActivated) &lt;br /&gt;
            { if ([navigationAction.request.URL.absoluteString hasSuffix:@&amp;quot;#&amp;quot;]) &lt;br /&gt;
                      {decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
                } else {&lt;br /&gt;
                    decisionHandler(WKNavigationActionPolicyCancel);&lt;br /&gt;
                    [webView loadRequest:[NSURLRequest requestWithURL:navigationAction.request.URL]];&lt;br /&gt;
                }} else {&lt;br /&gt;
                 decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
            }}}&lt;br /&gt;
*/&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via User Choice Opt-out, the current Opt-Out status as detected by the SDK is available via the [[optOutStatus]] property in the Nielsen SDK API&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@property (readonly) BOOL optOutStatus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Airplay}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Going_Live}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Removing_Simulator_Slices}}&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the Simplified API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen Simplified API using a standard no-frills player.&lt;br /&gt;
** [[Swift Basic Sample|Swift 5.0 Sample]]&lt;br /&gt;
** [[Objective-c Basic example|Objective-C Sample]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen Simplified API integrated into a custom video player.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Browser_SDK&amp;diff=5484</id>
		<title>DCR Taiwan Video Browser SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Browser_SDK&amp;diff=5484"/>
		<updated>2021-11-03T04:43:57Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: Created page with &amp;quot;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}}  {{CurrentBreadcrumb}} Category:Digital  __NOTOC__ == Overview == The Nielsen SDK is one of multiple fr...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The Browser SDK (BSDK) is the framework for website developers to integrate Nielsen Measurement into their media players. Nielsen SDKs are also equipped to measure static content and can track key life cycle events.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 30px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-&lt;br /&gt;
|| ☑ || '''App ID (apid)''' || Unique ID assigned to the player/site and configured by product. During initial implementation, a 'test' apid will be given. Once the implementation has been certified, a 'production' apid will then be generated and needs to be used before 'going live'. || Contact Nielsen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Configure SDK ==&lt;br /&gt;
There are two steps required for configuring the SDK:&lt;br /&gt;
*Add Static Queue Snippet&lt;br /&gt;
*Create SDK Instance&lt;br /&gt;
&lt;br /&gt;
=== Static Queue Snippet ===&lt;br /&gt;
The static queue snippet allows the SDK APIs to be called while the actual SDK and configuration file are still being downloaded. As the queue can capture all API calls before the download completes, there is no wait time. Once the SDK is available, the API calls will transition from directing to the queue to the SDK seamlessly.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the following script tag to the website:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Create SDK Instance===&lt;br /&gt;
To initialize the SDK, create an SDK instance by making the initialization call:&lt;br /&gt;
&lt;br /&gt;
==== Initialization API Call ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
NOLBUNDLE.nlsQ(&amp;quot;&amp;lt;apid&amp;gt;&amp;quot;, &amp;quot;&amp;lt;instanceName&amp;gt;&amp;quot;,{nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
When creating an instance, pass the following values: (&amp;lt;code&amp;gt;nol_sdkDebug&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;optout&amp;lt;/code&amp;gt; are optional)&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter	!! Description	!! Values&lt;br /&gt;
|-&lt;br /&gt;
| apid	|| Unique ID assigned to player/site ||	&lt;br /&gt;
'TXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Test Apid that starts with 'T'&amp;lt;br/&amp;gt;&lt;br /&gt;
'PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' - Production Apid that starts with 'P'&lt;br /&gt;
|-&lt;br /&gt;
|instanceName ||	Name of SDK instance ||	&amp;quot;any string value&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| nol_sdkDebug	|| Enables Nielsen console logging if desired. 	|| &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
{nol_sdkDebug: &amp;quot;debug&amp;quot;} &lt;br /&gt;
{nol_sdkDebug: &amp;quot;info&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;warn&amp;quot;}&lt;br /&gt;
{nol_sdkDebug: &amp;quot;true&amp;quot;}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|optout || Optional: OptOut global parameter. || &amp;lt;code&amp;gt;1/0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;true/false&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example SDK Initialization ====&lt;br /&gt;
When the initialization call is made, a unique static configuration file, &amp;lt;apid&amp;gt;.js, will be downloaded based on the apid and will be cached on the user’s browser.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
    nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
    optout: &amp;quot;false&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the configuration is downloaded, the SDK itself will be downloaded and initialized. All SDK modules are included in one file: “nlsSDK600.bundle.min.js”. More information on OptOut Parameter under [[DCR Taiwan Video Browser SDK#Privacy_and_Opt-Out|Privacy and Opt-Out.]]&lt;br /&gt;
&lt;br /&gt;
=== Example SDK Configuration ===&lt;br /&gt;
&lt;br /&gt;
The configuration should include the Static Queue Snippet and an SDK Instance for an unique App ID as shown in the example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Add Static Queue Snippet&lt;br /&gt;
!function(e,n){&lt;br /&gt;
  function t(e){&lt;br /&gt;
    return&amp;quot;object&amp;quot;==typeof e?JSON.parse(JSON.stringify(e)):e&lt;br /&gt;
  }&lt;br /&gt;
  e[n]=e[n]||&lt;br /&gt;
  {&lt;br /&gt;
    nlsQ:function(o,r,c){&lt;br /&gt;
      var s=e.document,&lt;br /&gt;
      a=s.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
      a.async=1,&lt;br /&gt;
      a.src=(&amp;quot;http:&amp;quot;===e.location.protocol?&amp;quot;http:&amp;quot;:&amp;quot;https:&amp;quot;)+&amp;quot;//cdn-gl.imrworldwide.com/conf/&amp;quot;+o+&amp;quot;.js#name=&amp;quot;+r+&amp;quot;&amp;amp;ns=&amp;quot;+n;&lt;br /&gt;
      var i=s.getElementsByTagName(&amp;quot;script&amp;quot;)[0];&lt;br /&gt;
      return i.parentNode.insertBefore(a,i),&lt;br /&gt;
      e[n][r]=e[n][r]||{g:c||{},&lt;br /&gt;
      ggPM:function(o,c,s,a,i){e[n][r].q=e[n][r].q||[];try{var l=t([o,c,s,a,i]);e[n][r].q.push(l)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}},&lt;br /&gt;
      trackEvent:function(o){e[n][r].te=e[n][r].te||[];try{var c=t(o);e[n][r].te.push(c)}&lt;br /&gt;
catch(e){console&amp;amp;&amp;amp;console.log&amp;amp;&amp;amp;console.log(&amp;quot;Error: Cannot register event in Nielsen SDK queue.&amp;quot;)}}},&lt;br /&gt;
      e[n][r]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}(window,&amp;quot;NOLBUNDLE&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
// Created SDK Instance&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {nol_sdkDebug: &amp;quot;debug&amp;quot;});&lt;br /&gt;
&amp;lt;/script&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Create Metadata Objects ===&lt;br /&gt;
There are two types of asset metadata:&lt;br /&gt;
*content: identify video&lt;br /&gt;
*ad: identify each ad&lt;br /&gt;
&lt;br /&gt;
The metadata received for each asset is used for classification and reporting.&lt;br /&gt;
&lt;br /&gt;
Metadata can be passed through key-values using the Nielsen reserved keys. User will need to set up content and ad objects with the required Nielsen keys as shown in the sample code below.&lt;br /&gt;
&lt;br /&gt;
==== Content Metadata ====&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Content Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var contentMetadataObject =&lt;br /&gt;
{  &lt;br /&gt;
  type:           'content',&lt;br /&gt;
  assetid:        'VID-123456',&lt;br /&gt;
  program:        'program name',&lt;br /&gt;
  title:          'episode title',&lt;br /&gt;
  length:         'length in seconds',&lt;br /&gt;
  isfullepisode:  'y',&lt;br /&gt;
  adloadtype:     '2',&lt;br /&gt;
  segB:           'custom segment B', // optional&lt;br /&gt;
  segC:           'custom segment C', // optional&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var adMetadataObject = &lt;br /&gt;
{  &lt;br /&gt;
  type:    'preroll',&lt;br /&gt;
  assetid: 'AD-1'&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt; URL Character Limit: There is a URL character limit of 2K characters due to browser limitations. Exceeding this value could impair data delivery on particular browsers. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Call Nielsen APIs ====&lt;br /&gt;
The method for calling events is ggPM().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
nSdkInstance.ggPM('event', parameter, ...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interrupt Scenarios ==&lt;br /&gt;
&lt;br /&gt;
=== Pause Event ===&lt;br /&gt;
The setPlayheadPostion event is used for handling pause. To indicate pause, stop passing the playhead position to the SDK. Once the content resumes, begin sending the playhead again with the correct playhead value.&lt;br /&gt;
&lt;br /&gt;
=== Other Interrupt Scenarios ===&lt;br /&gt;
The following possible browser interruption scenarios must be handled:&lt;br /&gt;
&lt;br /&gt;
* Browser/Tab close&lt;br /&gt;
* Leaving the page to another destination&lt;br /&gt;
* Pressing the stop button&lt;br /&gt;
* Network Loss&lt;br /&gt;
&lt;br /&gt;
There are many cases where the player itself has the ability to detect such situations. If not, these interruption scenarios can be handled through JavaScript. The events that are called will depend on the asset being played (e.g. midroll vs. content).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
window.addEventListener('beforeunload', function(event) &lt;br /&gt;
{&lt;br /&gt;
  // Only inside a midroll indicate &amp;lt;stop&amp;gt; for the ad&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
  &lt;br /&gt;
  // Indicate &amp;lt;end&amp;gt; and &amp;lt;stop&amp;gt; for the content&lt;br /&gt;
  nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
  nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' User may need to add code to support specific browser versions (e.g. older versions of Internet Explorer).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position in seconds	|| Call when content or ads complete playing and pass playhead position&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== SDK Playhead Event Sequence ==&lt;br /&gt;
The sample event lifecycles can be used as a reference for identifying the order for calling events.&lt;br /&gt;
&lt;br /&gt;
=== Content Playback ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// CONTENT PLAYS&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Content Playback with Ads ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// START OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject); &lt;br /&gt;
 &lt;br /&gt;
// PREROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', prerollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// MIDROLL&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', midrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// CONTENT RESUMES&lt;br /&gt;
nSdkInstance.ggPM('loadMetadata', contentMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
&lt;br /&gt;
// END OF STREAM&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('end', playheadPosition);&lt;br /&gt;
 &lt;br /&gt;
// POSTROLL&lt;br /&gt;
nSdkInstance.ggPM('loadmetadata', postrollMetadataObject);&lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
//  &lt;br /&gt;
//   pass playhead every second&lt;br /&gt;
//   &lt;br /&gt;
nSdkInstance.ggPM('setPlayheadPosition', playheadPosition);&lt;br /&gt;
nSdkInstance.ggPM('stop', playheadPosition);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* 'setPlayheadPosition' is used for calculating duration and must be passed every second. The final playhead position must be sent for the current asset being played before calling 'stop', 'end', or 'loadmetadata'.&lt;br /&gt;
&lt;br /&gt;
* For Ad Pods, events must be called for each individual Ad. Each Ad playhead position should begin at ‘0’ when ad starts.&lt;br /&gt;
&lt;br /&gt;
* When content has resumed following an ad break, the playhead position update must continue where previous content segment left off. The playhead position should be passed as a rounded number with no decimals.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are two primary methods for implementing user Opt-out preferences:&lt;br /&gt;
# [[#User Opt Out|User Opt Out]] - Provide a link to the Nielsen Privacy Policy page when a User can make their selection&lt;br /&gt;
# [[#Initialization Opt Out|Initialization Opt Out]] - Global OptOut Parameter&lt;br /&gt;
&lt;br /&gt;
=== User Opt Out === &lt;br /&gt;
The site must provide a means for the user to opt-out of, or opt back into, Nielsen Measurement. A user can opt-out if they would prefer not to participate in any Nielsen online measurement research. To implement the User Opt-Out option, include the following two items in your privacy policy.&lt;br /&gt;
*A notice that the player (or page in relation to static measurement) includes proprietary measurement software that allows users to contribute to market research (such as Nielsen Content Ratings).&lt;br /&gt;
*A link to the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&lt;br /&gt;
On the Nielsen Digital Measurement Privacy Policy page, users can click Choices to read more detailed information about the measurement software, learn about their options with regard to Nielsen measurement, and, if they do not want to participate in Nielsen online measurement, click a link to receive an opt-out cookie.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
* Once users have opted out via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=total&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/  link], their browser cookies will contain the value '''TOTAL_OPTOUT'''. This will prevent a redirect to our data provider from occurring&lt;br /&gt;
* Users can opt back in via this [http://server-us.imrworldwide.com/cgi-bin/o?oo=cancel&amp;amp;tu=https://sites.nielsen.com/legal/policy/en/cookie-policy/ link].  When a user selects that link, their opt-out cookie will be deleted and they will be able to be measured moving forward.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The following paragraph is a template for a Privacy Statement.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
The properties may feature Nielsen proprietary measurement software, which will allow users to contribute to market research, such as Nielsen Digital Content Ratings. To learn more about the information that Nielsen software may collect and your choices with regard to it, please see the Nielsen Digital Measurement Privacy Policy at https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== User Opt Back In ====&lt;br /&gt;
Once users have opted-out, they can choose to opt back into Nielsen Measurement at anytime by selecting the opt back in link on the Nielsen Digital Privacy Policy page. When a user selects the link, their opt-out cookie will be deleted and they will be able to be measured.&lt;br /&gt;
&lt;br /&gt;
=== Initialization Opt Out ===&lt;br /&gt;
The BSDK600 now supports the ability to optout on initialization of the SDK by allowing an optout global parameter to be passed.  This optout will be maintained through the session of the SDK instance. Specifications and limitations are specified below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type&lt;br /&gt;
! Supported Values&lt;br /&gt;
! Notes&lt;br /&gt;
! Optout&lt;br /&gt;
|-&lt;br /&gt;
||optout||True, Yes, or 1|| Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: true});&lt;br /&gt;
|| Ping parameter will set uoo=true.&lt;br /&gt;
|-&lt;br /&gt;
||optout|| False, No, or 0 || Case is insensitive and can be string or bool&lt;br /&gt;
Example: nlsQ(&amp;quot;XXXXXXXX-BH45-JKY6-BKH7-67GJKY68GJK7&amp;quot;, &amp;quot;myInstance&amp;quot;, { optout: false});&lt;br /&gt;
|| Ping parameter will set uoo to blank.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
==== Example of using OptOut ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;XXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, {&lt;br /&gt;
  nol_sdkDebug: &amp;quot;debug&amp;quot;,&lt;br /&gt;
  optout: &amp;quot;true&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Opt Out Overview ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser Cookie&lt;br /&gt;
! uoo value in session ping&lt;br /&gt;
! Final Optout Status&lt;br /&gt;
|-&lt;br /&gt;
||Default Value || no uoo value or uoo=0|| Not Opted Out&lt;br /&gt;
|-&lt;br /&gt;
||Default Value ||  uoo=1 || Opted Out&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
After the integration has been certified, users will need to make a couple of updates to the initialization call to ensure that player will be measured properly. Ensure that a production apid (starting with 'P') is used after going live.&lt;br /&gt;
Disable debug logging by deleting {nol_sdkDebug: 'DEBUG'} from initialization call.&lt;br /&gt;
&lt;br /&gt;
'''Example Production Initialization Call'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
var nSdkInstance = NOLBUNDLE.nlsQ(&amp;quot;PXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&amp;quot;, &amp;quot;nlsnInstance&amp;quot;, { optout: &amp;quot;false&amp;quot;});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Android_SDK&amp;diff=5483</id>
		<title>DCR Taiwan Video Android SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_Android_SDK&amp;diff=5483"/>
		<updated>2021-11-03T04:42:12Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: Created page with &amp;quot;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}}  {{CurrentBreadcrumb}} Category:Digital  == Overview == The Nielsen SDK is one of multiple framework SD...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}}  {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
Before you start the integration, you will need:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 15%;&amp;quot; | Item&lt;br /&gt;
! Description&lt;br /&gt;
! Source&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''App ID (appid)''' || Unique ID assigned to the player/site and configured by product. || Provided by Nielsen&lt;br /&gt;
|-style=&amp;quot;background-color:#d0f6f8;&amp;quot;&lt;br /&gt;
 || '''Nielsen SDK''' || Includes SDK frameworks and '''sample implementation'''; ''See [[Android SDK Release Notes]]'' || [[Special:Downloads|Download]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If need App ID(s) or our SDKs, feel free to reach out to us and we will be happy to help you get started.&lt;br /&gt;
Refer to [[Digital Measurement Onboarding]] guide for information on how to get a Nielsen App SDK and appid.&lt;br /&gt;
&lt;br /&gt;
==  Implementation ==&lt;br /&gt;
This guide covers implementation steps for Android Studio utilizing the Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! SDK Flavor&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '''Android Ad Version'''&lt;br /&gt;
|* Opt-In and Opt-Out functionality managed by Opt out of Ads Personlization setting on device. '''(Preferred approach)''' &amp;lt;br /&amp;gt;* The Nielsen SDK will collect the [https://developer.android.com/training/articles/ad-id Google Advertising ID] unless the user Opts Out.&amp;lt;br&amp;gt;* If the Google Play Service is unavailable, (ie: Amazon and Huawei devices) the Nielsen sdk will secure the Android ID.&amp;lt;br&amp;gt; * There are 3 versions available starting with the Nielsen SDK 8.1.0.0.&lt;br /&gt;
|-&lt;br /&gt;
| '''Android No Ad Framework'''&lt;br /&gt;
|* Without the Ad Framework, the Nielsen SDK cannot read the Google Advertising ID, so will retrieve the '''AndroidID'''.&amp;lt;br /&amp;gt;* The AndroidID is a 64-bit number (expressed as a hexadecimal string), unique to each combination of app-signing key, user and device.&amp;lt;br /&amp;gt;* The developer is required to present the User Choice Opt Out page which is described in the [[DCR_Sweden_Video_Android_SDK#Global iOS SDK Opt-out|Global iOS SDK Opt-out]].&lt;br /&gt;
|-&lt;br /&gt;
| '''Android SDK noID'''&lt;br /&gt;
|* This version of the Nielsen SDK is perfect for Kid apps, or where no ID is required.&amp;lt;br&amp;gt;* Please review the [https://engineeringportal.nielsen.com//docs/DCR_Video_Android_SDK#Special_Note_Regarding_Apps_in_the_Kids_Category Opt Out Requirement].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== How to obtain the NielsenAppApi ===&lt;br /&gt;
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of Gradle. We recommend using the Gradle-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.&lt;br /&gt;
* [[Digital_Measurement_Android_Artifactory_Guide|Select to obtain Gradle implementation guide]]&lt;br /&gt;
* [[Special:Downloads|Select to Download Directly]]&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
&lt;br /&gt;
=== Configuring Android Development Environment ===&lt;br /&gt;
*The Nielsen App SDK (located in the [https://engineeringportal.nielsen.com/docs/Special:Downloads Downloads section] of the website) class is the primary application interface to the Nielsen App SDK on Android.&lt;br /&gt;
*The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.&lt;br /&gt;
*The Nielsen App SDK can also be added as a [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Android_Artifactory_Guide Artifact Repository]. If implemented this way, you do not need to download the appsdk from the Nielsen Portal.&lt;br /&gt;
&lt;br /&gt;
'''Nielsen App SDK is compatible with Android OS versions 2.3+. Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.'''&lt;br /&gt;
&lt;br /&gt;
The requirement for the Java ''AppSdk.jar'' library and the ''libAppSdk.so'' native library will depend on the type of host application that will make use of them.&lt;br /&gt;
* '''For Video player applications'''&lt;br /&gt;
** The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 3.0 and later will support it natively).&lt;br /&gt;
** If the player application uses a 3rd party media player implementing its own HLS, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.&lt;br /&gt;
&lt;br /&gt;
Once SDK is downloaded ensure to unzip the Nielsen SDK and copy the AppSdk.jar in your app (Android Studio) libs folder, then right click the AppSdk.jar and select '''Add As Library'''.&lt;br /&gt;
Ensure the AppSdk.jar file is added in 'build.grade (App Level) file.&lt;br /&gt;
* App SDK 1.2 provides support for x86, mips, and armeabi-7a architecture.&lt;br /&gt;
&lt;br /&gt;
==== Google Play Services ====&lt;br /&gt;
Add the Google Play Services in the project,&lt;br /&gt;
Steps: Android Studio -&amp;gt; File -&amp;gt; Project Structure -&amp;gt;(In module selection) select App -&amp;gt; Dependencies (tab) -&amp;gt; Click &amp;quot;+&amp;quot; button and search for &amp;lt;code&amp;gt;&amp;quot;*play-services*&amp;quot;&amp;lt;/code&amp;gt;.  Then select the most recent version of the [https://developers.google.com/admob/android/quick-start play-services Artifact].&lt;br /&gt;
Ensure it is added in build.gradle (App level) file&lt;br /&gt;
&lt;br /&gt;
==== Manifest File ==== &lt;br /&gt;
* Add the following permissions on the project’s ''AndroidManifest.xml'' file.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more details to handle runtime permissions in Android versions, please visit [https://developer.android.com/training/permissions/requesting.html].   &lt;br /&gt;
&lt;br /&gt;
* In &amp;lt;code&amp;gt;AndroidManifest.xml &amp;lt;/code&amp;gt;under &amp;lt;application&amp;gt; node add the following metadata&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&amp;lt;manifest&amp;gt;&lt;br /&gt;
    &amp;lt;application&amp;gt;&lt;br /&gt;
        &amp;lt;!-- Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713 --&amp;gt;&lt;br /&gt;
        &amp;lt;meta-data&lt;br /&gt;
            android:name=&amp;quot;com.google.android.gms.ads.APPLICATION_ID&amp;quot;&lt;br /&gt;
            android:value=&amp;quot;ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/application&amp;gt;&lt;br /&gt;
&amp;lt;/manifest&amp;gt;&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* App SDK checks to see if there is a Google service available and updated.&lt;br /&gt;
* If not available or updated, App SDK will not use this service when executing its functions and will make reference to missing imports and the app will not be compiled.&lt;br /&gt;
&lt;br /&gt;
==== Library ====&lt;br /&gt;
Nielsen App SDK uses the following packages/classes from the [https://developers.google.com/android/guides/setup Google Play service].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;coffeescript&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
  implementation 'com.google.android.gms:play-services-ads:xx.x.x'&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Classes/package ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;&lt;br /&gt;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;&lt;br /&gt;
import com.google.android.gms.common.ConnectionResult;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesUtil;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesRepairableException;&lt;br /&gt;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SDK Initialization ==&lt;br /&gt;
The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object, which can be used simultaneously without any issue. The sharedInstance API that creates a singleton object was deprecated prior to version 5.1.1. (Version 4.0 for Android)&lt;br /&gt;
&lt;br /&gt;
The following table contains the list of arguments that can be passed via the AppInfo JSON schema.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter / Argument !! Description !! Source !! Required? !! Example&lt;br /&gt;
|-&lt;br /&gt;
| appid || Unique Nielsen ID for the application. The ID is a GUID data type. If you did not receive your App ID, let us know and we will provide you. || Nielsen-specified || Yes || PXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;br /&gt;
|-&lt;br /&gt;
| nol_devDebug || Enables Nielsen console logging. Only required for testing&lt;br /&gt;
|| Nielsen-specified || Optional || &amp;quot;DEBUG&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debug flag for development environment ==&lt;br /&gt;
Player application developers / integrators can use Debug flag to check whether an App SDK API call made is successful. To activate the Debug flag,&lt;br /&gt;
Pass the argument &amp;lt;code&amp;gt;@&amp;quot;nol_devDebug&amp;quot;:@&amp;quot;INFO&amp;quot;&amp;lt;/code&amp;gt;, in the JSON string . The permitted values are:&lt;br /&gt;
&lt;br /&gt;
* '''INFO''': Displays the API calls and the input data from the application (validate player name, app ID, etc.). It can be used as certification Aid.&lt;br /&gt;
* '''WARN''': Indicates potential integration / configuration errors or SDK issues.&lt;br /&gt;
* '''ERROR''': Indicates important integration errors or non-recoverable SDK issues.&lt;br /&gt;
* '''DEBUG''': Debug logs, used by the developers to debug more complex issues.&lt;br /&gt;
&lt;br /&gt;
Once the flag is active, it logs each API call made and the data passed. The log created by this flag is minimal.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': DO NOT activate the Debug flag in a production environment.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Sample SDK Initialization Code ====&lt;br /&gt;
[[AppSDK()]] is no longer a singleton object and should be initialized as below.&lt;br /&gt;
&lt;br /&gt;
'''Initialization of App SDK object through a JSON object'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;try&lt;br /&gt;
{&lt;br /&gt;
  // Prepare AppSdk configuration object (JSONObject)&lt;br /&gt;
  JSONObject appSdkConfig = new JSONObject()&lt;br /&gt;
          .put(&amp;quot;appid&amp;quot;, &amp;quot;PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA&amp;quot;)&lt;br /&gt;
          .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;); // only for debug builds&lt;br /&gt;
&lt;br /&gt;
// Pass appSdkConfig to the AppSdk constructor&lt;br /&gt;
mAppSdk = new AppSdk(appContext, appSdkConfig, appSdkListener);&lt;br /&gt;
}&lt;br /&gt;
catch (JSONException e)&lt;br /&gt;
{&lt;br /&gt;
  Log.e(TAG, &amp;quot;Couldn’t prepare JSONObject for appSdkConfig&amp;quot;, e);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, &amp;lt;code&amp;gt;appContext&amp;lt;/code&amp;gt; is the App context object and &amp;lt;code&amp;gt;appSdkConfig&amp;lt;/code&amp;gt; is JSON object for holding the parameters (&amp;lt;code&amp;gt;appid&amp;lt;/code&amp;gt;) the App passes to the Nielsen App SDK via a JSON string. The appid is obtained from Nielsen operational support and is unique to the app.&lt;br /&gt;
&lt;br /&gt;
The integration of Nielsen App SDK will depend on type of client app.&amp;lt;br /&amp;gt;&lt;br /&gt;
* Ensure that SDK files (AppSdk.jar and libAppSdk.so [App SDK 1.2 Only]) are included under the App’s project and the App SDK is linked to the App (the setting to link App SDK to the App can be found on property page of the App’s project).&lt;br /&gt;
&lt;br /&gt;
== APP SDK Error &amp;amp; Event Codes ==&lt;br /&gt;
To view the Error and Event codes for iOS and Android, please review the [[APP SDK Event Codes|App SDK Event Code]] Reference page.&lt;br /&gt;
&lt;br /&gt;
== Configure Payload ==&lt;br /&gt;
=== Handling JSON Metadata ===&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Variable Names like appid, appname, sfcode, dataSrc, title, type etc. are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
JSONObject contentMetadata = new JSONObject()&lt;br /&gt;
//SDK Metadata&lt;br /&gt;
    .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;assetid&amp;quot;, &amp;quot;vid345-67483&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;title&amp;quot;, &amp;quot;Program S3, EP1&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;isfullepisode&amp;quot;, &amp;quot;y&amp;quot;) &lt;br /&gt;
    .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)&lt;br /&gt;
    .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentValueB&amp;quot;)  //optional&lt;br /&gt;
    .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentValueC&amp;quot;)  //optional   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Content metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Example Ad Object ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sequence of Calls ==&lt;br /&gt;
=== play ===&lt;br /&gt;
Use [[DCR_Video_APP_SDK#play|play]] to pass the channel descriptor information through channelName parameter when the user taps the '''Play''' button on the player.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    public void play(JSONObject channelInfo);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== loadMetadata ===&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void loadMetadata(JSONObject contentMetadata);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== playheadPosition ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void setPlayheadPosition(long position)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stop ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void stop()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== end ===&lt;br /&gt;
When content stop is initiated and content cannot be resumed from the same position (it can only be restarted from the beginning of stream).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;public void end()&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;[nielsenMeter play];&amp;lt;/code&amp;gt; || // call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[nielsenMeter loadMetadata: contentMetadataObject];&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;[nielsenMeter setplayheadPosition: position];&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;[nielsenMeter end];&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'setPlayheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: || current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'setPlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the Unix timestamp; for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Initial state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''setplayheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position timer is fired.  If a LIVE event, use the current Unix timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the playback is paused, switches between content and ad (within the same content playback) or encounters interruptions.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.&lt;br /&gt;
## Initialization fails&lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop()]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- &lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] &lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad-123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[setPlayheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
'''Ad Content'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;    long pos = mAdPlayer.videoPosition() / 1000;&lt;br /&gt;
   if (mAppSdk != null)&lt;br /&gt;
   {&lt;br /&gt;
     mAppSdk.setPlayheadPosition(pos);&lt;br /&gt;
   }&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: The playhead positions for ad and content should be maintained separately.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
|  rowspan=&amp;quot;1&amp;quot; | End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should reset or begin from 0 at ad start. When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handling Foreground and Background states ==&lt;br /&gt;
There are a few approaches to managing the Foreground and Background states of an app available to use for state measurement.&lt;br /&gt;
* Utilizing the Androidx LifeCycleObserver (The recommended approach starting sdk version 7.1.0.0+)&lt;br /&gt;
* Utilizing the [[DCR_Video_Android_SDK#The_SdkBgFgDetectionUtility_class|SdkBgFgDetectionUtility]] class&lt;br /&gt;
* Adding a tag to the Manifest XML&lt;br /&gt;
* Manual Management&lt;br /&gt;
=== The LifeCycleObserver ===&lt;br /&gt;
AndroidX replaces the original support library APIs with packages in the androidx namespace, and Android Studio 3.2 and higher provides an automated migration tool. (Select '''Refactor&amp;gt; Migrate to AndroidX''' from the menu bar.)&lt;br /&gt;
&lt;br /&gt;
Starting with version 7.1.0, with AndroidX support, an additional utility is provided in the AppSDK - application background/foreground state detection by the AppSdk leveraging the Android Architecture component &amp;quot;LifeCycleObserver&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The AppSdk is now capable of detecting the application UI visibility state transitions between background and foreground, without forcing the applications to register for AppSdk's AppSdkApplication class, which is responsible for handling the detection of application background/foreground state transitions at present.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Please note, that if you already have an app designed that utilizes the depreciated SdkBgFgDetectionUtility Class, the AppSDK will ignore any calls to these methods if it can utilize the LifeCycleObserver.  LifeCycleObserver based auto detection will take precedence. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
==== Adding the AndroidX dependency ====&lt;br /&gt;
In order to make use of the app background/foreground state transition auto detection feature of AndroidX AppSdk, the app gradle file needs the androidx dependency. The AppSdk API calls - &amp;lt;code&amp;gt;appInForeground()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;appInBackground()&amp;lt;/code&amp;gt;  will still be respected by AppSdk by executing the old AppSdk flow of handling &amp;quot;app in foreground&amp;quot; and &amp;quot;app in background&amp;quot; states as is.&lt;br /&gt;
&lt;br /&gt;
==== Using the LifeCycle Extension ====&lt;br /&gt;
The following androidx dependency is required in the app gradle file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
implementation &amp;quot;androidx.lifecycle:lifecycle-extensions:2.1.0&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
If you would like to take advantage of this auto detection feature of AppSdk at the very initial stage (e.g. splash screen or at of app launch time), before the AppSdk is initialized, can do so by calling the following newly introduced AppSdk public api, passing the application context :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void registerLifeCycleObserver(Context applicationContext)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Log messages for the new auto detection ====&lt;br /&gt;
&lt;br /&gt;
When the AppSdk app successfully registers for the LifeCycleObserver : &amp;lt;code&amp;gt;Registered LifeCycleObserver for App Background/Foreground auto-detection&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When the app enters the foreground state :&amp;lt;code&amp;gt;App is in foreground, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the app enters the background state :&amp;lt;code&amp;gt;App is in background, auto detected by AppSDK&amp;lt;/code&amp;gt;&lt;br /&gt;
* If the client app doesn't have the &amp;quot;androidx&amp;quot; gradle dependency and AppSdk fails to register LifeCycleObserver :&amp;lt;code&amp;gt;AndroidX LifecycleObserver can not be observed. Please use androidx dependency to activate SDK auto-detection of app background/foreground state.&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInForeground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - foreground&amp;lt;/code&amp;gt;&lt;br /&gt;
* When the appInBackground() is explicitly called while LifeCycleObserver auto detection is active :&amp;lt;code&amp;gt;Ignoring the appInBackground() call, as the App Background/Foreground auto-detection is active. The current state is - background&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The SdkBgFgDetectionUtility class ===&lt;br /&gt;
Foreground/Background state measurement is a requirement of Nielsen AppSDK implementation which is especially crucial for static measurement. It may be implemented in multiple ways for Android. This includes&lt;br /&gt;
* Enable the Nielsen SDK to measure background/foreground state by makingthe relevant update to the AndroidManifest.&lt;br /&gt;
* Integrate Nielsen’s SdkBgFgDetectionUtility class within your Custom Application Class.&lt;br /&gt;
* Custom implementation of the required methods within your application.&lt;br /&gt;
&lt;br /&gt;
==== ForeGround/Background Measurement via AndroidManifest ====&lt;br /&gt;
The simplest way to measure the app background/foreground state is to add the following application tag to the Manifest XML. Integrating this into the Manifest XML will enable the SDK to measure app state directly. This approach is supported for Android 4.0 and up only; it requires that the application class is not in use for some other purpose.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;application android:name=&amp;quot;com.nielsen.app.sdk.AppSdkApplication&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using the Android SdkBgFbDetectionUtility Class ====&lt;br /&gt;
For developers who are already using the application class, it is recommended that background/foreground state is implemented using the  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class].  The  [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] is compatible with Android 4+ and has been made available to Nielsen clients. (You will need to copy/paste the code provided into a file).&lt;br /&gt;
&lt;br /&gt;
==== Manual Background/ForeGround State Management ====&lt;br /&gt;
In cases where the developer is not able to use the AndroidManifest.xml solution nor the Nielsen provided   [https://engineeringportal.nielsen.com/docs/Android_Background_Foreground SdkBgFgDetectionUtility class] the developer will need to manually identify the change of state through the application and call the respective API (appInForeground() or appInBackground()) to inform the SDK regarding the change of state from background to foreground or foreground to background.&lt;br /&gt;
&lt;br /&gt;
The SDK is informed about app state using the below methods.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
AppLaunchMeasurementManager.appInForeground(getApplicationContext());&lt;br /&gt;
AppLaunchMeasurementManager.appInBackground(getApplicationContext());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Within the lifecycle of individual activities, onResume() and onPause() are best suited to providing indication of the app state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Correct measurement of the foreground/background state is crucial to Static App measurement within Nielsen Digital Content Ratings (DCR).&lt;br /&gt;
== Using the NielsenAppSDKJSHandler ==&lt;br /&gt;
There could be a scenario in which a browser page, that is already tagged with the Nielsen BSDK, needs to be loaded via a webview.  In this situation it is recommended to use the '''NielsenAppSDKJSHandler''' which will allow communication between the AppSDK and the BSDK. &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''This feature is supported in versions 7.2 and above.'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
* Make sure you have the latest AppSdk.jar from Nielsen&lt;br /&gt;
* Enable the javascript on webview using below lines&lt;br /&gt;
&amp;lt;br&amp;gt; &lt;br /&gt;
 &amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
WebSettings webSetting = webView.getSettings();&lt;br /&gt;
webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Add  NielsenAppSDKJSHandler instance as javascript interface to webview with name “NielsenAppSDK” like below snippet&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext()), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
This will enable listening to BSDK api calls within the APPSDK.  Please make sure your Technical Account Manager is aware that you wish to implement this method so a configuration file can be modified on the Nielsen servers; however, there are '''no changes required to the Browser page'''.&lt;br /&gt;
&lt;br /&gt;
==== Example:====&lt;br /&gt;
The below is an example of opening a webview with the NielsenAppSDKJSHandler&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
      WebSettings webSetting = webView.getSettings();&lt;br /&gt;
      webView.getSettings().setDomStorageEnabled(true); &lt;br /&gt;
      webSetting.setJavaScriptEnabled(true);&lt;br /&gt;
      webView.addJavascriptInterface(new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;), &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
      String url = &amp;quot;https://nielsen.com.index.htm&amp;quot;;&lt;br /&gt;
      webView.loadUrl(url);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;AndroidManifest.xml&amp;lt;/code&amp;gt; may need the following permissions set:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Closing NielsenAppSDKJSHandler ===&lt;br /&gt;
NielsenAppSDKJSHandler should be closed or cleaned up in below scenarios&lt;br /&gt;
* Before WebView is getting destructed&lt;br /&gt;
* Before loading new page&lt;br /&gt;
* Before closing application&lt;br /&gt;
NielsenAppSDKJSHandler provides a public interface with name &amp;quot;close()&amp;quot; and this function should be called on NielsenAppSDKJSHandler's instance in all above scenarios.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;&lt;br /&gt;
// get your webview&lt;br /&gt;
WebView webView = findViewById(R.id.webView);&lt;br /&gt;
 &lt;br /&gt;
//Added JS Handler instance as java script interface for ggpm api type&lt;br /&gt;
NielsenAppSDKJSHandler jshandler = new NielsenAppSDKJSHandler(getApplicationContext(), &amp;quot;&amp;quot;);&lt;br /&gt;
webView.addJavascriptInterface(jshandler, &amp;quot;NielsenAppSDK&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
//Close JS Handler before making webview as null&lt;br /&gt;
jshandler.close();&lt;br /&gt;
webView = null;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Interruptions during playback ==&lt;br /&gt;
As part of integrating Nielsen App SDK with the player application, the Video app developer needs to handle the following possible interruption scenarios:&lt;br /&gt;
* Pause / Play&lt;br /&gt;
* Network Loss (Wi-Fi / Airplane / Cellular)&lt;br /&gt;
* Call Interrupt (SIM or Third party Skype / Hangout call)&lt;br /&gt;
* Alarm Interrupt&lt;br /&gt;
* Content Buffering&lt;br /&gt;
* Device Lock / Unlock &lt;br /&gt;
* App going in the Background/Foreground&lt;br /&gt;
* Channel / Station Change Scenario&lt;br /&gt;
* Unplugging of headphone&lt;br /&gt;
In case of encountering one of the above interruptions, the player application needs to&lt;br /&gt;
* Call [[stop()]] immediately (except when content is buffering) and withhold sending playhead position.&lt;br /&gt;
* Start sending pings – &amp;lt;code&amp;gt;'loadMetadata'&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'playheadPosition'&amp;lt;/code&amp;gt; for the new viewing session, once the playback resumes.&lt;br /&gt;
Please see the [https://engineeringportal.nielsen.com/docs/Digital_Measurement_Interruption_Scenarios Interruption Scenarios Page] for more details&lt;br /&gt;
&lt;br /&gt;
== Pre-Certification Checklists ==&lt;br /&gt;
After the application is ready to be sent for Nielsen Certification, please go through the [[Digital Pre-Certification Checklist App SDK]] and ensure the app behaves as expected, before submitting to Nielsen.&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK:&lt;br /&gt;
# '''[[#Global_Android_SDK_Opt-out|Global Android SDK Opt-out]]''' - managed by ''Opt out of Ads Personalization'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global_Android_SDK_No_Ad_Framework_Optout|Global Android SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without Google Play Services or when using the noAd version of the SDK.&lt;br /&gt;
# '''[[#Global_Android_SDK_No_ID_Optout_.28Kids_Category.29|Global Android SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen Android when the [https://developers.google.com/android/guides/setup Google Play services APIs] have been setup in your project.&lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the Android's '''Opt out of Ads Personalization''' setting. The user is opted out of demographic measurement if the OS-level '''Opt out of Ads Personalization''' setting is ''enabled''. As a publisher, you cannot override this setting.&lt;br /&gt;
&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global Android SDK, this optOutURL informs the user how to deactivate/activate “Out of Ads Personalization”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;'''Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information'''&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No Ad Framework Optout ===&lt;br /&gt;
The ''No Ad Framework Optout'' can be used when the host application does not leverage Google Play Services such as when using the noAd version or the NoID version.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Nielsen Android SDK 5.1.1.18 and above will check for ''OS-level opt-out'' first, if available. The user will be opted out if indicated at the OS-level '''OR''' the App-level.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The No Ad Framework Optout method works as follows: ====&lt;br /&gt;
* Get the current Nielsen opt-out URL via [[userOptOutURLString()]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[userOptOutURLString()]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut()]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global Android SDK No ID Optout (Kids_Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the NoID version of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=java&amp;gt;appSdk.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;);  // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OptOut Example Code ==&lt;br /&gt;
Below you will find some sample code for the:&lt;br /&gt;
* [[#Global OptOut Example|Global Android SDK]] - managed by Opt out of Ads Personalization setting on device '''(preferred approach)'''.&lt;br /&gt;
* [[#No_Ad_Framework_Optout_Sample_Code|Global Android noAd Framework]] - Use if Google Play APIs are unavailable or running noAd version.&lt;br /&gt;
*  It is currently not required to display an OptOut page for the NoID/Kids Build of the SDK.&lt;br /&gt;
===&amp;lt;span id=&amp;quot;Global OptOut Example&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Global OptOut Example ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user.  Please see the next section if using the No Ad Framework build&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;span id=&amp;quot;No Ad Framework Optout Sample Code&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;No Ad Framework Optout Sample Code ===&lt;br /&gt;
The below code is an AndroidX example of displaying the Nielsen Privacy page to the user with the No Ad Framework SDK Build.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class OptOutActivity extends AppCompatActivity implements IAppNotifier {&lt;br /&gt;
&lt;br /&gt;
    WebView webView;&lt;br /&gt;
    AppSdk appSdk;&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onCreate(@Nullable Bundle savedInstanceState) {&lt;br /&gt;
        super.onCreate(savedInstanceState);&lt;br /&gt;
        setContentView(R.layout.activity_optout);&lt;br /&gt;
        webView = (WebView) findViewById(R.id.webView);&lt;br /&gt;
        webView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;
&lt;br /&gt;
        webView.setWebViewClient(new WebViewClient() {&lt;br /&gt;
            @SuppressWarnings(&amp;quot;deprecation&amp;quot;)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {&lt;br /&gt;
                Toast.makeText(OptOutActivity.this, description, Toast.LENGTH_SHORT).show();&lt;br /&gt;
            }&lt;br /&gt;
            @TargetApi(android.os.Build.VERSION_CODES.M)&lt;br /&gt;
            @Override&lt;br /&gt;
            public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {&lt;br /&gt;
                // Redirect to deprecated method, so you can use it in all SDK versions&lt;br /&gt;
                onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
            @Override&lt;br /&gt;
            public boolean shouldOverrideUrlLoading(WebView view, String url) {&lt;br /&gt;
&lt;br /&gt;
                if(url.contains(&amp;quot;nielsen&amp;quot;)){&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://1 it means the user selected Opt Out&lt;br /&gt;
                    // If url value = &amp;quot;nielsenappsdk://0&amp;quot; it means the user selected Opt-In&lt;br /&gt;
                    appSdk.userOptOut(url);&lt;br /&gt;
                }&lt;br /&gt;
                return true;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        });&lt;br /&gt;
        String url = appSdk.userOptOutURLString();   // Request Optout URL from NielsenSDK&lt;br /&gt;
        webView.loadUrl(url);                         //Display to the user in a Webview&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    public void onBackPressed() {&lt;br /&gt;
        super.onBackPressed();&lt;br /&gt;
        mSdkInterface.getSDK(appSdk);&lt;br /&gt;
    }&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void onDestroy() {&lt;br /&gt;
        super.onDestroy();&lt;br /&gt;
        if (appSdk != null)&lt;br /&gt;
        {&lt;br /&gt;
            appSdk.close();&lt;br /&gt;
            appSdk = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Required Privacy Links ===&lt;br /&gt;
Users must either have access to the &amp;quot;About Nielsen Measurement&amp;quot; page, or have similar text available within the native app. Include &amp;quot;About Nielsen Measurement&amp;quot; and &amp;quot;Your Choices&amp;quot; link in the Privacy Policy / EULA or as a button near the link to the app's Privacy Policy.&lt;br /&gt;
&lt;br /&gt;
In addition, the following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
'''&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;'''&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via App-level Opt-out, the current Opt-Out status as detected by the SDK is available via the [[getOptOutStatus()]] property in the Nielsen Android SDK API. &amp;lt;code&amp;gt;appSdk.getOptOutStatus()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Going Live ==&lt;br /&gt;
Following Nielsen testing, you will need to:&lt;br /&gt;
&lt;br /&gt;
# '''Disable Debug Logging''': Disable logging by deleting &amp;lt;code&amp;gt;{nol_devDebug: 'DEBUG'}&amp;lt;/code&amp;gt; from initialization call.&lt;br /&gt;
# '''Notify Nielsen''': Once you are ready to go live, let us know so we can enable you for reporting. We will not be able to collect or report data prior to receiving notification from you.&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen  API using a standard no-frills player.&lt;br /&gt;
** [[Android Basic example|Android Studio Example]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen API integrated into a custom video player is bundled with the SDK.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_iOS_SDK&amp;diff=5482</id>
		<title>DCR Taiwan Video iOS SDK</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=DCR_Taiwan_Video_iOS_SDK&amp;diff=5482"/>
		<updated>2021-11-03T04:41:16Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: Created page with &amp;quot;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}} {{CurrentBreadcrumb}} Category:Digital  == Overview == The Nielsen SDK is one of multiple framework SDK...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{Breadcrumb|International}} {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc.&lt;br /&gt;
The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:&lt;br /&gt;
*Application launch events and how long app was running&lt;br /&gt;
*Time of viewing a sub section / page in the application.&lt;br /&gt;
&lt;br /&gt;
This guide covers implementation steps for iOS using Xcode utilizing the Standard Nielsen SDK for DCR.&lt;br /&gt;
&lt;br /&gt;
{{iOS_SpecialNotes_for_iOS14}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Prerequisites_and_Implementation_Overview}}&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Setting up your  Development Environment  ==&lt;br /&gt;
Prior to SDK Version 6.2.0.0 the  IOS framework has been distributed as a static library packaged into framework bundle format. Apple recommends to use dynamic framework, it has some benefits over static libraries like less executable file size of an app, faster startup time and native support in xCode IDE. Nielsen AppSDK has been transformed into dynamic framework in this release ([[iOS_Static_Framework_Setup|static framework]] is still available).&lt;br /&gt;
&lt;br /&gt;
If migrating from the static library to this new dynamic framework, once implemented, unless your specific application requires, you can remove the following Frameworks that were once required:&amp;lt;code&amp;gt; [AdSupport, JavascriptCore, SystemConfiguration, Security, AVFoundation, libc++] &amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The '''Dynamic framework''' is created as a fat framework. It means that it contains slices required for devices (armv7, arm64) as well as slices required for simulators (i386, x86_64). Simulator slices are needed to let clients build and debug their app on the simulators, but they should be removed before sending the app to the AppStore. The example of the shell script that should be added as a Run Script phase in the application can be [[DCR_Taiwan_Video_iOS_SDK#Removing_Simulators_.28Dynamic_Framework_Only.29|found below]].&lt;br /&gt;
&lt;br /&gt;
'''[[DCR_Video_iOS_SDK_xcframework|XCFramework]]''' is solution for the problems described above Apple recommends to use XCFrameworks. In XCFramework, we no longer build a single framework with multiple architectures. Instead, we build one small framework for each combination of architecture and target and store it in its own folder. The top-level XCFramework folder have folders like ios-arm64, ios-arm64-simulator, etc. Each of these folders is its own framework, complete with headers, modules, and binary.&lt;br /&gt;
&lt;br /&gt;
=== Configuring Xcode Development Environment ===&lt;br /&gt;
Starting with SDK version 6.0.0.0, the Nielsen App SDK is compatible with Apple iOS versions 8.0 and above.  In addition, when using the dynamic framework,  all the required frameworks are linked automatically as the are needed.  More details can be found here: https://stackoverflow.com/questions/24902787/dont-we-need-to-link-framework-to-xcode-project-anymore&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note''': All communications between the SDK and the Census (Collection Facility) use HTTPS.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Download Framework ===&lt;br /&gt;
The first step is to download and copy the [[Special:Downloads|NielsenAppApi.framework]] bundle to the app project directory. (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Framework ===&lt;br /&gt;
In the General tab for app configuration add NielsenAppApi.framework in the list of Embedded Binaries.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Add Path ===&lt;br /&gt;
Add path to the NielsenAppApi.framework in the Framework Search Paths build setting.  (''Not required if using CocaPods'')&lt;br /&gt;
&lt;br /&gt;
=== Import Framework ===&lt;br /&gt;
Add NielsenAppApi.framework module in the source file of your app:&lt;br /&gt;
&lt;br /&gt;
==== Using Swift ====&lt;br /&gt;
Add the following:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Using Objective-C ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@import NielsenAppApi;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_SDK_Initialization}}&lt;br /&gt;
&lt;br /&gt;
== Configure Metadata ==&lt;br /&gt;
All the SDK methods handles only two types of objects: NSString, NSDictionary. The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.&lt;br /&gt;
* NSDictionary object&lt;br /&gt;
** If an object of unexpected type is passed to the method, the error message will be logged.&lt;br /&gt;
** If string has invalid JSON format, the error message will be logged.&lt;br /&gt;
* JSON value must be string value.&lt;br /&gt;
** This includes boolean and numeric values. For example, a value of true should be represented with &amp;quot;true&amp;quot;, number value 123 should be &amp;quot;123&amp;quot;.&lt;br /&gt;
** All the Nielsen Key names (e.g. appid, program) are case-sensitive. Use the correct variable name as specified in the documentation.&lt;br /&gt;
* JSON string can be prepared using either raw NSString or serialized NSDictionary.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Create channelName Metadata ===&lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| Any string representing the channel/stream	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
=== Create Content Metadata ===&lt;br /&gt;
Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.&lt;br /&gt;
&amp;lt;blockquote&amp;gt; program and title metadata values should be passed to SDK as UTF-8 strings. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| clientid	|| &lt;br /&gt;
parent ID – value is automatically populated through provided App ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to override the brand configured to the App ID, pass parent &amp;lt;br/&amp;gt;&lt;br /&gt;
value here and the sub-brand ID associated to that brand in the subbrand &amp;lt;br/&amp;gt;&lt;br /&gt;
key (e.g. multiple brands in App)	&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| subbrand	|| sub-brand ID – value is automatically populated through provided&amp;lt;br/&amp;gt;&lt;br /&gt;
App ID. In order to override the sub-brand configured to the App ID, value can &amp;lt;br/&amp;gt;&lt;br /&gt;
be passed here (e.g. multiple sub-brands in App)&lt;br /&gt;
||&lt;br /&gt;
Nielsen provided	&lt;br /&gt;
||&lt;br /&gt;
|-&lt;br /&gt;
| type ||	type of asset	|| &amp;quot;content&amp;quot;	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid	|| unique ID assigned to asset 	|| custom&amp;lt;br&amp;gt;(no [[Special Characters]]). The Content ID should be populated here which should correspond to the same value in the post transmission logs. || ✓&lt;br /&gt;
|-&lt;br /&gt;
| program	|| name of program 	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| title	|| episode name	|| custom	|| ✓&lt;br /&gt;
|-&lt;br /&gt;
| length	|| length of content in seconds	|| seconds (86400 for live stream)||	✓&lt;br /&gt;
|-&lt;br /&gt;
| segB	|| custom segment B. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	||&lt;br /&gt;
|-&lt;br /&gt;
| segC	|| custom segment C. Custom segments can be used to aggregate content however you choose. Some examples include genre, category, or platform.	|| custom	 ||&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| isfullepisode	|| full episode flag ||	&lt;br /&gt;
*'y', 'yes', or 'lf' – full episode&lt;br /&gt;
*'n', 'no', or 'sf' – non full episode	&lt;br /&gt;
'''Note:''' For livestream content with Dynamic Ad Insertion (DAI), the isfullepisode value should be set to 'y'. &lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|adloadtype	|| type of Ad load:&lt;br /&gt;
* 1) Linear – matches TV Ad load. Content with linear Ad Load is not eligible for DCR measurement and will not be included in DCR reporting.&lt;br /&gt;
* 2) Dynamic – Dynamic Ad Insertion (DAI)&lt;br /&gt;
||&lt;br /&gt;
*&amp;quot;1&amp;quot; – content with linear Ads. Note: Content with linear Ad load is not included in DCR measurement. &lt;br /&gt;
*&amp;quot;2&amp;quot; – content with dynamic Ads	&lt;br /&gt;
||&lt;br /&gt;
✓&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Metadata Example ====&lt;br /&gt;
&amp;lt;code&amp;gt;Swift&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
let contentMetadata = [&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
    &amp;quot;assetid&amp;quot;: &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Program S2, E3&amp;quot;,&lt;br /&gt;
    &amp;quot;isfullepisode&amp;quot;: &amp;quot;y&amp;quot;,&lt;br /&gt;
    &amp;quot;program&amp;quot;: &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
    &amp;quot;adloadtype&amp;quot;: &amp;quot;2&amp;quot;,&lt;br /&gt;
    &amp;quot;segB&amp;quot;: &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    &amp;quot;segC&amp;quot;: &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Objective-C&amp;lt;/code&amp;gt;    &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt; &lt;br /&gt;
NSDictionary * contentMetadata = @ {&lt;br /&gt;
    @ &amp;quot;type&amp;quot;: @ &amp;quot;content&amp;quot;,&lt;br /&gt;
    @ &amp;quot;assetid&amp;quot;: @ &amp;quot;C77664&amp;quot;,&lt;br /&gt;
    @ &amp;quot;title&amp;quot;: @ &amp;quot;S2,E3&amp;quot;,&lt;br /&gt;
    @ &amp;quot;isfullepisode&amp;quot;: @ &amp;quot;y&amp;quot;,  &lt;br /&gt;
    @ &amp;quot;program&amp;quot;: @ &amp;quot;Program Name&amp;quot;,&lt;br /&gt;
    @ &amp;quot;length&amp;quot;: @ &amp;quot;3600&amp;quot;,&lt;br /&gt;
    @ &amp;quot;adloadtype&amp;quot;: @ &amp;quot;2&amp;quot;,&lt;br /&gt;
    @ &amp;quot;segB&amp;quot;: @ &amp;quot;CustomSegmentValueB&amp;quot;, //optional&lt;br /&gt;
    @ &amp;quot;segC&amp;quot;: @ &amp;quot;CustomSegmentValueC&amp;quot;, //optional&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Configure metadata === &lt;br /&gt;
channelName should remain constant throughout the completion of an episode or live stream.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Description !!	Values	 !! Required&lt;br /&gt;
|-&lt;br /&gt;
| channelName	|| ChannelInfo refers to the Channel name. This can be a free-form value&lt;br /&gt;
value such as a friendly name for the content being played. the SDK&amp;lt;br/&amp;gt;&lt;br /&gt;
will pass the application name automatically.&lt;br /&gt;
|| custom	|| No&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ad Metadata ===&lt;br /&gt;
The Ad Metadata (if applicable) should be passed for each individual ad.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keys	!! Description	!! Values	!! Required&lt;br /&gt;
|-&lt;br /&gt;
| type 	|| type of Ad	||  &amp;lt;code&amp;gt;'preroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'midroll'&amp;lt;/code&amp;gt;,  &amp;lt;code&amp;gt;'postroll'&amp;lt;/code&amp;gt; &amp;lt;br&amp;gt; &amp;lt;code&amp;gt;'ad'&amp;lt;/code&amp;gt;  - If specific type can not be identified.||	✓&lt;br /&gt;
|-&lt;br /&gt;
| assetid ||	unique ID assigned to Ad	|| custom &amp;lt;br&amp;gt;(no [[Special Characters]])	|| ✓&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Example Ad Object ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// create Ad object&lt;br /&gt;
&amp;quot;ad&amp;quot;: {&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;AD-ID123&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_LifeCycle_of_SDK}}&lt;br /&gt;
&lt;br /&gt;
== Configure API Calls ==&lt;br /&gt;
&amp;lt;!--[[File:appsdkTimeline-DCR.png|icon|link=]]--&amp;gt;&lt;br /&gt;
=== Sample API Sequence ===&lt;br /&gt;
A Sample API sequence could follow this flow:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;nielsenMeter.play()&amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nielsenMeter.loadMetadata(contentMetadata)&amp;lt;/code&amp;gt; || // MetadataObject contains the JSON metadata&amp;lt;br&amp;gt; for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;nielsenMeter.playheadPosition(pos);&amp;lt;/code&amp;gt; || // playheadPosition is position of the playhead &amp;lt;br&amp;gt;while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;nielsenMeter.end()&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== SDK Events ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event !!	Parameter	!! Description&lt;br /&gt;
|-&lt;br /&gt;
| 'play'	|| 	|| Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| 'loadMetadata'	|| content/ad metadata object	|| Needs to be called at the beginning of each asset&lt;br /&gt;
|-&lt;br /&gt;
| 'playheadPosition'	|| playhead position as integer&amp;lt;br/&amp;gt;&lt;br /&gt;
VOD: current position in seconds &amp;lt;br/&amp;gt;&lt;br /&gt;
Live: current UNIX timestamp (seconds since Jan-1-1970 UTC) &amp;lt;br/&amp;gt;&lt;br /&gt;
Note: 'PlayheadPosition' has to be called every second&lt;br /&gt;
||&lt;br /&gt;
Pass playhead position every second during playback&lt;br /&gt;
|-&lt;br /&gt;
| 'stop' ||	playhead position	|| Call during any interruption to content or Ad playback and at the end of each Ad.&lt;br /&gt;
|-&lt;br /&gt;
| 'end'	|| playhead position in seconds	|| Call when the current video asset completes playback and pass the playhead position. &amp;lt;br/&amp;gt;&lt;br /&gt;
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: For livestream, send the UNIX timestamp, for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; or&amp;lt;code&amp;gt; '''loadmetadata'''&amp;lt;/code&amp;gt;,.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Life cycle of SDK instance ===&lt;br /&gt;
Life cycle of SDK instance includes four general states:&lt;br /&gt;
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Idle state'''.&lt;br /&gt;
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for an event to occur.&lt;br /&gt;
# '''Processing state''' – The SDK instance is processing playing information. The &amp;lt;code&amp;gt;'''play'''&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.&lt;br /&gt;
## &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; – Call this API every one second when playhead position is active.  If a LIVE event, use the current UNIX timestamp (seconds since Jan-1-1970 UTC).&lt;br /&gt;
## &amp;lt;code&amp;gt;'''stop'''&amp;lt;/code&amp;gt; – Call this API when the content or Ad playback is interrupted and at the end of each Ad. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''end'''&amp;lt;/code&amp;gt; – Call when content completes. When called, the SDK instance exits from Processing state.&lt;br /&gt;
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. &lt;br /&gt;
## &amp;lt;code&amp;gt;'''appDisableApi'''&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.&lt;br /&gt;
&lt;br /&gt;
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop]] to stop the measurement.&lt;br /&gt;
* As soon as the playback resumes, call &amp;lt;code&amp;gt;'''loadMetadata''' &amp;lt;/code&amp;gt; and   &amp;lt;code&amp;gt;'''playheadPosition'''&amp;lt;/code&amp;gt; &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== API Call Sequence ===&lt;br /&gt;
==== Use Case 1: Content has no Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for content as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
  &amp;quot;type&amp;quot;: &amp;quot;content&amp;quot;,&lt;br /&gt;
  &amp;quot;assetid&amp;quot;: &amp;quot;vid345-67483&amp;quot;,&lt;br /&gt;
  &amp;quot;program&amp;quot;: &amp;quot;ProgramName&amp;quot;,&lt;br /&gt;
  &amp;quot;title&amp;quot;: &amp;quot;Program S3, EP1&amp;quot;,&lt;br /&gt;
  &amp;quot;length&amp;quot;: &amp;quot;3600&amp;quot;,&lt;br /&gt;
  ...&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop.&lt;br /&gt;
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // Call at start of each new stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| Content || &amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| Interruption || &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // call stop when content playback is interrupted&lt;br /&gt;
|-style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Resume Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt;  || // Call loadMetadata and pass content metadata object when content resumes&lt;br /&gt;
|- style=&amp;quot;background-color:#d8f5d7;&amp;quot;&lt;br /&gt;
|&amp;lt;code&amp;gt;mAppSdk.setPlayheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // continue pasing playhead position every second starting from position where content is resumed&lt;br /&gt;
|- &lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Content playback is completed.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Use Case 2: Content has Advertisements ====&lt;br /&gt;
Call [[play()]] at start of stream&lt;br /&gt;
&lt;br /&gt;
Call [[loadMetadata()]] with JSON metadata for ad as below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;{&lt;br /&gt;
   &amp;quot;type&amp;quot;: &amp;quot;preroll&amp;quot;,&lt;br /&gt;
   &amp;quot;assetid&amp;quot;: &amp;quot;ad123&amp;quot;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: In case the individual ad details are not available, send ad pod (presence) details through the [[loadMetadata]] and playhead position through [[playheadPosition]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Call [[playheadPosition|playheadPosition()]] every one second until a pause / stop / another [[loadMetadata()]] is called. Playhead should be passed for the entire duration of ad pod, if the ad pod details are passed as part of [[loadMetadata()]].&lt;br /&gt;
&lt;br /&gt;
The sample API sequence can be used as a reference to identify the specific events that need to be called during content and ad playback.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type !! Sample code !! Description&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Start of stream || &amp;lt;code&amp;gt;mAppSdk.play(); &amp;lt;/code&amp;gt; || // stream starts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Preroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(prerollMetadataObject);&amp;lt;/code&amp;gt; || // prerollMetadataObject contains the JSON metadata for the preroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the preroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after preroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Midroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(midrollMetaDataObject);&amp;lt;/code&amp;gt; || // midrollMetadataObject contains the JSON metadata for the midroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the midroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after midroll occurs&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | Content Resumes || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(contentMetaDataObject);&amp;lt;/code&amp;gt; || // contentMetadataObject contains the JSON metadata for the content being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the content is being played&lt;br /&gt;
|-&lt;br /&gt;
| End of Stream || &amp;lt;code&amp;gt;mAppSdk.end();&amp;lt;/code&amp;gt; || // Call end() at the end of content&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | Postroll || &amp;lt;code&amp;gt;mAppSdk.loadMetadata(postrollMetaDataObject);&amp;lt;/code&amp;gt; || // postrollMetadataObject contains the JSON metadata for the postroll ad&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.playheadPosition(playheadPosition);&amp;lt;/code&amp;gt; || // position is position of the playhead while the postroll ad is being played&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mAppSdk.stop();&amp;lt;/code&amp;gt; || // Call stop after postroll occurs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Note: Each Ad playhead should begin from 0 at ad start.  When content has resumed following an ad break, playhead position must continue from where previous content segment was left off.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Sequence_of_Calls}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Foreground_and_Background}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Interuptions_during_Playback}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_NielsenAppSDKJSHandler}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_PreCertification_Checklists}}&lt;br /&gt;
&lt;br /&gt;
== Privacy and Opt-Out ==&lt;br /&gt;
&lt;br /&gt;
There are currently 3 flavors of the Nielsen SDK: &lt;br /&gt;
# '''[[#Global iOS SDK|Global iOS SDK Opt-out]]''' - managed by ''AppTracking'' or ''Limit Ad Tracking'' setting on device ('''preferred approach''').&lt;br /&gt;
# '''[[#Global iOS SDK No Ad Framework|Global iOS SDK No Ad Framework Optout]]''' - Direct call to SDK. Can be used without the Ad Framework&lt;br /&gt;
# '''[[#Global iOS SDK No ID|Global iOS SDK No ID Optout]]''' - Direct call to SDK. Should be used for Kids Category.&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK Opt-out ===&lt;br /&gt;
''OS-level Opt-out'' method available on Nielsen iOS &lt;br /&gt;
&lt;br /&gt;
The Nielsen SDK automatically leverages the iOS's '''Limit Ad Tracking''' or '''AppTracking''' setting. &lt;br /&gt;
*  If the User's device is running &amp;lt; iOS 13.x, the Nielsen SDK will check the status of '''Limit Ad Tracking'''.&lt;br /&gt;
*  iOS14 modifies the way Apple manages the collection of a User's Opt-In status through '''AppTracking'''. Starting with Version 8.x+, the Nielsen App SDK will check the iOS version during initialization. If the device is running iOS12 or iOS13, the Limit Ad Tracking setting is requested. If iOS14.x +, then AppTracking is utilized.&lt;br /&gt;
==== Webview Element ====&lt;br /&gt;
It is a requirement to display a WebView element whose loadUrl is set to the value obtained from optOutURL.&lt;br /&gt;
If using the Global iOS SDK, this optOutURL informs the user how to deactivate/activate “App Tracking/Limit Ad Tracking”.&lt;br /&gt;
&lt;br /&gt;
In addition, The following text must be included in your app store description.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;Please note: This app features Nielsen’s proprietary measurement software which contributes to market research, like Nielsen’s Digital Content Ratings. Please see https://www.nielsen.com/tw/en/legal/privacy-statement/digital-measurement/ for more information&amp;quot;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No Ad Framework Optout ===&lt;br /&gt;
The ''User Choice'' method can be used without the Ad Framework, or in situations where the publisher does not wish to use the [https://developer.apple.com/documentation/apptrackingtransparency App Tracking Transparency Framework]. As this flavor of the Nielsen SDK does not use the Ad Framework, so it is necessary to display an Optout Page to the userand capture their selection.&lt;br /&gt;
&lt;br /&gt;
Similar to the Global iOS SDK Flavor, it is a requirement to display a WebView element whose loadUrl is set to the&lt;br /&gt;
value obtained from optOutURL. This is a special URL that indicates Opt-in, or Opt-out and close the WebView.&lt;br /&gt;
&lt;br /&gt;
==== This opt-out method works as follows: ====&lt;br /&gt;
* Get the Nielsen opt-out URL via [[optOutURL]]&lt;br /&gt;
* Display a WebView element whose loadUrl is set to the value obtained from [[optOutURL]]&lt;br /&gt;
* Detect if the WebView URL changes to a special URL that indicates Opt-in, or Opt-out and close the WebView&lt;br /&gt;
** Opt-out if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://1&amp;lt;/code&amp;gt;&lt;br /&gt;
** Opt-in if the WebView URL = &amp;lt;code&amp;gt;nielsenappsdk://0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Pass the detected URL to the [[userOptOut]] function&lt;br /&gt;
** Example: &amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Global iOS SDK No ID Optout (Kids Category) ===&lt;br /&gt;
If you are building an app that will be listed in the Kids Category:&lt;br /&gt;
#  Ensure that you are using the [https://nielsendownloads-green.digitalengsdk.com/digital/Nielsen-iOS-App-SDK-GlobalNoId_latest.zip NoID version] of the Nielsen SDK Framework.&lt;br /&gt;
#  Immediately following the initialization of the Nielsen SDK ensure you call the userOptOut API with Opt out selection: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=swift&amp;gt;NielsenAppApi?.userOptOut(&amp;quot;nielsenappsdk://1&amp;quot;); // User opt-out&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Opt-out example code ==&lt;br /&gt;
===== Swift =====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;swift&amp;quot;&amp;gt;&lt;br /&gt;
import UIKit&lt;br /&gt;
import WebKit&lt;br /&gt;
import NielsenAppApi&lt;br /&gt;
&lt;br /&gt;
class OptOutVC: UIViewController, NielsenAppApiDelegate, WKNavigationDelegate {&lt;br /&gt;
    var nielsenApi : NielsenAppApi!&lt;br /&gt;
    var webView: WKWebView!&lt;br /&gt;
   &lt;br /&gt;
    override func loadView() {&lt;br /&gt;
        webView = WKWebView()&lt;br /&gt;
        webView.navigationDelegate = self&lt;br /&gt;
        view = webView&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    override func viewDidLoad() {&lt;br /&gt;
        super.viewDidLoad()&lt;br /&gt;
&lt;br /&gt;
        if let appApi = self.nielsenApi {&lt;br /&gt;
            //Getting the optPut URL from SDK&lt;br /&gt;
            if let url = URL(string: appApi.optOutURL) {&lt;br /&gt;
                webView.load(URLRequest(url: url))&lt;br /&gt;
                webView.allowsBackForwardNavigationGestures = true&lt;br /&gt;
            }}}&lt;br /&gt;
&lt;br /&gt;
        func closeOptOutView() {&lt;br /&gt;
            self.dismiss(animated: true, completion: nil)&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
// Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.  This will receive the user's selection&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*  &lt;br /&gt;
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: &lt;br /&gt;
@escaping (WKNavigationActionPolicy) -&amp;gt; Void) {&lt;br /&gt;
            print(navigationAction.request.url?.absoluteString as Any) //For debugging to check what is being passed from webpage.&lt;br /&gt;
            if navigationAction.request.url?.absoluteString == &amp;quot;nielsen://close&amp;quot; {&lt;br /&gt;
                closeOptOutView()&lt;br /&gt;
                decisionHandler(.cancel)&lt;br /&gt;
            } else {&lt;br /&gt;
                if let url = navigationAction.request.url?.absoluteString, url.hasPrefix(&amp;quot;nielsen&amp;quot;) {&lt;br /&gt;
                    nielsenApi?.userOptOut(url). //either nielsenappsdk://1 or nielsenappsdk://0&lt;br /&gt;
                    decisionHandler(.cancel)&lt;br /&gt;
                } else {&lt;br /&gt;
                    if navigationAction.navigationType == .linkActivated {&lt;br /&gt;
                        if let url = navigationAction.request.url?.absoluteString, url.hasSuffix(&amp;quot;#&amp;quot;) {&lt;br /&gt;
                            decisionHandler(.allow)&lt;br /&gt;
                        } else {&lt;br /&gt;
                            decisionHandler(.cancel)&lt;br /&gt;
                            webView.load(navigationAction.request)&lt;br /&gt;
                        }&lt;br /&gt;
                    } else {&lt;br /&gt;
                        decisionHandler(.allow)&lt;br /&gt;
                    }}}}&lt;br /&gt;
  */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===== Objective-C =====&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#import &amp;quot;OptOutVC.h&amp;quot;&lt;br /&gt;
#import &amp;quot;NielsenInit.h&amp;quot;&lt;br /&gt;
#import &amp;lt;NielsenAppApi/NielsenAppApi.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@interface OptOutVC ()&lt;br /&gt;
&lt;br /&gt;
@property (weak, nonatomic) IBOutlet UIWebView *webView;&lt;br /&gt;
@end&lt;br /&gt;
&lt;br /&gt;
@implementation OptOutVC&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
&lt;br /&gt;
- (void)viewDidLoad {&lt;br /&gt;
    [super viewDidLoad];&lt;br /&gt;
    //Getting the optPut URL from eventTracker&lt;br /&gt;
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL&lt;br /&gt;
 URLWithString:self.nielsenApi.optOutURL]]];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//Uncomment below code if you are using the Global iOS SDK No Ad Framework Flavor.&lt;br /&gt;
// From the custom User_Choice opt out page.  Only required for non-ad framework or no-id builds&lt;br /&gt;
// of the Nielsen SDK&lt;br /&gt;
/*     &lt;br /&gt;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction&lt;br /&gt;
 decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler&lt;br /&gt;
{&lt;br /&gt;
    if ([navigationAction.request.URL.absoluteString isEqualToString:kNielsenWebClose])&lt;br /&gt;
    {   [self performSelector:@selector(closeOptOutView) withObject:nil afterDelay:0];&lt;br /&gt;
        decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
     } else {&lt;br /&gt;
        if ([navigationAction.request.URL.absoluteString hasPrefix:@&amp;quot;nielsen&amp;quot;])&lt;br /&gt;
        {[self.nielsenAppApi userOptOut:navigationAction.request.URL.absoluteString];&lt;br /&gt;
            decisionHandler(WKNavigationActionPolicyCancel); &lt;br /&gt;
        } else {&lt;br /&gt;
            if (navigationAction.navigationType == WKNavigationTypeLinkActivated) &lt;br /&gt;
            { if ([navigationAction.request.URL.absoluteString hasSuffix:@&amp;quot;#&amp;quot;]) &lt;br /&gt;
                      {decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
                } else {&lt;br /&gt;
                    decisionHandler(WKNavigationActionPolicyCancel);&lt;br /&gt;
                    [webView loadRequest:[NSURLRequest requestWithURL:navigationAction.request.URL]];&lt;br /&gt;
                }} else {&lt;br /&gt;
                 decisionHandler(WKNavigationActionPolicyAllow);&lt;br /&gt;
            }}}&lt;br /&gt;
*/&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Retrieve current Opt-Out preference ==&lt;br /&gt;
Whether the user is opted out via OS-level Opt-out or via User Choice Opt-out, the current Opt-Out status as detected by the SDK is available via the [[optOutStatus]] property in the Nielsen SDK API&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objective-c&amp;quot;&amp;gt;&lt;br /&gt;
@property (readonly) BOOL optOutStatus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{iOS_Airplay}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Going_Live}}&lt;br /&gt;
&lt;br /&gt;
{{iOS_Removing_Simulator_Slices}}&lt;br /&gt;
&lt;br /&gt;
== Sample Applications ==&lt;br /&gt;
The below sample applications have been designed to show the Simplified API's functionality and are broken into two distinct categories:&lt;br /&gt;
* '''Basic''' - To show the functionality of the Nielsen Simplified API using a standard no-frills player.&lt;br /&gt;
** [[Swift Basic Sample|Swift 5.0 Sample]]&lt;br /&gt;
** [[Objective-c Basic example|Objective-C Sample]]&lt;br /&gt;
&lt;br /&gt;
* '''Advanced''' - Nielsen Simplified API integrated into a custom video player.&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=File:TWFlagIcon.png&amp;diff=5481</id>
		<title>File:TWFlagIcon.png</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=File:TWFlagIcon.png&amp;diff=5481"/>
		<updated>2021-11-03T04:16:32Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
	<entry>
		<id>https://engineeringportal.nielsen.com/w/index.php?title=International_DCR&amp;diff=5480</id>
		<title>International DCR</title>
		<link rel="alternate" type="text/html" href="https://engineeringportal.nielsen.com/w/index.php?title=International_DCR&amp;diff=5480"/>
		<updated>2021-11-03T04:13:29Z</updated>

		<summary type="html">&lt;p&gt;BryanLim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}} {{CurrentBreadcrumb}}&lt;br /&gt;
[[Category:Digital]]&lt;br /&gt;
{{CategoryIcon|International.png|International DCR}}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Please contact your Nielsen representative for documentation if the guides for your country aren't listed.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! colspan=&amp;quot;5&amp;quot; | Downloads&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 90px;&amp;quot; |{{SmallIcon|DownloadIcon.png|alt=Cloud API}} &lt;br /&gt;
|style=&amp;quot;width: 90px;&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| '''[[Digital Downloads|SDK Downloads]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Australia&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{SmallIcon|AUFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
|-&lt;br /&gt;
|  {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Australia Video iOS SDK|Request DCR Australia Video iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Australia Video Android SDK|Request DCR Australia Video Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Australia Video Browser SDK|Request DCR Australia Video Browser SDK]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Czech&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;6&amp;quot; | {{SmallIcon|CZFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;6&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
| {{OSIcon|macOSIcon.png}}&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
{{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Czech Video App SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Czech Video Browser SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;1&amp;quot; | {{OSIcon|StaticIcon.png}}&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Czech Static Browser SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; |&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; |&lt;br /&gt;
| '''[[Czech SDK Metadata]]'''&lt;br /&gt;
|-&lt;br /&gt;
| '''[[Czech Changing Approved Player]]'''&lt;br /&gt;
|-&lt;br /&gt;
| '''[[Czech Contacts]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Denmark&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
!| Links&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;5&amp;quot; | {{SmallIcon|DKFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;5&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
|-&lt;br /&gt;
|  {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Denmark Video iOS SDK]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=DK Sign License Agreement]&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Denmark Video Android SDK]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=DK Sign License Agreement]&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Denmark Video Browser SDK]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=DK Sign License Agreement]&lt;br /&gt;
|-&lt;br /&gt;
| {{SmallIcon|CloudAPIIcon.png}}&lt;br /&gt;
| {{OSIcon|APIIcon.png}}&lt;br /&gt;
| '''[[DCR Denmark Video Cloud API]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=DK Sign License Agreement]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Germany&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width: 90px;&amp;quot; |{{SmallIcon|DEFlagIcon.png}} &lt;br /&gt;
|style=&amp;quot;width: 90px;&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| '''[[AGF Implementation Documentation]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Italy&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;9&amp;quot; | {{SmallIcon|ITFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;9&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
|{{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Italy Video iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
|{{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Italy Video Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; | {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Italy Video Browser SDK (6.0.0)]]'''&lt;br /&gt;
|-&lt;br /&gt;
| '''[[DCR Italy Video Browser SDK (6.0.1)]] (Object Video only)'''&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;5&amp;quot; | {{OSIcon|StaticIcon.png}}&lt;br /&gt;
|{{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Italy Static iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
|{{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Italy Static Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Italy Static Browser SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
|  {{OSIcon|FacebookIcon.png|alt=Facebook Instant Articles}}&lt;br /&gt;
| '''[[DCR Italy Static Facebook Instant Articles Browser SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
|  {{OSIcon|AMPIcon.png|alt=Google AMP}}&lt;br /&gt;
| '''[[DCR Italy Static Google AMP Cloud API]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Norway&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|norway-flag-xs.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
| {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Norway Audio ios App SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Norway Audio Android App SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Norway Audio Browser SDK]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Poland&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|PLFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
| {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Poland Video iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Poland Video Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Poland Video Browser SDK]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | India&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{SmallIcon|INFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
|-&lt;br /&gt;
|  {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR India Video iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR India Video Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR India Video Browser SDK]]'''&lt;br /&gt;
|}&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Sweden&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
!| Links&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;5&amp;quot; | {{SmallIcon|SWflagicon.png}}&lt;br /&gt;
| rowspan=&amp;quot;4&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;5&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
|-&lt;br /&gt;
|  {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Sweden Video iOS SDK]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=SE Sign License Agreement]&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Sweden Video Android SDK]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=SE Sign License Agreement]&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Sweden Video Browser SDK]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=SE Sign License Agreement]&lt;br /&gt;
|-&lt;br /&gt;
| {{SmallIcon|CloudAPIIcon.png}}&lt;br /&gt;
| {{OSIcon|APIIcon.png}}&lt;br /&gt;
| '''[[DCR Sweden Video Cloud API]]'''&lt;br /&gt;
| [https://engineeringportal.nielsen.com/docs/Special:ClickThrough?region=SE Sign License Agreement]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Taiwan&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|TWFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
| {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Taiwan Video iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Taiwan Video Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Taiwan Video Browser SDK]]'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; | Thailand&lt;br /&gt;
! style=&amp;quot;width: 90px;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 45px;&amp;quot; | OS&lt;br /&gt;
!| Guide&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|THFlagIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{SmallIcon|SDKIcon.png}}&lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; | {{OSIcon|VideoIcon.png}}&lt;br /&gt;
| {{OSIcon|macOSIcon.png}}&lt;br /&gt;
| '''[[DCR Thailand Video iOS SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|AndroidIcon.png}}&lt;br /&gt;
| '''[[DCR Thailand Video Android SDK]]'''&lt;br /&gt;
|-&lt;br /&gt;
| {{OSIcon|BrowserIcon.png}}&lt;br /&gt;
| '''[[DCR Thailand Video Browser SDK]]'''&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>BryanLim</name></author>
	</entry>
</feed>