แชร์การให้สิทธิ์ของแอปกับ Google TV โดยใช้ Engage SDK

คำแนะนำในคู่มือนี้จะช่วยให้นักพัฒนาแอปแชร์ข้อมูลการสมัครใช้บริการและการให้สิทธิ์ของแอปกับ Google TV ได้โดยใช้ Engage SDK ผู้ใช้สามารถค้นหาเนื้อหาที่มีสิทธิ์รับชมและช่วยให้ Google TV แสดงคําแนะนําเนื้อหาที่เกี่ยวข้องสูงแก่ผู้ใช้ได้โดยตรงภายในประสบการณ์การใช้งาน Google TV บนทีวี อุปกรณ์เคลื่อนที่ และแท็บเล็ต

สิ่งที่ต้องมีก่อน

คุณต้องเริ่มต้นใช้งานฟีดการดําเนินการกับสื่อก่อนจึงจะใช้ Device Entitlement API ได้ หากยังไม่ได้ดำเนินการ ให้ทําตามกระบวนการเริ่มต้นใช้งานฟีดการกระทํากับสื่อให้เสร็จสมบูรณ์

งานก่อนเริ่มเวิร์กช็อป

ก่อนเริ่มต้น ให้ทำตามขั้นตอนต่อไปนี้ ยืนยันว่าแอปกำหนดเป้าหมายเป็น API ระดับ 19 ขึ้นไปสำหรับการผสานรวมนี้

  1. วิธีเพิ่มคลัง com.google.android.engage ลงในแอป

    มี SDK แยกต่างหากสําหรับการผสานรวม 1 รายการสําหรับแอปบนอุปกรณ์เคลื่อนที่และ 1 รายการสําหรับแอปทีวี

    สำหรับอุปกรณ์เคลื่อนที่

    
      dependencies {
        implementation 'com.google.android.engage:engage-core:1.5.5
      }
    

    สำหรับทีวี

    
      dependencies {
        implementation 'com.google.android.engage:engage-tv:1.0.2
      }
    
  2. ตั้งค่าสภาพแวดล้อมบริการ Engage เป็นเวอร์ชันที่ใช้งานจริงในไฟล์ AndroidManifest.xml

    สำหรับ apk บนอุปกรณ์เคลื่อนที่

    
    <meta-data
          android:name="com.google.android.engage.service.ENV"
          android:value="PRODUCTION">
    </meta-data>
    

    สำหรับ APK ของทีวี

    
    <meta-data
        android:name="com.google.android.engage.service.ENV"
        android:value="PRODUCTION">
    </meta-data>
    
  3. ก่อนส่ง APK ไปยัง Google ให้ตั้งค่าสภาพแวดล้อมบริการ Engage เป็น "เวอร์ชันที่ใช้งานจริง" ในไฟล์ AndroidManifest.xml เผยแพร่ข้อมูลเฉพาะเมื่อแอปอยู่เบื้องหน้าและผู้ใช้โต้ตอบกับแอปอยู่ เช่น การเปิดตัวแอป หลังเข้าสู่ระบบ หรือระหว่างการใช้งาน ไม่แนะนำให้เผยแพร่จากกระบวนการเบื้องหลัง

  4. เผยแพร่ข้อมูลการสมัครใช้บริการในเหตุการณ์ต่อไปนี้

    1. ผู้ใช้เข้าสู่ระบบแอป
    2. ผู้ใช้สลับระหว่างโปรไฟล์ (หากรองรับโปรไฟล์)
    3. ผู้ใช้สมัครใช้บริการใหม่
    4. ผู้ใช้อัปเกรดการสมัครใช้บริการที่มีอยู่
    5. การสมัครใช้บริการของผู้ใช้หมดอายุ

การรวมระบบ

ส่วนนี้จะแสดงตัวอย่างโค้ดและวิธีการที่จำเป็นในการใช้ AccountProfile และ SubscriptionEntity เพื่อจัดการการสมัครใช้บริการประเภทต่างๆ

บัญชีและโปรไฟล์ผู้ใช้

ระบุข้อมูลบัญชีเพื่ออนุญาตให้ใช้ฟีเจอร์ที่ปรับเปลี่ยนในแบบของคุณบน Google TV ใช้ AccountProfile เพื่อระบุข้อมูลต่อไปนี้

  1. รหัสบัญชี: ตัวระบุที่ไม่ซ้ำซึ่งแสดงถึงบัญชีของผู้ใช้ รหัสนี้อาจเป็นรหัสบัญชีจริงหรือรหัสที่มีการสร้างความสับสนอย่างเหมาะสม
