L'SDK PAL (libreria di accesso programmatico) per Roku consente ai publisher che dispongono dell'approvazione per le chiamate VAST dirette (DVC) di monetizzare le applicazioni Roku basate su DVC. L'SDK PAL consente di richiedere a Google i nonce, ovvero stringhe criptate, in modo da poter firmare le richieste DVC. Ogni nuova richiesta di stream deve essere accompagnata da un nonce appena generato. Tuttavia, puoi riutilizzare lo stesso nonce per più richieste di annunci all'interno dello stesso stream.
Questa guida illustra un esempio di come incorporare l'SDK PAL in un'applicazione Roku, richiedere un nonce e registrare le impressioni degli annunci.
Prerequisiti
Prima di iniziare questa guida, devi:
- Un ambiente di sviluppo Roku: per ulteriori informazioni, consulta la guida alla configurazione dell'ambiente di sviluppo Roku.
Una cartella del progetto con la seguente struttura:
./ components/ MainScene.xml PALInterface.xml SampleVideoPlayer.xml images/ icon_focus_hd.png icon_focus_sd.png icon_side_hd.png icon_side_sd.png splash_fhd.png splash_hd.png splash_sd.png source/ main.brs manifest
Configura il progetto
Prima di integrare l'SDK PAL, devi configurare i file del progetto.
manifest
title=PAL for Roku Sample
subtitle=As seen in the PAL for Roku Get Started Guide
major_version=1
minor_version=0
build_version=00001
mm_icon_focus_hd=pkg:/images/icon_focus_hd.png
mm_icon_side_hd=pkg:/images/icon_side_hd.png
mm_icon_focus_sd=pkg:/images/icon_focus_sd.png
mm_icon_side_sd=pkg:/images/icon_side_sd.png
splash_screen_sd=pkg:/images/splash_sd.jpg
splash_screen_hd=pkg:/images/splash_hd.jpg
splash_screen_fhd=pkg:/images/splash_fhd.jpg
splash_color=#000000
splash_min_time=1000
ui_resolutions=hd
source/main.brs
sub Main()
showChannelSGScreen()
end sub
sub showChannelSGScreen()
screen = CreateObject("roSGScreen")
m.port = CreateObject("roMessagePort")
screen.setMessagePort(m.port)
m.scene = screen.CreateScene("MainScene")
screen.show()
while(true)
msg = wait(0, m.port)
msgType = type(msg)
if msgType = "roSGScreenEvent"
if msg.isScreenClosed() then return
end if
end while
end sub
Creare un video player di esempio
Il componente SampleVideoPlayer
racchiude semplicemente un componente video per acquisire
le pressioni del telecomando. Sostituisci onKeyEvent
in modo che, una volta trasferito il controllo del telecomando al video player/player di annunci, eventuali ulteriori pressioni dei tasti (su, giù, sinistra, destra, clic e così via) vengano acquisite e trasmesse a PAL.
components/SampleVideoPlayer.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="SampleVideoPlayer" extends="Video">
<interface>
<field id="pressedKey" type="String" />
</interface>
<script type="text/brightscript">
<![CDATA[
Function onKeyEvent(key as String, press as Boolean) as Boolean
If press
m.top.pressedKey = key
End If
return True
End Function
]]>
</script>
<children>
<Label text="VIDEO" color="0xFFFFFFFF" font="font:MediumBoldSystemFont" horizAlign="center" vertAlign="center" width="720" height="480" />
</children>
</component>
Creare un'interfaccia di test
Implementa una scena con pulsanti per eseguire le seguenti operazioni:
- Richiedi un nonce.
- Invia un clic sull'annuncio.
- Invia un evento di inizio riproduzione.
- Invia un evento di fine riproduzione.
- Trasferisci lo stato attivo sul pulsante del video.
components/MainScene.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="MainScene" extends="Scene" initialFocus="requestNonceButton">
<children>
<ButtonGroup>
<button text="Request Nonce" id="requestNonceButton" />
<button text="Send Ad Click" id="sendAdClickButton" />
<button text="Send Playback Start" id="sendPlaybackStartButton" />
<button text="Send Playback End" id="sendPlaybackEndButton" />
<button text="Transfer Focus to Video" id="transferFocusToVideoButton" />
</ButtonGroup>
<SampleVideoPlayer id="YourVideoPlayer" width="720" height="480" focusable="true" />
</children>
</component>
Crea un componente dell'interfaccia SDK
Per comunicare tra la scena principale e l'SDK PAL, è necessario un componente che contenga codice asincrono. Questo è necessario perché l'SDK PAL effettua richieste di rete esterne, che non possono verificarsi nel thread principale di un'applicazione Roku. Per inviare dati a questo componente, è necessaria un'interfaccia che definisca i dati inviati e ricevuti dal componente.
components/PALInterface.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="PALInterface" extends="Task">
<interface>
<!--Commands-->
<field id="requestNonce" type="Boolean" />
<field id="sendAdClick" type="Boolean" />
<field id="sendAdTouchKey" type="String" />
<field id="sendPlaybackStart" type="Boolean" />
<field id="sendPlaybackEnd" type="Boolean" />
<field id="endThread" type="Boolean" />
<!--Responses-->
<field id="errors" type="stringarray" />
<field id="nonce" type="String" />
</interface>
</component>
Importa l'SDK IMA
Per utilizzare la libreria PAL, devi richiedere l'SDK IMA per Roku nel manifest della tua app e importarlo nel componente PALInterface
.
manifest
... splash_color=#000000 splash_min_time=1000 ui_resolutions=hd bs_libs_required=googleima3
components/PALInterface.xml
<?xml version = "1.0" encoding = "utf-8" ?> <component name="PALInterface" extends="Task"> <interface> <!-- commands --> <field id="requestNonce" type="Boolean" /> <field id="sendAdClick" type="Boolean" /> <field id="sendAdTouchKey" type="String" /> <field id="sendPlaybackStart" type="Boolean" /> <field id="sendPlaybackEnd" type="Boolean" /> <field id="endThread" type="Boolean" /> <!-- responses --> <field id="errors" type="stringarray" /> <field id="nonce" type="String" /> </interface> <script type = "text/brightscript"> <![CDATA[ Library "IMA3.brs" ]]> </script> </component>
Attivare il componente dell'interfaccia dalla scena
Aggiungi il codice BrightScript che ascolta le interazioni degli utenti e attiva le modifiche nel componente dell'interfaccia:
Per ricevere l'output dal componente dell'interfaccia, implementa gli osservatori dei campi nei campi dell'interfaccia associati a questi output e associali alle funzioni di callback nel componente principale. Esegui questa operazione al momento della prima registrazione del componente.
Per inviare le interazioni utente al componente dell'interfaccia, implementa gli osservatori dei campi sui pulsanti che hai creato in precedenza per attivare le modifiche nei campi dell'interfaccia associati a questi comandi.
components/MainScene.xml
<?xml version="1.0" encoding="utf-8" ?> <component name="MainScene" extends="Scene" initialFocus="requestNonceButton"> <children> <ButtonGroup> <button text="Request Nonce" id="requestNonceButton" /> <button text="Send Ad Click" id="sendAdClickButton" /> <button text="Send Ad Touch" id="sendAdTouchButton" /> <button text="Send Playback Start" id="sendPlaybackStartButton" /> <button text="Send Playback End" id="sendPlaybackEndButton" /> </ButtonGroup> <Video id="YourVideoPlayer" width="720" height="480" focusable="true" /> </children> <script type="text/brightscript"> <![CDATA[ Function init() requestNonceButton = m.top.findNode("requestNonceButton") requestNonceButton.observeField("buttonSelected", "requestNonce") sendAdClickButton = m.top.findNode("sendAdClickButton") sendAdClickButton.observeField("buttonSelected", "sendAdClick") sendPlaybackStart = m.top.findNode("sendPlaybackStartButton") sendPlaybackStart.observeField("buttonSelected", "sendPlaybackStart") sendPlaybackEnd = m.top.findNode("sendPlaybackEndButton") sendPlaybackEnd.observeField("buttonSelected", "sendPlaybackEnd") loadImaSdk() End Function ' Initialize SDK Interface component and attach callbacks to field observers. Function loadImaSdk() as Void m.sdkTask = createObject("roSGNode", "PALInterface") m.sdkTask.observeField("errors", "onSdkLoadedError") m.sdkTask.observeField("nonce", "onNonceLoaded") print "Running load IMA task." m.sdkTask.control = "RUN" End Function Sub onSdkLoadedError(message as Object) print "----- errors in the sdk loading process --- ";message.getData() End Sub ' Callback triggered when Nonce is loaded. Sub onNonceLoaded(message as Object) nonce = m.sdkTask.nonce print "onNonceLoaded ";nonce End Sub Function requestNonceButtonPressed() As Void print "Request Nonce" ' Inform the SDK interface component to request a nonce. m.sdkTask.requestNonce = True End Function ' Action triggered on player start, either from user action or autoplay. Function sendPlaybackStart() As Void m.sdkTask.sendPlaybackStart = True End Function ' Action triggered on player end, either when content ends or the user exits ' playback of this content. Function sendPlaybackEnd() As Void m.sdkTask.sendPlaybackEnd = True End Function ]]> </script> </component>
Aggiungere metodi per trasferire lo stato attivo
Successivamente, acquisisci le pressioni dei tasti dell'utente per trasferire lo stato attivo all'elemento video e viceversa.
components/MainScene.xml
... <script type="text/brightscript"> <![CDATA[ Function init() ... m.sendPlaybackStart = m.top.findNode("sendPlaybackStartButton") m.sendPlaybackStart.observeField("buttonSelected", "sendPlaybackStart") m.sendPlaybackEnd = m.top.findNode("sendPlaybackEndButton") m.sendPlaybackEnd.observeField("buttonSelected", "sendPlaybackEnd") m.transferFocusToVideoButton = m.top.findNode("transferFocusToVideoButton") m.transferFocusToVideoButton.observeField("buttonSelected", "transferFocusToVideo") ' Your video player set up to handle key press events. m.video = m.top.findNode("YourVideoPlayer") m.video.observeField("pressedKey", "onVideoKeyPress") loadImaSdk() End Function ... ' Action triggered on player end, either when content ends or the user exits ' playback of this content. Function sendPlaybackEnd() As Void m.sdkTask.sendPlaybackEnd = True End Function Function transferFocusToVideo() As Void m.video.setFocus(true) End Function Function onVideoKeyPress() As Void key = m.video.pressedKey If key = "" Return End If m.sdkTask.sendAdTouchKey = key ' If back or up is pressed, transfer focus back up to the buttons. If key = "back" or key = "up" m.transferFocusToVideoButton.setFocus(true) End If ' Reset so that we get the next key press, even if it's a repeat of the last ' key. m.video.pressedKey = "" End Function ]]> </script> </component>
Inizializza l'SDK PAL e crea un nonceLoader
Ora puoi iniziare a sviluppare la logica di base dell'implementazione dell'SDK PAL. Innanzitutto, inizializza l'SDK da un thread separato.
components/PALInterface.xml
... <script type = "text/brightscript"> <![CDATA[ Library "IMA3.brs" Sub init() ' It is not possible to access roUrlTransfer on the main thread. Setting ' functionName to a function and then setting control to "RUN" causes that 'function to run on a separate thread. m.top.functionName = "runPalThread" ' Loads the SDK on the current thread if it is not yet loaded. ' This blocks execution of other functions on this thread until the SDK is loaded. If m.sdk = Invalid m.sdk = new_imaSdk() End If m.nonceLoader = m.sdk.CreateNonceLoader() End Sub ' Starts the player event loop. This loop only terminates when "endThread" is sent. Function runPalThread() as Void ' Used for the player life cycle loop. m.top.endThread = False port = CreateObject("roMessagePort") End Function ]]> </script> </component>
Elaborare le richieste di nonce
Una volta creato nonceLoader
, devi gestire le richieste di nonce collegando un osservatore al campo requestNonce
. Se colleghi questo osservatore solo
dopo l'inizializzazione di nonceLoader
, puoi assicurarti che le richieste di nonce vengano
gestite nel thread dell'SDK e che una richiesta di nonce possa essere effettuata solo se è presente
un nonceLoader
valido.
components/PALInterface.xml
... ' Starts the player event loop. This loop only terminates when "endThread" is sent. Function runPalThread() as Void ' Used for the player life cycle loop. m.top.endThread = False port = CreateObject("roMessagePort") ' Now that the nonceLoader exists, begin listening for nonce requests. m.top.observeField("requestNonce", m.port) End Function ' Requests a nonce from the PAL SDK. Function requestNonce() as Void nonceRequest = m.sdk.CreateNonceRequest() m.nonceManager = m.nonceLoader.loadNonceManager(nonceRequest) m.top.nonce = nonceManager.getNonce() End Function ]]> </script> </component>
Raccogliere le informazioni sul consenso per lo spazio di archiviazione
Il valore predefinito per
NonceRequest.storageAllowed
è true
, ma può essere modificato dopo aver raccolto il consenso appropriato. Il metodo getConsentToStorage()
è un segnaposto per il tuo metodo di ottenimento del consenso dell'utente, tramite l'integrazione con una CMP o in base ad altri metodi per gestire il consenso per lo spazio di archiviazione.
components/PALInterface.xml
... <script type = "text/brightscript"> <![CDATA[ Library "IMA3.brs" Sub init() ' It is not possible to access roUrlTransfer on the main thread. Setting ' functionName to a function and then setting control to "RUN" causes that 'function to run on a separate thread. m.top.functionName = "runPalThread" ' Loads the SDK on the current thread if it is not yet loaded. ' This blocks execution of other functions on this thread until the SDK is loaded. If m.sdk = Invalid m.sdk = new_imaSdk() End If m.isConsentToStorage = getConsentToStorage() m.nonceLoader = m.sdk.CreateNonceLoader() End Sub ... ' Requests a nonce from the PAL SDK. Function requestNonce() as Void nonceRequest = m.sdk.CreateNonceRequest() ' Include changes to storage consent here. nonceRequest.storageAllowed = m.isConsentToStorage m.nonceManager = m.nonceLoader.loadNonceManager(nonceRequest) m.top.nonce = nonceManager.getNonce() End Function
Presta attenzione agli indicatori del ciclo di vita dei giocatori
Per consentire all'integrazione di PAL di inviare correttamente gli indicatori, devi configurare un loop per ascoltare gli indicatori del ciclo di vita del player.
components/PALInterface.xml
... ' Now that the nonceLoader exists, begin listening for nonce requests. m.top.observeField("requestNonce", m.port) m.top.observeField("sendAdClick", m.port) m.top.observeField("sendAdTouchKey", m.port) m.top.observeField("sendPlaybackStart", m.port) m.top.observeField("sendPlaybackEnd", m.port) ' Setting endThread to true causes the while loop to exit. m.top.observeField("endThread", m.port) While Not m.top.endThread message = m.port.waitMessage(1000) If message = Invalid pollManager() Else If message.getField() = "requestNonce" And m.top.requestNonce = True requestNonce() m.top.requestNonce = False Else If message.getField() = "sendAdClick" And m.top.sendAdClick = True sendAdClick() m.top.sendAdClick = False Else If message.getField() = "sendAdTouchKey" And m.top.sendAdTouchKey <> "" sendAdTouch(m.top.sendAdTouchKey) m.top.sendAdTouchKey = "" Else If message.getField() = "sendPlaybackStart" And m.top.sendPlaybackStart = True sendPlaybackStart() m.top.sendPlaybackStart = False Else If message.getField() = "sendPlaybackEnd" And m.top.sendPlaybackEnd = True sendPlaybackEnd() m.top.sendPlaybackEnd = False End If End While End Function Function pollManager() as Void If m.nonceManager <> Invalid m.nonceManager.poll() End If End Function ' Requests a nonce from the PAL SDK. Function requestNonce() as Void nonceRequest = m.sdk.CreateNonceRequest() m.nonceManager = m.nonceLoader.loadNonceManager(nonceRequest) m.top.nonce = nonceManager.getNonce() End Function ]]> </script> </component>
Registra gli ascoltatori per sendPlaybackStart
, sendPlaybackEnd
, sendAdClick
e sendAdTouch
Quindi, chiama sendPlaybackStart
su "avvio del video player". Questo metodo avvia chiamate asincrone ai server Google per raccogliere l'indicatore necessario per il monitoraggio e il rilevamento del traffico non valido proveniente dall'interno del sito. Chiama sendPlaybackEnd
al termine della riproduzione.
Chiama sendAdClick
in risposta al clic sull'annuncio. Quindi, chiama sendAdTouch
per gli eventi di tocco o clic dell'utente non di clicthrough.
components/PALInterface.xml
... ' Requests a nonce from the IMA SDK. Function requestNonce() as Void nonceRequest = m.sdk.CreateNonceRequest() m.nonceManager = m.nonceLoader.loadNonceManager(nonceRequest) m.top.nonce = nonceManager.getNonce() End Function ' Registers an ad click using the IMA SDK. Function sendAdClick() as Void If m.nonceManager <> Invalid m.nonceManager.sendAdClick() End If End Function ' Registers an ad touch event using the IMA SDK. Function sendAdTouch(touch as String) as Void If m.nonceManager <> Invalid m.nonceManager.sendAdTouch(touch) End If End Function ' Registers the start of playback using the IMA SDK. Function sendPlaybackStart() as Void If m.nonceManager <> Invalid m.nonceManager.sendPlaybackStart() End If End Function ' Registers the end of playback using the IMA SDK. Function sendPlaybackEnd() as Void If m.nonceManager <> Invalid m.nonceManager.sendPlaybackEnd() End If End Function ]]> </script> </component>
Allega il nonce alle richieste di annunci
Per utilizzare il nonce che ricevi dalla libreria PAL in un'applicazione di produzione, avvia le richieste di annunci solo dopo che il nonce è stato generato. Poi, aggiungi
il nonce al tag annuncio utilizzando il parametro u_paln
.
components/MainScene.xml
... ' Callback triggered when Nonce is loaded. Sub onNonceLoaded(message as Object) nonce = m.sdkTask.nonce print "onNonceLoaded ";nonce makeAdRequest(nonce) End Sub Sub makeAdRequest(nonce) ' Sample ad tag URL used in this sample. Your apps method of getting this ' URL will likely be different. adTag = "https://pubads.g.doubleclick.net/gampad/ads?iu=/124319096/external/single_ad_samples" preparedTag = adTag + "&u_paln=" + nonce ' Implement custom ad request logic here. Print "ad tag with nonce ";preparedTag End Sub ...
È tutto. Ora hai un'app Roku che può richiedere un nonce PAL e registrare gli eventi della sessione di riproduzione con l'SDK PAL.
(Facoltativo) Invia gli indicatori di Google Ad Manager tramite ad server di terze parti
Configura la richiesta dell'ad server di terze parti per Ad Manager.
Configura l'ad server di terze parti in modo da includere il nonce nella richiesta del server ad Ad Manager. Ecco un esempio di tag annuncio configurato all'interno dell'ad server di terze parti:
'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'
Per ulteriori dettagli, consulta la guida all'implementazione lato server di Google Ad Manager.
Ad Manager cerca givn=
per identificare il valore nonce. Il server pubblicitario di terze parti deve supportare una propria macro, ad esempio%%custom_key_for_google_nonce%%
, e sostituirla con il parametro di query nonce fornito nel passaggio precedente. Ulteriori informazioni su come eseguire questa operazione dovrebbero essere disponibili nella documentazione dell'ad server di terze parti.
È tutto. Ora dovresti avere il parametro nonce propagato dall'SDK PAL, tramite i tuoi server intermedi e poi a Google Ad Manager. In questo modo, puoi migliorare la monetizzazione tramite Google Ad Manager.