Roku için Programatik Erişim Kitaplığı (PAL) SDK'sı, doğrudan VAST çağrısı (DVC) onayı olan yayıncıların DVC tabanlı Roku uygulamalarından para kazanmasını sağlar. PAL SDK'sı, DVC isteklerini imzalayabilmeniz için Google'dan şifrelenmiş dize olan tek seferlik kimlikler isteyebilirsiniz. Her yeni akış isteği, yeni oluşturulmuş bir tek seferlik sayı ile birlikte gönderilmelidir. Ancak aynı tek seferlik rastgele sayıyı aynı akıştaki birden fazla reklam isteği için yeniden kullanabilirsiniz.
Bu kılavuzda, PAL SDK'sının bir Roku uygulamasına nasıl dahil edileceği, tek seferlik rastgele sayı isteğinde bulunulacağı ve reklam gösterimlerinin nasıl kaydedileceği açıklanmaktadır.
Ön koşullar
Bu rehbere başlamadan önce şunları yapmanız gerekir:
- Roku geliştirme ortamı: Daha fazla bilgi için Roku Geliştirici ortamı kurulum kılavuzuna bakın.
Aşağıdaki yapıya sahip bir proje klasörü:
./ 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
Projenizi oluşturma
PAL SDK'sını entegre etmeden önce proje dosyalarınızı yapılandırmanız gerekir.
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
Örnek video oynatıcı oluşturma
SampleVideoPlayer
bileşeni, uzaktan kumanda tuşlarına basma işlemlerini yakalamak için bir video bileşenini sarar. Uzaktan kumandanın odağı video/reklam oynatıcıya aktarıldıktan sonra diğer tuş basışlarının (yukarı, aşağı, sol, sağ, tıklama vb.) yakalanıp PAL'e aktarılması için onKeyEvent
değerini geçersiz kılın.
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>
Test arayüzü oluşturma
Aşağıdakileri yapmak için düğmelerin bulunduğu bir sahne uygular:
- Tek seferlik bir sayı isteyin.
- Reklam tıklaması gönderin.
- Oynatma işleminin başlatıldığı bir etkinlik gönderin.
- Oynatma sonu etkinliği gönderin.
- Odağı video düğmesine aktarın.
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>
SDK arayüzü bileşeni oluşturma
Ana sahne ile PAL SDK'sı arasında iletişim kurmak için asenkron kod içeren bir bileşene ihtiyacınız vardır. PAL SDK'sı harici ağ istekleri gönderir. Bu istekler, Roku uygulamasındaki ana iş parçacığında yapılamaz. Bu bileşene veri göndermek için bileşenin hangi verileri gönderip aldığını tanımlayan bir arayüze ihtiyacınız vardır.
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>
IMA SDK'sını içe aktarma
PAL kitaplığını kullanmak için uygulama manifestinizde Roku için IMA SDK'yı zorunlu kılmanız ve PALInterface
bileşenine içe aktarmanız gerekir.
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>
Arayüz bileşenini sahneden tetikleme
Ardından, kullanıcı etkileşimlerini dinleyen ve arayüz bileşeninde değişiklikleri tetikleyen BrightScript kodunu ekleyin:
Arayüz bileşeninden çıkış almak için bu çıkışlarla ilişkili arayüz alanlarında alan gözlemcileri uygulayın ve bunları ana bileşendeki geri çağırma işlevlerine ekleyin. Bunu bileşen ilk kaydedildiğinde yapın.
Kullanıcı etkileşimlerini arayüz bileşenine göndermek için, daha önce oluşturduğunuz düğmelere alan gözlemcileri uygulayarak bu komutlarla ilişkili arayüz alanlarında değişiklikleri tetikleyin.
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>
Odağı aktarmak için yöntemler ekleme
Ardından, odak noktasını video öğenize ve video öğenizden aktarmak için kullanıcının tuş basmalarını yakalayın.
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>
PAL SDK'yı başlatın ve nonceLoader oluşturun
Artık PAL SDK uygulamasını temel mantığını oluşturmaya başlayabilirsiniz. Öncelikle SDK'yı ayrı bir mesaj dizisinden başlatın.
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>
Tek seferlik istek işleme
nonceLoader
oluşturulduktan sonra, requestNonce
alanına bir gözlemci ekleyerek tek seferlik isteklerini işlemeniz gerekir. Bu gözlemciyi yalnızca nonceLoader
başlatıldıktan sonra ekleyerek tek seferlik isteklerin SDK iş parçacığında işlenmesini ve tek seferlik isteklerin yalnızca geçerli bir nonceLoader
varsa gönderilebilmesini sağlayabilirsiniz.
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>
Depolama alanı izin bilgilerini toplama
NonceRequest.storageAllowed
için varsayılan değer true
'tır ancak uygun izni aldıktan sonra bu değer değiştirilebilir. getConsentToStorage()
yöntemi, bir CMP ile entegrasyon yaparak veya depolama alanı iznini işlemek için diğer yöntemlere göre kullanıcı izni alma yönteminiz için bir yer tutucudur.
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
Oyuncu yaşam döngüsü sinyallerini dinleme
PAL entegrasyonunuzun sinyalleri düzgün şekilde göndermesine izin vermek için oynatıcınızın yaşam döngüsü sinyallerini dinleyecek bir döngü oluşturmanız gerekir.
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>
sendPlaybackStart
, sendPlaybackEnd
, sendAdClick
ve sendAdTouch
için dinleyicileri kaydetme
Ardından, "video oynatıcıyı başlat" için sendPlaybackStart
işlevini çağırın. Bu yöntem, IVT izleme ve algılama için gereken sinyali toplamak amacıyla Google sunucularına asynkron çağrılar başlatır. Oynatma sona erdiğinde sendPlaybackEnd
numaralı telefonu arayın.
Reklam tıklamasına yanıt olarak sendAdClick
'ü arayın. Ardından, tıklama olmayan kullanıcı dokunma veya tıklama etkinlikleri için sendAdTouch
işlevini çağırın.
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>
Tek seferlik sayıyı reklam isteklerine ekleme
PAL kitaplığından aldığınız tek seferlik kimliği bir üretim uygulamasında kullanmak için reklam isteklerinizi yalnızca tek seferlik kimlik oluşturulduktan sonra başlatın. Ardından, u_paln
parametresini kullanarak tek seferlik rastgele sayıyı reklam etiketine ekleyin.
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 ...
İşte bu kadar. Artık PAL tek seferlik rastgele sayıları isteyip oynatma oturumu etkinliklerini PAL SDK'sına kaydedebilen bir Roku uygulamanız var.
(İsteğe bağlı) Google Ad Manager sinyallerini üçüncü taraf reklam sunucuları aracılığıyla gönderme
Üçüncü taraf reklam sunucusunun Ad Manager isteğini yapılandırın.
Üçüncü taraf reklam sunucunuzu, sunucunun Ad Manager'a gönderdiği isteğe tek seferlik kimliği dahil edecek şekilde yapılandırın. Aşağıda, üçüncü taraf reklam sunucusunun içinde yapılandırılmış bir reklam etiketi örneği verilmiştir:
'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'
Daha fazla bilgi için Google Ad Manager sunucu tarafı uygulama kılavuzuna bakın.
Ad Manager, tek seferlik değer belirlemek için givn=
değerini arar. Üçüncü taraf reklam sunucusunun, %%custom_key_for_google_nonce%%
gibi kendi makrosunu desteklemesi ve bunu önceki adımda sağladığınız tek seferlik sorgu parametresiyle değiştirmesi gerekir. Bunu nasıl yapacağınızla ilgili daha fazla bilgiyi üçüncü taraf reklam sunucusunun belgelerinde bulabilirsiniz.
İşte bu kadar. Artık tek seferlik rastgele sayı parametresinin PAL SDK'sından, aracı sunucularınız aracılığıyla Google Ad Manager'a yayıldığını görebilirsiniz. Bu sayede Google Ad Manager üzerinden daha iyi para kazanabilirsiniz.