Engage SDK를 사용하여 Google TV와 앱 사용 권한 공유

이 가이드에는 개발자가 Engage SDK를 사용하여 앱 정기 결제 및 권한 데이터를 Google TV와 공유하는 방법이 포함되어 있습니다. 사용자는 권한이 있는 콘텐츠를 찾고 Google TV에서 TV, 모바일, 태블릿의 Google TV 환경 내에서 사용자에게 매우 관련성이 높은 콘텐츠 추천을 제공하도록 Google TV를 사용 설정할 수 있습니다.

기본 요건

기기 권한 API를 사용하려면 먼저 미디어 액션 피드를 온보딩해야 합니다. 아직 완료하지 않았다면 미디어 액션 피드 온보딩 프로세스를 완료하세요.

사전 작업

시작 가이드의 사전 작업 안내를 완료합니다.

  1. 다음 이벤트에 정기 결제 정보를 게시합니다.
    1. 사용자가 앱에 로그인합니다.
    2. 사용자가 프로필 간에 전환합니다 (프로필이 지원되는 경우).
    3. 사용자가 새 정기 결제를 구매합니다.
    4. 사용자가 기존 정기 결제를 업그레이드합니다.
    5. 사용자 정기 결제가 만료됩니다.

통합

이 섹션에서는 다양한 정기 결제 유형을 관리하기 위해 SubscriptionEntity를 구현하는 데 필요한 코드 예와 안내를 제공합니다.

일반 등급 정기 결제

예를 들어 모든 유료 콘텐츠에 대한 액세스 권한을 부여하는 정기 결제 등급이 하나인 서비스와 같이 미디어 제공업체 서비스의 기본 정기 결제를 사용하는 사용자의 경우 다음과 같은 필수 세부정보를 제공합니다.

  1. SubscriptionType: 사용자에게 있는 특정 정기 결제 요금제를 명확하게 나타냅니다.

    • SUBSCRIPTION_TYPE_ACTIVE: 사용자에게 활성 상태인 유료 정기 결제가 있습니다.
    • SUBSCRIPTION_TYPE_ACTIVE_TRIAL: 사용자에게 체험판 정기 결제가 있습니다.
    • SUBSCRIPTION_TYPE_INACTIVE: 사용자에게 계정은 있지만 활성 상태인 정기 결제 또는 체험판은 없습니다.
  2. ExpirationTimeMillis: 선택사항이며 시간은 밀리초 단위입니다. 정기 결제가 만료되는 시점을 지정합니다.

  3. ProviderPackageName: 정기 결제를 처리하는 앱의 패키지 이름을 지정합니다.

샘플 미디어 제공업체 피드의 예

"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()

프리미엄 구독

앱에서 일반 등급을 넘어 확장된 콘텐츠 또는 기능이 포함된 다단계 프리미엄 정기 결제 패키지를 제공하는 경우 정기 결제에 하나 이상의 권한을 추가하여 이를 나타냅니다.

이 권한에는 다음과 같은 필드가 있습니다.

  1. Identifier: 이 권한에 필요한 식별자 문자열입니다. 이 식별자는 Google TV에 게시된 미디어 제공업체 피드에 제공된 권한 식별자 중 하나와 일치해야 합니다 (ID 필드가 아님).
  2. Name: 보조 정보이며 권한 일치에 사용됩니다. 선택사항이지만 사람이 읽을 수 있는 권한 이름을 제공하면 개발자와 지원팀 모두 사용자 권한을 더 잘 이해할 수 있습니다. 예: Sling Orange
  3. ExpirationTimeMillis: 정기 결제 만료 시간과 다른 경우 이 권한의 만료 시간을 밀리초 단위로 지정합니다(선택사항). 기본적으로 권한은 정기 결제 만료와 함께 만료됩니다.

다음 샘플 미디어 제공업체 피드 스니펫의 경우

"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() 메서드를 사용하여 SubscriptionCluster 객체를 게시합니다.AppEngagePublishClient

시작 가이드에 설명된 대로 클라이언트를 초기화하고 서비스 가용성을 확인해야 합니다.

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

setSubscription()을 사용하여 사용자에게 서비스 정기 결제가 하나만 있어야 하는지 확인합니다.

연결된 정기 결제 목록을 허용하는 addLinkedSubscription() 또는 addLinkedSubscriptions()를 사용하여 사용자가 연결된 정기 결제를 0개 이상 보유할 수 있도록 합니다.

서비스에서 요청을 받으면 새 항목이 생성되고 60일 후에 이전 항목이 자동으로 삭제됩니다. 시스템은 항상 최신 항목을 사용합니다. 오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.

