L'SDK PAL (Programmatic Access Library) per Roku consente ai publisher con l'approvazione diretta delle chiamate VAST (DVC) di monetizzare le applicazioni Roku basate su DVC. L'SDK PAL ti consente di richiedere nonce, ovvero stringhe criptate, a Google, 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 annuncio 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 per sviluppatori Roku.
Una cartella di 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 di 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
sorgente/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
aggrega semplicemente un componente video per acquisire le pressioni dei telecomandi. Sostituisci onKeyEvent
in modo che, una volta trasferito l'elemento attivo al telecomando al video/player di annunci, eventuali ulteriori pressioni dei tasti (su, giù, sinistra, destra, clic e così via) vengano acquisite e riportate 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>
Crea un'interfaccia di test
Implementa una scena con pulsanti per:
- Richiedi un nonce.
- Invia un clic sull'annuncio.
- Invia un evento con avvio della riproduzione.
- Invia un evento con fine riproduzione.
- Trasferisci lo stato attivo sul pulsante 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>
Creare 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 in un'applicazione Roku. Per inviare dati a questo componente, è necessaria un'interfaccia che definisca i dati che il componente invia e riceve.
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>
Importare l'SDK IMA
Per utilizzare la libreria PAL, devi richiedere l'SDK IMA per Roku nel file manifest dell'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>
Attiva componente interfaccia dalla scena
Poi, aggiungi il codice BrightScript che rimane in ascolto delle interazioni degli utenti e attiva le modifiche nel componente dell'interfaccia:
Per ricevere output dal componente dell'interfaccia, implementa gli osservatori dei campi nei campi di interfaccia associati a questi output e collegali alle funzioni di callback nel componente principale. Esegui questa operazione alla prima registrazione del componente.
Per inviare interazioni utente al componente dell'interfaccia, implementa gli osservatori di campo sui pulsanti creati 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>
Aggiungi metodi per trasferire lo stato attivo
Successivamente, acquisisci le pressioni dei tasti 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 creare 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>
Elabora richieste nonce
Dopo aver creato nonceLoader
, devi gestire le richieste nonce associando un osservatore al campo requestNonce
. Collegando questo osservatore solo dopo l'inizializzazione di nonceLoader
, puoi assicurarti che le richieste nonce vengano gestite nel thread dell'SDK e che sia possibile effettuare una richiesta nonce solo se esiste un valore 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 informazioni sul consenso per l'archiviazione
Il valore predefinito di NonceRequest.storageAllowed
è true
, ma può essere modificato dopo aver ottenuto il consenso appropriato. Il metodo getConsentToStorage()
è un segnaposto per il tuo metodo per ottenere il consenso degli utenti, tramite l'integrazione con una CMP o altri metodi per gestire il consenso per l'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
Ascolta i segnali del ciclo di vita del player
Per consentire all'integrazione PAL di inviare correttamente segnali, devi configurare un loop per ascoltare i segnali 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 listener per sendPlaybackStart
, sendPlaybackEnd
, sendAdClick
e sendAdTouch
Dopodiché, chiama sendPlaybackStart
su "avviamento del video player". Questo metodo avvia
chiamate asincrone ai server Google per raccogliere il segnale necessario per il
monitoraggio e il rilevamento dell'IVT. Chiama sendPlaybackEnd
al termine della riproduzione.
Chiama sendAdClick
in risposta al clickthrough dell'annuncio. Quindi, chiama sendAdTouch
per
eventi di tocco o clic dell'utente senza clic.
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>
Associa il nonce alle richieste di annunci
Per utilizzare il nonce che ricevi dalla libreria PAL in un'applicazione di produzione, avvia le richieste di annuncio solo dopo la generazione del nonce. 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 disponi di un'app Roku che può richiedere un nonce PAL e registrare eventi di sessione di riproduzione con l'SDK PAL.
(Facoltativo) Inviare 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. Di seguito è riportato 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. L'ad server di terze parti deve supportare alcune macro, ad esempio %%custom_key_for_google_nonce%%
, e sostituirle 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. A questo punto, il parametro nonce dovrebbe essere propagato dall'SDK PAL, tramite i server intermedi, quindi in Google Ad Manager. Ciò consente una migliore monetizzazione tramite Google Ad Manager.