शुरू करें

Roku के लिए प्रोग्रामैटिक ऐक्सेस लाइब्रेरी (PAL) SDK टूल, सीधे तौर पर VAST कॉल (डीवीसी) की मंज़ूरी वाले पब्लिशर को DVC-आधारित Roku ऐप्लिकेशन से कमाई करने की सुविधा देता है. PAL SDK टूल की मदद से, Google से नॉन्स, जो एन्क्रिप्ट की गई स्ट्रिंग होती हैं, के लिए Google से अनुरोध किया जा सकता है, ताकि आप DVC अनुरोधों पर हस्ताक्षर कर सकें. स्ट्रीम करने के हर नए अनुरोध के साथ, नया जनरेट किया गया नॉन्स होना चाहिए. हालांकि, एक ही स्ट्रीम में कई विज्ञापन अनुरोधों के लिए एक ही नॉन्स का फिर से इस्तेमाल किया जा सकता है.

इस गाइड में, Roku ऐप्लिकेशन में PAL SDK टूल को शामिल करने, नॉन्स का अनुरोध करने, और विज्ञापन इंप्रेशन रजिस्टर करने के तरीकों के उदाहरण दिए गए हैं.

ज़रूरी शर्तें

यह गाइड शुरू करने से पहले, आपको ये काम करने होंगे:

अपना प्रोजेक्ट सेट अप करें

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

सोर्स/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>

टेस्ट इंटरफ़ेस बनाना

यह करने के लिए बटन के साथ सीन लागू करता है:

  • नॉन्स के लिए अनुरोध करें.
  • एक विज्ञापन क्लिक भेजें.
  • प्लेबैक स्टार्ट किया गया इवेंट भेजें.
  • वह इवेंट भेजें जिसके खत्म होने के बाद वीडियो चलाया जा सके.
  • फ़ोकस को 'वीडियो' बटन पर ले जाएं.

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 लाइब्रेरी का इस्तेमाल करने के लिए, आपको अपने ऐप्लिकेशन मेनिफ़ेस्ट में Roku के लिए IMA SDK की ज़रूरत होगी और उसे 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 फ़ील्ड में ऑब्ज़र्वर जोड़कर नॉन्स अनुरोधों को मैनेज करना होगा. इस ऑब्ज़र्वर को nonceLoader शुरू होने के बाद ही अटैच करके, यह पक्का किया जा सकता है कि SDK टूल के थ्रेड में नॉन्स अनुरोधों को हैंडल किया जाए. साथ ही, मान्य 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() वाला तरीका, उपयोगकर्ता की सहमति लेने के आपके तरीके के लिए एक प्लेसहोल्डर है. इसके लिए, सीएमपी के साथ इंटिग्रेट किया जा सकता है या स्टोरेज के लिए सहमति लेने के दूसरे तरीके इस्तेमाल किए जा सकते हैं.

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 के सर्वर को एसिंक्रोनस कॉल शुरू किए जाते हैं, ताकि आईवीटी की निगरानी और पता लगाने के लिए ज़रूरी सिग्नल इकट्ठा किए जा सकें. प्लेबैक खत्म होने पर 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>

विज्ञापन अनुरोधों में नॉन्स अटैच करें

PAL लाइब्रेरी से मिले नॉन्स का इस्तेमाल किसी प्रोडक्शन ऐप्लिकेशन में करने के लिए, विज्ञापन अनुरोधों को सिर्फ़ तब शुरू करें, जब नॉन्स जनरेट हो जाए. इसके बाद, 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 नॉन्स के लिए अनुरोध कर सकता है. साथ ही, PAL SDK टूल की मदद से, प्लेबैक सेशन के इवेंट रजिस्टर किए जा सकते हैं.

(ज़रूरी नहीं) तीसरे पक्ष के विज्ञापन सर्वर से Google Ad Manager के सिग्नल भेजना

Ad Manager के लिए, तीसरे पक्ष के विज्ञापन सर्वर के अनुरोध को कॉन्फ़िगर करें.

Ad Manager से किए गए सर्वर के अनुरोध में, नॉन्स को शामिल करने के लिए, अपने तीसरे पक्ष के विज्ञापन सर्वर को कॉन्फ़िगर करें. यहां तीसरे पक्ष के विज्ञापन सर्वर में कॉन्फ़िगर किए गए एक विज्ञापन टैग का उदाहरण दिया गया है:

'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'

ज़्यादा जानकारी के लिए, Google Ad Manager सर्वर-साइड लागू करने की गाइड देखें.

Ad Manager, नॉन्स वैल्यू की पहचान करने के लिए, givn= को खोजता है. तीसरे पक्ष के विज्ञापन सर्वर को अपने खुद के कुछ मैक्रो, जैसे कि %%custom_key_for_google_nonce%% के साथ काम करना होगा. साथ ही, इसकी जगह पिछले चरण में दिए गए नॉन्स क्वेरी पैरामीटर से बदलना होगा. इसे पूरा करने के तरीके की ज़्यादा जानकारी, तीसरे पक्ष के विज्ञापन सर्वर के दस्तावेज़ में उपलब्ध होनी चाहिए.

हो गया! अब आपको PAL SDK से मिले नॉन्स पैरामीटर को अपने इंटरमीडियरी सर्वर के ज़रिए, और उसके बाद Google Ad Manager में भेजना होगा. यह Google Ad Manager के ज़रिए बेहतर कमाई करने को बढ़ावा देता है.