کتابخانه دسترسی برنامهنویسی (PAL) SDK برای Roku به ناشران با تأیید تماس مستقیم VAST (DVC) امکان کسب درآمد از برنامههای Roku مبتنی بر DVC را میدهد. PAL SDK به شما این امکان را می دهد که nonces را که رشته های رمزگذاری شده هستند از Google درخواست کنید تا بتوانید درخواست های DVC را امضا کنید. هر درخواست جریان جدید باید با یک nonce جدید تولید شده همراه باشد. با این حال، میتوانید از همان nonce برای چندین درخواست تبلیغات در یک جریان استفاده مجدد کنید.
این راهنما مثالی از نحوه ترکیب PAL SDK در برنامه Roku، درخواست nonce و ثبت نمایش تبلیغات را توضیح میدهد.
پیش نیازها
قبل از شروع این راهنما، باید موارد زیر را رعایت کنید:
- یک محیط توسعه Roku — برای اطلاعات بیشتر به راهنمای تنظیم محیط توسعه دهنده Roku مراجعه کنید.
پوشه پروژه با ساختار زیر:
./ 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
پروژه خود را تنظیم کنید
قبل از اینکه PAL SDK را یکپارچه کنید، باید فایل های پروژه خود را پیکربندی کنید.
آشکار
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
یک نمونه پخش کننده ویدیو ایجاد کنید
مؤلفه SampleVideoPlayer
به سادگی یک مؤلفه ویدیویی را برای گرفتن فشارهای کنترل از راه دور میپیچد. onKeyEvent
نادیده بگیرید تا وقتی تمرکز کنترل از راه دور به پخش کننده ویدیو/تبلیغ منتقل شود، فشارهای کلیدی دیگر (بالا، پایین، چپ، راست، کلیک، و غیره) گرفته شود و به 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>
یک رابط آزمایشی ایجاد کنید
یک صحنه را با دکمه ها برای انجام کارهای زیر پیاده سازی می کند:
- درخواست یک nonce.
- یک کلیک تبلیغاتی ارسال کنید.
- یک رویداد شروع پخش را ارسال کنید.
- یک رویداد با پایان پخش ارسال کنید.
- فوکوس را به دکمه ویدیو منتقل کنید.
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 ایجاد کنید
برای برقراری ارتباط بین صحنه اصلی و PAL SDK، به کامپوننتی نیاز دارید که حاوی کد ناهمزمان باشد. این امر ضروری است زیرا PAL SDK درخواستهای شبکه خارجی را ارائه میکند، که نمیتواند در رشته اصلی برنامه Roku رخ دهد. برای ارسال داده به این کامپوننت، به یک رابط نیاز دارید که مشخص کند کامپوننت چه داده هایی را ارسال و دریافت می کند.
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 را وارد کنید
برای استفاده از کتابخانه PAL، باید به IMA SDK برای Roku در مانیفست برنامه خود نیاز داشته باشید و آن را به مؤلفه PALInterface
وارد کنید.
آشکار
... 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>
عامل رابط از صحنه
در مرحله بعد، کد BrightScript را اضافه کنید که به تعاملات کاربر گوش می دهد و تغییراتی را در مؤلفه رابط ایجاد می کند:
برای دریافت خروجی از مؤلفه واسط، ناظرهای میدانی را روی فیلدهای رابط مرتبط با آن خروجی ها پیاده سازی کنید و آنها را به توابع پاسخ به تماس در مؤلفه اصلی متصل کنید. زمانی که کامپوننت برای اولین بار ثبت شد این کار را انجام دهید.
برای ارسال تعاملات کاربر به مؤلفه رابط، مشاهدهگرهای میدانی را روی دکمههایی که قبلاً ایجاد کردهاید پیادهسازی کنید تا تغییراتی را در فیلدهای رابط مرتبط با آن دستورات ایجاد کنید.
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>
روش هایی برای انتقال تمرکز اضافه کنید
در مرحله بعد، فشارهای کلید کاربر را برای انتقال فوکوس به و از عنصر ویدیوی خود ضبط کنید.
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 را راه اندازی کنید و یک nonceLoader ایجاد کنید
اکنون می توانید منطق اصلی پیاده سازی PAL SDK را شروع کنید. ابتدا SDK را از یک رشته جداگانه مقداردهی اولیه کنید.
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>
درخواست های غیر عادی را پردازش کنید
پس از ایجاد nonceLoader
، باید با پیوست کردن یک مشاهدهگر به فیلد requestNonce
درخواستهای nonce را مدیریت کنید. با پیوست کردن این ناظر تنها پس از مقداردهی اولیه nonceLoader
، میتوانید اطمینان حاصل کنید که درخواستهای nonce در رشته SDK مدیریت میشوند، و درخواست nonce تنها در صورت وجود 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>
اطلاعات رضایت ذخیره سازی را جمع آوری کنید
مقدار پیشفرض NonceRequest.storageAllowed
true
است، اما این مقدار را میتوان پس از کسب رضایت مناسب تغییر داد. متد getConsentToStorage()
یک مکان نگهدار برای روش خود شما برای کسب رضایت کاربر است، یا از طریق ادغام با یک CMP، یا بر اساس روشهای دیگر برای مدیریت رضایت ذخیرهسازی.
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
به سیگنال های چرخه زندگی بازیکن گوش دهید
برای اینکه ادغام PAL شما به درستی سیگنالها را ارسال کند، باید یک حلقه برای گوش دادن به سیگنالهای چرخه عمر پخشکننده خود تنظیم کنید.
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
و sendAdTouch
سپس، با sendPlaybackStart
در "شروع پخش ویدئو" تماس بگیرید. این روش تماسهای ناهمزمان با سرورهای Google را برای جمعآوری سیگنال مورد نیاز برای نظارت و شناسایی IVT آغاز میکند. با پایان پخش با sendPlaybackEnd
تماس بگیرید. در پاسخ به کلیک روی آگهی با sendAdClick
تماس بگیرید. سپس، sendAdTouch
را برای لمس بدون کلیک کاربر یا رویدادهای کلیک کنید.
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>
nonce را به درخواست های آگهی پیوست کنید
برای استفاده از nonce که از کتابخانه PAL در یک برنامه تولیدی دریافت میکنید، درخواستهای تبلیغاتی خود را فقط پس از ایجاد nonce آغاز کنید. سپس، nonce را با استفاده از پارامتر 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 ...
همین! اکنون یک برنامه Roku دارید که می تواند یک PAL nonce درخواست کند و رویدادهای جلسه پخش را با PAL SDK ثبت کند.
(اختیاری) سیگنال های Google Ad Manager را از طریق سرورهای تبلیغاتی شخص ثالث ارسال کنید
درخواست سرور آگهی شخص ثالث برای Ad Manager را پیکربندی کنید.
سرور تبلیغات شخص ثالث خود را پیکربندی کنید تا nonce را در درخواست سرور به Ad Manager لحاظ کند. در اینجا نمونه ای از تگ تبلیغاتی است که در داخل سرور تبلیغات شخص ثالث پیکربندی شده است:
'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'
برای جزئیات بیشتر، راهنمای پیاده سازی سمت سرور Google Ad Manager را ببینید.
Ad Manager برای شناسایی مقدار nonce به دنبال givn=
می گردد. سرور تبلیغات شخص ثالث باید از مقداری ماکرو خاص مانند %%custom_key_for_google_nonce%%
پشتیبانی کند و آن را با پارامتر درخواست nonce که در مرحله قبل ارائه کردید جایگزین کند. اطلاعات بیشتر در مورد نحوه انجام این کار باید در مستندات سرور تبلیغات شخص ثالث موجود باشد.
همین! اکنون باید پارامتر nonce را از PAL SDK از طریق سرورهای واسطه خود و سپس به Google Ad Manager منتشر کنید. این امکان کسب درآمد بهتر از طریق Google Ad Manager را فراهم می کند.