Pakiet SDK biblioteki zautomatyzowanego dostępu (PAL) na platformę Roku umożliwia wydawcom, którzy mają uprawnienia do korzystania z bezpośrednich wywołań VAST (DVC), zarabianie na aplikacjach na Roku opartych na DVC. Pakiet PAL SDK umożliwia wysyłanie od Google żądań jednorazowych, czyli zaszyfrowanych ciągów znaków, aby można było podpisywać żądania DVC. Każdemu nowemu żądaniu strumienia musi towarzyszyć nowo wygenerowana wartość jednorazowa. Możesz jednak użyć tej samej liczby jednorazowej dla wielu żądań reklamy w tym samym strumieniu.
W tym przewodniku znajdziesz przykładowy sposób włączania pakietu PAL SDK do aplikacji Roku, żądania nonce i rejestrowania wyświetleń reklam.
Wymagania wstępne
Przed rozpoczęciem tego przewodnika wykonaj następujące czynności:
- Środowisko programistyczne Roku – więcej informacji znajdziesz w przewodniku konfiguracji środowiska programistycznego Roku.
Folder projektu o tej strukturze:
./ 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
Konfigurowanie projektu
Zanim zintegrujesz pakiet SDK PAL, musisz skonfigurować pliki projektu.
plik manifestu
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
Tworzenie przykładowego odtwarzacza
Komponent SampleVideoPlayer
opakowuje po prostu komponent wideo, aby przechwytywać naciśnięcia pilota. Zastąp onKeyEvent
, tak aby po przeniesieniu fokusu pilota do odtwarzacza wideo lub reklamy wszystkie naciśnięcia klawiszy (w górę, w dół, w lewo, w prawo, kliknij itd.) były rejestrowane i wyświetlane jako dymki w górę.
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>
Tworzenie interfejsu testowego
Wdroż scenę z przyciskami, które umożliwiają:
- Poproś o nonce.
- Wyślij kliknięcie reklamy.
- Wyślij zdarzenie rozpoczęcia odtwarzania.
- Wysyłanie zdarzenia zakończenia odtwarzania.
- Przenieś zaznaczenie na przycisk wideo.
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>
Tworzenie komponentu interfejsu pakietu SDK
Aby umożliwić komunikację między główną sceną a pakietem SDK PAL, potrzebujesz komponentu zawierającego kod asynchroniczny. Jest to konieczne, ponieważ pakiet PAL SDK wysyła zewnętrzne żądania sieciowe, które nie mogą wystąpić w głównym wątku aplikacji Roku. Aby wysyłać dane do tego komponentu, potrzebujesz interfejsu, który określa, jakie dane komponent wysyła i odbiera.
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>
Importowanie pakietu IMA SDK
Aby korzystać z biblioteki PAL, musisz wymagać pakietu IMA SDK dla Roku w pliku manifestu aplikacji i importować go do komponentu PALInterface
.
plik manifestu
... 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>
Wyzwalanie komponentu interfejsu ze sceny
Następnie dodaj kod BrightScript, który reaguje na interakcje użytkownika i wyzwala zmiany w komponencie interfejsu:
Aby otrzymywać dane wyjściowe z elementu interfejsu, zaimplementuj obserwatorów pól w polach interfejsu powiązanych z tymi danymi i dołącz je do funkcji wywołania zwrotnego w komponencie głównym. Zrób to podczas pierwszej rejestracji komponentu.
Aby wysyłać dane o interakcjach użytkownika do komponentu interfejsu, zaimplementuj obserwacje pól w utworzonych wcześniej przyciskach i wywołują zmiany w polach interfejsu powiązanych z tymi poleceniami.
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>
Dodawanie metod przenoszenia punktu skupienia
Następnie rejestruj naciśnięcia klawiszy przez użytkownika, aby przenosić fokus na element wideo i z niego.
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>
Inicjowanie pakietu SDK PAL i tworzenie obiektu nonceLoader
Teraz możesz zacząć tworzyć podstawową logikę implementacji pakietu SDK PAL. Najpierw zainicjuj pakiet SDK w osobnym wątku.
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>
Przetwarzaj żądania jednorazowe
Po utworzeniu nonceLoader
musisz obsługiwać żądania nonce, dołączając obserwatora do pola requestNonce
. Dołączając tego obserwatora dopiero po zainicjowaniu nonceLoader
, możesz mieć pewność, że żądania nonce są obsługiwane w wątku pakietu SDK, oraz że żądanie nonce może zostać wysłane tylko wtedy, gdy istnieje prawidłowy obiekt nonceLoader
.
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>
Zbieranie informacji o zgodzie na przechowywanie danych
Wartość domyślna dla parametru NonceRequest.storageAllowed
to true
, ale można ją zmienić po uzyskaniu odpowiedniej zgody. Metoda getConsentToStorage()
to miejsce zastępcze na Twoją metodę uzyskiwania zgody użytkownika, np. przez integrację z platformą CMP lub za pomocą innych metod obsługi zgody na przechowywanie danych.
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
Słuchaj sygnałów dotyczących cyklu życia gracza
Aby umożliwić integracji z PAL prawidłowe wysyłanie sygnałów, musisz skonfigurować pętlę, która będzie nasłuchiwać sygnałów cyklu życia odtwarzacza.
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>
Rejestrowanie słuchaczy w przypadku sendPlaybackStart
, sendPlaybackEnd
, sendAdClick
i sendAdTouch
Następnie wywołaj sendPlaybackStart
w miejscu „rozpoczęcie odtwarzania filmu”. Ta metoda uruchamia wywołania asynchroniczne do serwerów Google, aby zebrać sygnał potrzebny do monitorowania i wykrywania IVT. Po zakończeniu odtwarzania zadzwoń pod numer sendPlaybackEnd
.
Wywołaj sendAdClick
w odpowiedzi na kliknięcie reklamy. Następnie wywołaj funkcję sendAdTouch
w przypadku zdarzeń dotyku lub kliknięcia przez użytkownika, które nie prowadzą do kliknięcia reklamy.
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>
Załączanie nonce do żądań reklam
Aby używać identyfikatora nonce otrzymanego z biblioteki PAL w aplikacji produkcyjnej, rozpoczynaj żądania reklamy dopiero po wygenerowaniu tego identyfikatora. Następnie dołącz wartość jednorazową do tagu reklamy za pomocą parametru 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 ...
Znakomicie. Masz teraz aplikację Roku, która może poprosić o nonce PAL i zarejestrować zdarzenia sesji odtwarzania za pomocą pakietu SDK PAL.
(Opcjonalnie) Wysyłanie sygnałów Google Ad Managera przez serwery reklamowe firm zewnętrznych
Skonfiguruj żądanie serwera reklam zewnętrznego dla Ad Managera.
Skonfiguruj serwer reklamowy firmy zewnętrznej, aby uwzględniał wartość jednorazową w żądaniu serwera wysyłanym do Ad Managera. Oto przykład tagu reklamy skonfigurowanego w serwerze reklamowym firmy zewnętrznej:
'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'
Więcej informacji znajdziesz w przewodniku po implementacji Google Ad Managera po stronie serwera.
Ad Manager szuka wartości givn=
, aby zidentyfikować wartość nonce. Serwer reklam zewnętrzny musi obsługiwać własne makro, np. %%custom_key_for_google_nonce%%
, i zastępować je parametrem zapytania nonce podanym w poprzednim kroku. Więcej informacji o tym, jak to zrobić, powinno być dostępnych w dokumentacji serwera reklamowego firmy zewnętrznej.
Znakomicie. Parametr nonce powinien być teraz propagowany z pakietu SDK PAL przez serwery pośredniczące do Google Ad Managera. Umożliwia to lepszą monetyzację za pomocą Google Ad Managera.