本指南提供開發人員操作說明,說明如何使用 Engage SDK 與 Google TV 分享應用程式訂閱和授權資料。使用者可以在電視、行動裝置和平板電腦上,直接透過 Google TV 體驗尋找有權觀看的內容,並讓 Google TV 提供高度相關的內容建議。
必要條件
如要使用裝置授權 API,請先加入媒體動作動態消息。如果尚未完成,請完成媒體動作動態消息的啟用程序。
事前作業
開始前,請先完成下列步驟: 確認應用程式的目標 API 級別為 19 以上,才能進行這項整合
將
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 }
在
AndroidManifest.xml
檔案中,將 Engage 服務環境設為正式版。行動裝置 APK
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>
For TV apk
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>
將 APK 傳送給 Google 前,請在 AndroidManifest.xml 檔案中,將參與服務環境設為正式版。 為獲得最佳效能和未來相容性,請僅在應用程式處於前景且使用者積極與其互動時發布資料,例如啟動應用程式、登入後或使用期間。不建議從背景程序發布。
在下列事件發布訂閱資訊:
- 使用者登入您的應用程式。
- 使用者切換設定檔 (如果支援設定檔)。
- 使用者購買新訂閱項目。
- 使用者升級現有訂閱方案。
- 使用者訂閱方案到期。
整合
本節提供必要的程式碼範例和操作說明,協助您實作 AccountProfile
和 SubscriptionEntity
,管理各種訂閱類型。
使用者帳戶和個人資料
如要在 Google TV 上使用個人化功能,請提供帳戶資訊。使用 AccountProfile
提供:
- 帳戶 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();
共同的訂閱方案
如果使用者訂閱媒體供應商服務的基本方案 (例如:服務只有一個訂閱層級,可存取所有付費內容),請提供下列重要詳細資料:
訂閱類型:清楚指出使用者訂閱的具體方案。
SUBSCRIPTION_TYPE_ACTIVE
:使用者已啟用付費訂閱方案。SUBSCRIPTION_TYPE_ACTIVE_TRIAL
:使用者有試用訂閱方案。SUBSCRIPTION_TYPE_INACTIVE
:使用者有帳戶,但沒有有效訂閱方案或試用方案。
到期時間:選用時間 (以毫秒為單位)。指定訂閱方案的到期時間。
供應商套件名稱:指定處理訂閱項目的應用程式套件名稱。
範例:Sample 媒體供應商動態消息。
"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();
進階版訂閱
如果應用程式提供多層級的進階訂閱方案 (包含一般層級以外的擴充內容或功能),請在「Subscription」中新增一或多項授權,代表這些方案。
這項授權具有下列欄位:
- ID:這項授權的必要 ID 字串。這必須與發布至 Google TV 的媒體供應商動態饋給中提供的授權 ID 之一相符 (請注意,這不是 ID 欄位)。
- 名稱:這是輔助資訊,用於比對授權。 雖然是選用欄位,但提供人類可讀的授權名稱,有助於開發人員和支援團隊瞭解使用者授權。例如:Sling Orange。
- 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 天後自動刪除舊項目。系統一律會使用最新項目。 如果發生錯誤,整個要求都會遭到拒絕,現有狀態則維持不變。
確保訂閱方案有效
- 如要在變更時立即提供更新,請在使用者訂閱狀態變更時 (例如啟用、停用、升級、降級) 呼叫
publishSubscriptionCluster()
。 為持續提供準確的驗證結果,請至少每月呼叫一次
publishSubscriptionCluster()
。如要在標準 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() )
測試
本節提供逐步指南,說明如何測試訂閱項目導入作業。發布前,請先確認資料準確無誤,且功能正常運作。
發布整合檢查清單
應用程式應在前景發布,且使用者正積極與應用程式互動。
發布時機:
- 使用者首次登入。
- 使用者變更設定檔 (如果系統支援設定檔)。
- 使用者購買新訂閱項目。
- 使用者升級訂閱方案。
- 使用者訂閱方案到期。
在發布事件時,檢查應用程式是否在 logcat 中正確呼叫
isServiceAvailable()
和publishClusters()
API。確認驗證應用程式可顯示資料。 驗證應用程式應將訂閱項目顯示為獨立的一列。呼叫發布 API 時,資料應會顯示在驗證應用程式中。
- 確認應用程式的 Android 資訊清單檔案中,Engage Service Flag未設為正式版。
- 安裝並開啟 Engage Verification 應用程式。
- 如果驗證應用程式中的
isServiceAvailable
值為false
,請點選驗證應用程式中的Toggle
按鈕,將值設為true
。 - 輸入應用程式的套件名稱,系統就會自動顯示已發布的資料。
前往應用程式並執行下列各項動作:
- 登入。
- 切換設定檔 (如支援)。
- 購買新的訂閱方案。
- 升級現有訂閱方案。
- 讓訂閱方案到期。
驗證整合
如要測試整合結果,請使用。
驗證應用程式是 Android 應用程式,可讓開發人員用來驗證整合作業是否有效。此應用程式內含可協助開發人員驗證資料和廣播意圖的功能。有助於在發布前驗證資料準確度及功能是否正常運作。
- 針對每個事件,檢查應用程式是否已叫用
publishSubscription
API。在驗證應用程式中確認已發布的資料。 確認驗證應用程式中的所有項目都顯示綠色 如果所有實體資訊都正確,所有實體都會顯示「一切正常」的綠色勾號。
圖 1. 訂閱成功 驗證應用程式也會醒目顯示問題
圖 2.訂閱失敗 如要查看套裝訂閱方案的問題,請使用電視遙控器將焦點放在該套裝訂閱方案上,然後點選即可查看問題。你可能需要先將焦點移至該列,然後向右移動,找到「套裝訂閱」資訊卡。如圖 3 所示,問題會以紅色醒目顯示。此外,你也可以使用遙控器向下移動,查看套裝訂閱方案中的授權問題
圖 3. 訂閱錯誤 如要查看授權中的問題,請使用電視遙控器將焦點放在該特定授權上,然後按一下即可查看問題。問題會以紅色醒目顯示。
圖 4.訂閱錯誤詳細資料
下載
下載前,請先同意以下條款及細則。