// Set the account ID to which the subscription applies.
// Don't set the profile ID because subscription applies to account level.
val accountProfile = AccountProfile.Builder()
  .setAccountId("user_account_id")
  .setProfileId("user_profile id")
  .build();

การสมัครใช้บริการระดับทั่วไป

สำหรับผู้ใช้ที่สมัครใช้บริการพื้นฐานของผู้ให้บริการสื่อ เช่น บริการที่มีระดับการสมัครใช้บริการ 1 ระดับที่ให้สิทธิ์เข้าถึงเนื้อหาทั้งหมดแบบชำระเงิน ให้ระบุรายละเอียดที่สำคัญต่อไปนี้

  1. ประเภทการสมัครใช้บริการ: ระบุแพ็กเกจการสมัครใช้บริการที่ผู้ใช้มีอยู่อย่างชัดเจน

    1. SUBSCRIPTION_TYPE_ACTIVE: ผู้ใช้มีการสมัครใช้บริการแบบชำระเงินที่ใช้งานอยู่
    2. SUBSCRIPTION_TYPE_ACTIVE_TRIAL: ผู้ใช้สมัครใช้บริการช่วงทดลองใช้
    3. SUBSCRIPTION_TYPE_INACTIVE: ผู้ใช้มีบัญชีแต่ไม่มีการสมัครใช้บริการหรือช่วงทดลองใช้ที่ใช้งานอยู่
  2. เวลาหมดอายุ: เวลาเป็นมิลลิวินาที (ไม่บังคับ) ระบุเวลาที่การตั้งค่าการสมัครใช้บริการจะหมดอายุ

  3. ชื่อแพ็กเกจของผู้ให้บริการ: ระบุชื่อแพ็กเกจของแอปที่จัดการการสมัครใช้บริการ

ตัวอย่างฟีดผู้ให้บริการสื่อ

