使用 Engage SDK 與 Google TV 共用應用程式授權

本指南適用對象為開發人員,提供使用 Engage SDK 與 Google TV 共用應用程式訂閱和授權資料的操作說明。使用者可以直接在 Google TV 的電視、行動裝置和平板電腦體驗中,找到自己有權觀看的內容,並讓 Google TV 為他們提供高度相關的內容推薦。

必要條件

您必須先導入媒體操作動態饋給,才能使用裝置授權 API。如果尚未完成,請完成媒體動作動態饋給的導入程序。

事前作業

開始前,請完成下列步驟:驗證應用程式目標 API 級別為 19 以上,才能進行此整合

  1. com.google.android.engage 程式庫新增至應用程式:

    整合時需要使用不同的 SDK:一個用於行動應用程式,另一個用於電視應用程式。

    行動裝置適用

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

    電視

    
      dependencies {
        implementation 'com.google.android.engage:engage-tv:1.0.2
      }
    
  2. AndroidManifest.xml 檔案中將 Engage 服務環境設為正式版。

    行動版 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 前,請在 AndroidManifest.xml 檔案中將 Engage 服務環境設為正式版。為確保最佳效能和日後的相容性,請只在應用程式處於前景且使用者正在積極與其互動時 (例如應用程式啟動、登入後或在使用中) 發布資料。我們不建議從背景程序發布。

  4. 針對下列事件發布訂閱資訊:

    1. 使用者登入您的應用程式。
    2. 使用者在設定檔之間切換 (如果系統支援設定檔)。
    3. 使用者購買新的訂閱項目。
    4. 使用者升級現有訂閱項目。
    5. 使用者訂閱項目到期。

整合

本節提供實作 AccountProfileSubscriptionEntity 的必要程式碼範例和操作說明,以便管理各種訂閱項目類型。

使用者帳戶和個人資料

如要在 Google TV 上使用個人化功能,請提供帳戶資訊。使用 AccountProfile 提供:

  1. 帳戶 ID:代表使用者帳戶的專屬 ID。這可以是實際帳戶 ID,或是經過適當模糊處理的版本。
// 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 訂閱

如果應用程式提供多層次的進階訂閱方案,其中包含超出一般層次的擴充內容或功能,請在 Subscription 中新增一或多個授權,以表示這項情況。

此授權包含下列欄位:

  1. ID:此授權的必要 ID 字串。這項資訊必須與媒體供應商發布至 Google TV 的動態饋給中提供的授權 ID 相符 (請注意,這不是 ID 欄位)。
  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();

視需要,也可以為已連結的服務訂閱項目新增授權。

提供訂閱組合

在應用程式於前景運作時執行內容發布工作。

使用 AppEngagePublishClient 類別的 publishSubscriptionCluster() 方法發布 SubscriptionCluster 物件。

使用 isServiceAvailable 檢查服務是否可供整合。

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

使用 setSubscription() 驗證使用者應只訂閱一項服務。

使用 addLinkedSubscription()addLinkedSubscriptions() (可接受連結訂閱項目清單),讓使用者可以擁有零或多個連結訂閱項目。

服務收到要求後,系統會建立新項目,並在 60 天後自動刪除舊項目。系統一律會使用最新的項目。如果發生錯誤,整個要求都會遭到拒絕,現有狀態則維持不變。

保持訂閱項目最新

  1. 如要立即提供變更內容,請在使用者的訂閱狀態發生變更時 (例如啟用、停用、升級、降級) 呼叫 publishSubscriptionCluster()
  2. 如要定期驗證持續的準確性,請每月至少呼叫一次 publishSubscriptionCluster()

  3. 如要刪除影片探索資料,請在標準 60 天保留期限前,使用 client.deleteClusters() 方法從 Google TV 伺服器手動刪除使用者資料。這會刪除帳戶個人資料或整個帳戶的所有現有影片探索資料,具體取決於指定的 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. 檢查應用程式是否正確呼叫發布事件的 logcat 中的 isServiceAvailable()publishClusters() API。

  4. 確認驗證應用程式可顯示資料。驗證應用程式應將訂閱項目顯示為獨立的一列。叫用發布 API 時,資料應會顯示在驗證應用程式中。

    • 確認「Engage Service Flag」設為應用程式 Android 資訊清單檔案中的正式版本。
    • 安裝並開啟 Engage Verification 應用程式。
    • 如果驗證應用程式中的 isServiceAvailable 值為 false,請在驗證應用程式中按一下 Toggle 按鈕,將其設為 true
    • 輸入應用程式的套件名稱,系統會自動顯示已發布的資料。
  5. 前往應用程式並執行下列各項操作:

    • 登入。
    • 切換設定檔 (如有支援)。
    • 購買新的訂閱項目。
    • 升級現有訂閱項目。
    • 讓訂閱項目到期。

驗證整合

如要測試整合作業,請使用驗證應用程式

驗證應用程式是 Android 應用程式,可讓開發人員用來驗證整合作業是否有效。此應用程式內含可協助開發人員驗證資料和廣播意圖的功能。這有助於在發布前驗證資料準確性和功能是否正常運作。

  1. 針對每個事件,檢查應用程式是否已叫用 publishSubscription API。在驗證應用程式中驗證已發布的資料。 確認驗證應用程式中的所有項目皆為綠色
  2. 如果所有實體資訊都正確,系統會在所有實體中顯示「All Good」綠色勾號。

    驗證應用程式成功螢幕截圖
    圖 1. 成功訂閱
  3. 驗證應用程式也會標示問題

    驗證應用程式錯誤螢幕截圖
    圖 2.訂閱失敗
  4. 如要查看套裝訂閱項目中的問題,請使用電視遙控器將焦點放在特定套裝訂閱項目,然後點選即可查看問題。你可能需要先將焦點放在該列,然後向右移動,才能找到「套裝訂閱」資訊卡。如圖 3 所示,問題會以紅色標示。此外,請使用遙控器向下移動,查看套裝訂閱方案中授權的問題

    驗證應用程式錯誤詳細資料螢幕截圖
    圖 3.訂閱錯誤
  5. 如要查看授權問題,請使用電視遙控器將焦點放在特定授權上,然後點選即可查看問題。問題會以紅色標示。

    驗證應用程式錯誤螢幕截圖
    圖 4.訂閱錯誤詳細資料