정기 결제를 최신 상태로 유지

  1. 변경사항이 있을 때 즉시 업데이트를 제공하려면 활성화, 비활성화, 업그레이드, 다운그레이드와 같이 사용자의 정기 결제 상태가 변경될 때마다 publishSubscriptionCluster를 호출합니다.

  2. 정확성을 지속적으로 검증하려면 한 달에 한 번 이상 publishSubscriptionCluster를 호출합니다.

  3. Engage 데이터를 삭제하려면 표준 60일 보관 기간 전에 Google TV 서버에서 사용자의 데이터를 수동으로 삭제하려면 client.deleteClusters 메서드를 사용하세요. 이렇게 하면 지정된 DeleteReason에 따라 계정 프로필 또는 전체 계정의 기존 Engage 데이터가 모두 삭제됩니다.

    다음 코드 스니펫은 사용자 정기 결제를 삭제하는 방법을 보여줍니다.

    // If the user logs out from your media app, you must make the following call
    // to remove subscription and other Engage data from the current
    // google TV device.
    client.deleteClusters(
      new DeleteClustersRequest.Builder()
        .setAccountProfile(accountProfile)
      .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
      .build()
      )
    

    다음 코드 스니펫은 사용자가 동의를 철회할 때 사용자 정기 결제를 삭제하는 방법을 보여줍니다.

    // If the user revokes the consent to share across device, make the call
    // to remove subscription and other Engage data from all google
    // TV devices.
    client.deleteClusters(
      new DeleteClustersRequest.Builder()
        .setAccountProfile(accountProfile)
        .setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
        .build()
    )
    

    다음 코드는 사용자 프로필 삭제 시 정기 결제 데이터를 삭제하는 방법을 보여줍니다.

    // If the user delete a specific profile, you must make the following call
    // to remove subscription data and other Engage data.
    client.deleteClusters(
      new DeleteClustersRequest.Builder()
      .setAccountProfile(accountProfile)
      .setReason(DeleteReason.DELETE_REASON_ACCOUNT_PROFILE_DELETION)
      .build()
    )
    

테스트

이 섹션에서는 정기 결제 구현을 테스트하는 단계별 가이드를 제공합니다. 출시 전에 데이터 정확성과 올바른 기능을 확인하세요.

통합 게시 체크리스트

  1. 앱이 포그라운드에 있고 사용자가 앱과 적극적으로 상호작용할 때 게시가 이루어져야 합니다.

  2. 다음과 같은 경우 게시합니다.

    • 사용자가 처음으로 로그인합니다.
    • 사용자가 프로필을 변경합니다 (프로필이 지원되는 경우).
    • 사용자가 새 정기 결제를 구매합니다.
    • 사용자가 정기 결제를 업그레이드합니다.
    • 사용자 정기 결제가 만료됩니다.
  3. 게시 이벤트에서 앱이 logcat의 isServiceAvailablepublishClusters API를 올바르게 호출하는지 확인합니다.

  4. 데이터가 인증 앱에 표시되는지 확인합니다. 인증 앱에는 정기 결제가 별도의 행으로 표시되어야 합니다. 게시 API가 호출되면 데이터가 인증 앱에 표시되어야 합니다.

  5. 앱으로 이동하여 다음 각 작업을 실행합니다.

    • 로그인합니다.
    • 프로필 간에 전환합니다 (지원되는 경우).
    • 새 정기 결제를 구매합니다.
    • 기존 정기 결제를 업그레이드합니다.
    • 정기 결제를 만료합니다.

통합 확인

통합을 테스트하려면 인증 앱을 사용하세요.

  1. 각 이벤트에 대해 앱이 publishSubscription API를 호출했는지 확인합니다. 인증 앱에서 게시된 데이터를 확인합니다. 인증 앱에서 모든 항목이 녹색인지 확인합니다.
  2. 모든 항목의 정보가 올바르면 모든 항목에 'All Good' 녹색 체크표시가 표시됩니다.

    인증 앱 성공 스크린샷
    그림 1. 정기 결제 성공
  3. 인증 앱에서 문제도 강조표시됩니다.

    인증 앱 오류 스크린샷
    그림 2.정기 결제 실패
  4. 번들 정기 결제에서 문제를 확인하려면 TV 리모컨을 사용하여 특정 번들 정기 결제에 초점을 맞추고 클릭하여 문제를 확인합니다. 먼저 행에 초점을 맞추고 오른쪽으로 이동하여 번들 정기 결제 카드를 찾아야 할 수 있습니다. 그림 3과 같이 문제가 빨간색으로 강조표시됩니다. 또한 리모컨을 사용하여 아래로 이동하여 번들 정기 결제 내의 권한 문제를 확인합니다.

    인증 앱 오류 세부정보 스크린샷
    그림 3.정기 결제 오류
  5. 권한 문제를 확인하려면 TV 리모컨을 사용하여 특정 권한에 초점을 맞추고 클릭하여 문제를 확인합니다. 문제가 빨간색으로 강조표시됩니다.

    인증 앱 오류 스크린샷
    그림 4.정기 결제 오류 세부정보