"actionAccessibilityRequirement": [
  {
    "@type": "ActionAccessSpecification",
    "category": "subscription",
    "availabilityStarts": "2022-06-01T07:00:00Z",
    "availabilityEnds": "2026-05-31T07:00:00Z",
    "requiresSubscription": {
    "@type": "MediaSubscription",
    // Don't match this string,
    // ID is only used to for reconciliation purpose
    "@id": "https://www.example.com/971bfc78-d13a-4419",
    // Don't match this, as name is only used for displaying purpose
    "name": "Basic common name",
    "commonTier": true
  }

ตัวอย่างต่อไปนี้สร้าง SubscriptionEntity ให้กับผู้ใช้

val subscription = SubscriptionEntity
  .Builder()
  setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds since epoch
  .setExpirationTimeMillis(1767052800000)
  .build();

การสมัครใช้บริการ Premium

หากแอปเสนอแพ็กเกจการสมัครใช้บริการพรีเมียมแบบหลายระดับ ซึ่งรวมถึงเนื้อหาหรือฟีเจอร์ที่ขยายการให้บริการนอกเหนือจากระดับทั่วไป ให้แสดงข้อมูลนี้โดยการเพิ่มการให้สิทธิ์อย่างน้อย 1 รายการในการสมัครใช้บริการ

การให้สิทธิ์นี้มีช่องต่อไปนี้

  1. ตัวระบุ: สตริงตัวระบุที่ต้องระบุสำหรับการให้สิทธิ์นี้ ข้อมูลนี้ต้องตรงกับตัวระบุการให้สิทธิ์รายการใดรายการหนึ่ง (โปรดทราบว่านี่ไม่ใช่ช่องรหัส) ที่ระบุไว้ในฟีดของผู้ให้บริการสื่อที่เผยแพร่ไปยัง Google TV
  2. ชื่อ: ข้อมูลเสริมนี้ใช้สำหรับการจับคู่การให้สิทธิ์ แม้ว่าจะไม่ใช่สิ่งจําเป็น แต่การให้ชื่อการให้สิทธิ์ที่อ่านออกได้จะช่วยเพิ่มความเข้าใจเกี่ยวกับการให้สิทธิ์ของผู้ใช้สําหรับทั้งนักพัฒนาซอฟต์แวร์และทีมสนับสนุน เช่น Sling Orange
  3. Expiration TimeMillis: ระบุเวลาหมดอายุเป็นมิลลิวินาทีสำหรับการให้สิทธิ์นี้ (ไม่บังคับ) หากแตกต่างจากเวลาหมดอายุของการสมัครใช้บริการ โดยค่าเริ่มต้น สิทธิ์จะหมดอายุเมื่อการสมัครใช้บริการหมดอายุ

สําหรับตัวอย่างข้อมูลโค้ดฟีดของผู้ให้บริการสื่อต่อไปนี้

"actionAccessibilityRequirement": [
  {
    "@type": "ActionAccessSpecification",
    "category": "subscription",
    "availabilityStarts": "2022-06-01T07:00:00Z",
    "availabilityEnds": "2026-05-31T07:00:00Z",
    "requiresSubscription": {
    "@type": "MediaSubscription",
    // Don't match this string,
    // ID is only used to for reconciliation purpose
    "@id": "https://www.example.com/971bfc78-d13a-4419",

    // Don't match this, as name is only used for displaying purpose
    "name": "Example entitlement name",
    "commonTier": false,
    // match this identifier in your API. This is the crucial
    // entitlement identifier used for recommendation purpose.
    "identifier": "example.com:entitlementString1"
  }

ตัวอย่างต่อไปนี้สร้าง SubscriptionEntity สำหรับผู้ใช้ที่ติดตาม

// Subscription with entitlements.
// The entitlement expires at the same time as its subscription.
val subscription = SubscriptionEntity
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds
  .setExpirationTimeMillis(1767052800000)
  .addEntitlement(
    SubscriptionEntitlement.Builder()
    // matches with the identifier in media provider feed
    .setEntitlementId("example.com:entitlementString1")
    .setDisplayName("entitlement name1")
    .build()
  )
  .build();
// Subscription with entitlements
// The entitement has different expiration time from its subscription
val subscription = SubscriptionEntity
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds
  .setExpirationTimeMillis(1767052800000)
  .addEntitlement(
    SubscriptionEntitlement.Builder()
    .setEntitlementId("example.com:entitlementString1")
    .setDisplayName("entitlement name1")
    // You may set the expiration time for entitlement
    // December 15, 2025 10:00:00 AM in milliseconds
    .setExpirationTimeMillis(1765792800000)
    .build())
  .build();

การสมัครใช้บริการแพ็กเกจบริการที่ลิงก์

แม้ว่าโดยทั่วไปการสมัครใช้บริการจะมาจากผู้ให้บริการสื่อของแอปต้นทาง แต่การสมัครใช้บริการก็สามารถระบุแหล่งที่มาเป็นแพ็กเกจบริการที่ลิงก์ได้โดยระบุชื่อแพ็กเกจบริการที่ลิงก์ภายในการสมัครใช้บริการ

ตัวอย่างโค้ดต่อไปนี้แสดงวิธีสร้างการสมัครใช้บริการของผู้ใช้

// Subscription for linked service package
val subscription = SubscriptionEntity
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds since epoch
  .setExpirationTimeMillis(1767052800000)
  .build();

นอกจากนี้ หากผู้ใช้มีการสมัครใช้บริการอีกรายการในบริการย่อย ให้เพิ่มการสมัครใช้บริการอีกรายการและตั้งชื่อแพ็กเกจของบริการที่ลิงก์ให้สอดคล้องกัน

// Subscription for linked service package
val linkedSubscription = Subscription
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("linked service package name")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds since epoch
  .setExpirationTimeMillis(1767052800000)
  .addBundledSubscription(
    BundledSubscription.Builder()
      .setBundledSubscriptionProviderPackageName(
        "bundled-subscription-package-name"
      )
      .setSubscriptionType(SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE)
      .setExpirationTimeMillis(111)
      .addEntitlement(
        SubscriptionEntitlement.Builder()
        .setExpirationTimeMillis(111)
        .setDisplayName("Silver subscription")
        .setEntitlementId("subscription.tier.platinum")
        .build()
      )
      .build()
  )
    .build();

คุณเพิ่มการให้สิทธิ์ในการสมัครใช้บริการที่ลิงก์ไว้ด้วยก็ได้

ระบุชุดการสมัครใช้บริการ

เรียกใช้งานเผยแพร่เนื้อหาขณะที่แอปทำงานอยู่เบื้องหน้า

ใช้เมธอด publishSubscriptionCluster() จากคลาส AppEngagePublishClient เพื่อเผยแพร่ออบเจ็กต์ SubscriptionCluster

ใช้ isServiceAvailable เพื่อตรวจสอบว่าบริการพร้อมสำหรับการผสานรวมหรือไม่

client.publishSubscription(
  PublishSubscriptionRequest.Builder()
    .setAccountProfile(accountProfile)
    .setSubscription(subscription)
    .build();
  )

ใช้ setSubscription() เพื่อยืนยันว่าผู้ใช้ควรมีการสมัครใช้บริการเพียงรายการเดียว

ใช้ addLinkedSubscription() หรือ addLinkedSubscriptions() ซึ่งยอมรับรายการการสมัครใช้บริการที่ลิงก์ไว้ เพื่อให้ผู้ใช้มีการสมัครใช้บริการที่ลิงก์ไว้ตั้งแต่ 0 รายการขึ้นไป

เมื่อบริการได้รับคําขอ ระบบจะสร้างรายการใหม่และลบรายการเก่าโดยอัตโนมัติหลังจากผ่านไป 60 วัน ระบบจะใช้รายการล่าสุดเสมอ ในกรณีที่เกิดข้อผิดพลาด ระบบจะปฏิเสธคำขอทั้งหมดและคงสถานะที่มีอยู่ไว้

อัปเดตการสมัครใช้บริการให้เป็นปัจจุบันอยู่เสมอ

  1. หากต้องการอัปเดตทันทีเมื่อมีการเปลี่ยนแปลง ให้เรียกใช้ publishSubscriptionCluster() ทุกครั้งที่สถานะการสมัครใช้บริการของผู้ใช้มีการเปลี่ยนแปลง เช่น การเปิดใช้งาน การปิดใช้งาน การอัปเกรด การดาวน์เกรด
  2. โปรดเรียกใช้ publishSubscriptionCluster() อย่างน้อยเดือนละครั้งเพื่อให้การตรวจสอบความถูกต้องอย่างต่อเนื่อง

  3. หากต้องการลบข้อมูลการค้นพบวิดีโอ ให้ลบข้อมูลของผู้ใช้ออกจากเซิร์ฟเวอร์ Google TV ด้วยตนเองก่อนระยะเวลาการเก็บรักษามาตรฐาน 60 วัน โดยใช้วิธีการ client.deleteClusters() ซึ่งจะเป็นการลบข้อมูลการค้นพบวิดีโอที่มีอยู่ทั้งหมดสำหรับโปรไฟล์บัญชีหรือทั้งบัญชี ทั้งนี้ขึ้นอยู่กับ DeleteReason ที่ระบุ

    ข้อมูลโค้ดเพื่อนําการสมัครใช้บริการของผู้ใช้ออก

      // If the user logs out from your media app, you must make the following call
      // to remove subscription and other video discovery data from the current
      // google TV device.
      client.deleteClusters(
        new DeleteClustersRequest.Builder()
          .setAccountProfile(
            AccountProfile
              .Builder()
              .setAccountId()
              .setProfileId()
              .build()
          )
        .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
        .build()
        )
      ```
    Following code snippet demonstrates removal of user subscription
    when user revokes the consent.
    
    ```Kotlin
      // If the user revokes the consent to share across device, make the call
      // to remove subscription and other video discovery data from all google
      // TV devices.
      client.deleteClusters(
        new DeleteClustersRequest.Builder()
          .setAccountProfile(
            AccountProfile
            .Builder()
            .setAccountId()
            .setProfileId()
            .build()
          )
          .setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
          .build()
      )
      ```
    
    Following code demonstrates how to remove subscription data on user profile
    deletion.
    
    ```Kotlin
    // If the user delete a specific profile, you must make the following call
    // to remove subscription data and other video discovery data.
    client.deleteClusters(
      new DeleteClustersRequest.Builder()
      .setAccountProfile(
        AccountProfile
        .Builder()
        .setAccountId()
        .setProfileId()
        .build()
      )
      .setReason(DeleteReason.DELETE_REASON_ACCOUNT_PROFILE_DELETION)
      .build()
    )
    

การทดสอบ

ส่วนนี้จะแสดงคําแนะนําแบบทีละขั้นตอนสําหรับการทดสอบการติดตั้งใช้งานการติดตาม ตรวจสอบความถูกต้องของข้อมูลและฟังก์ชันการทํางานที่เหมาะสมก่อนเปิดตัว

รายการตรวจสอบการเผยแพร่การผสานรวม

  1. การเผยแพร่ควรเกิดขึ้นเมื่อแอปอยู่ในเบื้องหน้าและผู้ใช้โต้ตอบกับแอปอยู่

  2. เผยแพร่เมื่อ

    • ผู้ใช้เข้าสู่ระบบเป็นครั้งแรก
    • ผู้ใช้เปลี่ยนโปรไฟล์ (หากระบบรองรับโปรไฟล์)
    • ผู้ใช้สมัครใช้บริการใหม่
    • ผู้ใช้อัปเกรดการสมัครใช้บริการ
    • การสมัครใช้บริการของผู้ใช้หมดอายุ
  3. ตรวจสอบว่าแอปเรียกใช้ isServiceAvailable() และ publishClusters() API ใน logcat ของเหตุการณ์การเผยแพร่อย่างถูกต้องหรือไม่

  4. ตรวจสอบว่าข้อมูลแสดงอยู่ในแอปการยืนยัน แอปการยืนยันควรแสดงการสมัครใช้บริการเป็นแถวแยกต่างหาก เมื่อเรียกใช้ API เผยแพร่ ข้อมูลควรแสดงในแอปการยืนยัน

    • ตรวจสอบว่าFlag บริการ Engage ไม่ได้ตั้งค่าเป็นเวอร์ชันที่ใช้งานจริงในไฟล์ Manifest ของ Android ของแอป
    • ติดตั้งและเปิดแอปการยืนยัน Engage
    • หากค่าของ isServiceAvailable คือ false ในแอปการยืนยัน ให้คลิกปุ่ม Toggle ภายในแอปการยืนยันเพื่อตั้งค่าเป็น true
    • ป้อนชื่อแพ็กเกจของแอป ระบบจะแสดงข้อมูลที่เผยแพร่โดยอัตโนมัติ
  5. ไปที่แอปและดำเนินการต่อไปนี้ทีละรายการ

    • ลงชื่อเข้าใช้
    • สลับระหว่างโปรไฟล์ (หากรองรับ)
    • ซื้อการสมัครใช้บริการใหม่
    • อัปเกรดการสมัครใช้บริการที่มีอยู่
    • การสมัครใช้บริการหมดอายุ

ยืนยันการผสานรวม

หากต้องการทดสอบการผสานรวม ให้ใช้แอปการยืนยัน

แอปการยืนยันเป็นแอปพลิเคชัน Android ที่นักพัฒนาแอปสามารถใช้เพื่อยืนยันว่าการผสานรวมทํางาน แอปมีความสามารถในการช่วยนักพัฒนาแอปยืนยันข้อมูลและเจตนาออกอากาศ ซึ่งช่วยยืนยันความถูกต้องของข้อมูลและฟังก์ชันการทำงานที่เหมาะสมก่อนการเปิดตัว

  1. สําหรับแต่ละเหตุการณ์ ให้ตรวจสอบว่าแอปเรียกใช้ publishSubscription API หรือไม่ ยืนยันข้อมูลที่เผยแพร่ในแอปการยืนยัน ตรวจสอบว่าทุกอย่างเป็นสีเขียวในแอปการยืนยัน
  2. หากข้อมูลทั้งหมดของเอนทิตีถูกต้อง ระบบจะแสดงเครื่องหมายถูกสีเขียว "เรียบร้อยดี" ในทุกเอนทิตี

    ภาพหน้าจอแสดงการยืนยันแอปสำเร็จ
    รูปที่ 1 สมัครใช้บริการสำเร็จ
  3. ระบบจะไฮไลต์ปัญหาในแอปการยืนยันด้วย

    ภาพหน้าจอข้อผิดพลาดของแอปการยืนยัน
    รูปที่ 2. การสมัครใช้บริการไม่สำเร็จ
  4. หากต้องการดูปัญหาในการสมัครใช้บริการแบบแพ็กเกจ ให้ใช้รีโมตทีวีเพื่อโฟกัสไปที่การสมัครใช้บริการแบบแพ็กเกจที่ต้องการ แล้วคลิกเพื่อดูปัญหา คุณอาจต้องโฟกัสที่แถวแล้วเลื่อนไปทางขวาเพื่อค้นหาการ์ดการสมัครใช้บริการแบบแพ็กเกจ ระบบจะไฮไลต์ปัญหาเป็นสีแดงดังที่แสดงในรูปที่ 3 นอกจากนี้ ให้ใช้รีโมตเลื่อนลงเพื่อดูปัญหาเกี่ยวกับสิทธิ์ในการรับชมภายในการสมัครใช้บริการแบบแพ็กเกจ

    ภาพหน้าจอรายละเอียดข้อผิดพลาดของแอปการยืนยัน
    รูปที่ 3. ข้อผิดพลาดในการสมัครใช้บริการ
  5. หากต้องการดูปัญหาในการให้สิทธิ์ ให้ใช้รีโมตทีวีเพื่อโฟกัสที่การให้สิทธิ์ที่เฉพาะเจาะจงนั้น แล้วคลิกเพื่อดูปัญหา ระบบจะไฮไลต์ปัญหาเป็นสีแดง

    ภาพหน้าจอข้อผิดพลาดของแอปการยืนยัน
    รูปที่ 4.รายละเอียดข้อผิดพลาดในการสมัครใช้บริการ