TV용 Engage SDK 통합 가이드

이어서 시청하기는 연속 클러스터를 활용하여 여러 앱의 완료되지 않은 동영상과 동일한 TV 시즌에서 시청할 다음 에피소드를 하나의 UI 그룹으로 표시합니다. 이 연속 클러스터에서 이러한 항목을 표시할 수 있습니다. 이 가이드를 따라 Engage SDK를 사용하여 이어서 시청 환경을 통해 사용자 참여도를 높이는 방법을 알아보세요.

1단계: 사전 작업

시작하기 전에 다음 단계를 완료하세요.

이 통합을 위해 앱이 API 수준 19 이상을 타겟팅하는지 확인

  1. 다음과 같이 com.google.android.engage 라이브러리를 앱에 추가합니다.

    통합에 사용할 수 있는 SDK는 모바일 앱용 SDK와 TV 앱용 SDK로 각각 다릅니다.

    모바일

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

    TV

    
      dependencies {
        implementation 'com.google.android.engage:engage-tv:1.0.2
      }
    
  2. AndroidManifest.xml 파일에서 Engage 서비스 환경을 프로덕션으로 설정합니다.

    모바일

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

    TV

    
    <meta-data
        android:name="com.google.android.engage.service.ENV"
        android:value="PRODUCTION">
    </meta-data>
    
  3. TV APK에 WRITE_EPG_DATA 권한 추가

      <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
    
  4. 예약에 androidx.work와 같은 백그라운드 서비스를 사용하여 안정적인 콘텐츠 게시를 보장합니다.

  5. 원활한 시청 환경을 제공하려면 다음 이벤트가 발생할 때 이어서 시청 데이터를 게시하세요.

    1. 첫 로그인: 사용자가 처음 로그인하면 데이터를 게시하면 시청 기록을 즉시 사용할 수 있습니다.
    2. 프로필 생성 또는 전환 (다중 프로필 앱): 앱에서 여러 프로필을 지원하는 경우 사용자가 프로필을 만들거나 전환할 때 데이터를 게시합니다. 이렇게 하면 각 사용자에게 맞춤 환경이 제공됩니다.
    3. 동영상 재생 중단: 사용자가 중단한 지점부터 다시 시작할 수 있도록 동영상을 일시중지하거나 중지할 때 또는 재생 중에 앱이 종료될 때 데이터를 게시합니다.
    4. 이어서 시청하기 트레이 업데이트 (지원되는 경우): 사용자가 이어서 시청하기 트레이에서 항목을 삭제하면 업데이트된 데이터를 게시하여 변경사항을 반영합니다. 이렇게 하면 트레이가 관련성 있고 맞춤설정된 상태로 유지됩니다.
    5. 동영상 완료:
      1. 영화의 경우 '이어서 시청하기' 트레이에서 시청이 완료된 영화를 삭제합니다. 영화가 시리즈에 속하는 경우 다음 영화를 추가하여 사용자의 참여를 유도합니다.
      2. 에피소드의 경우 시청이 완료된 에피소드를 삭제하고 시리즈의 다음 에피소드(있는 경우)를 추가하여 계속 시청하도록 유도합니다.

통합

AccountProfile

Google TV에서 맞춤설정된 '이어 볼만한 동영상' 환경을 사용하려면 계정 및 프로필 정보를 제공하세요. AccountProfile을 사용하여 다음을 제공합니다.

  1. 계정 ID: 애플리케이션 내에서 사용자의 계정을 나타내는 고유 식별자입니다. 실제 계정 ID이거나 적절하게 난독화된 버전일 수 있습니다.

  2. 프로필 ID (선택사항): 애플리케이션이 단일 계정 내에서 여러 프로필을 지원하는 경우 특정 사용자 프로필의 고유 식별자(실제 또는 난독화된 식별자)를 제공합니다.

// If your app only supports account
val accountProfile = AccountProfile.Builder()
      .setAccountId("your_users_account_id")
      .build()
// If your app supports both account and profile
val accountProfile = AccountProfile.Builder()
      .setAccountId("your_users_account_id")
      .setProfileId("your_users_profile_id")
.build()

항목 만들기

SDK는 각 항목 유형을 나타내는 여러 항목을 정의했습니다. 연속 클러스터는 다음 항목을 지원합니다.

  1. MovieEntity
  2. TvEpisodeEntity
  3. LiveStreamingVideoEntity
  4. VideoClipEntity

이러한 항목의 플랫폼별 URI 및 포스터 이미지를 지정합니다.

아직 만들지 않았다면 Android TV, Android, iOS와 같은 각 플랫폼의 재생 URI도 만듭니다. 따라서 사용자가 각 플랫폼에서 시청을 계속할 때 앱은 타겟팅된 재생 URI를 사용하여 동영상 콘텐츠를 재생합니다.

// Required. Set this when you want continue watching entities to show up on
// Google TV
val playbackUriTv =
          PlatformSpecificUri.Builder()
              .setPlatformType(PlatformType.TYPE_ANDROID_TV)
              .setActionUri(Uri.parse("https://www.example.com/entity_uri_for_tv"))
              .build()

// Required. Set this when you want continue watching entities to show up on
// Google TV Android app, Entertainment Space, Playstore Widget
val playbackUriAndroid =
          PlatformSpecificUri.Builder()
              .setPlatformType(PlatformType.TYPE_ANDROID_MOBILE)
              .setActionUri(Uri.parse("https://www.example.com/entity_uri_for_android"))
              .build()
// Optional. Set this when you want continue watching entities to show up on
// Google TV iOS app
val playbackUriIos =
          PlatformSpecificUri.Builder()
              .setPlatformType(PlatformType.TYPE_IOS)
              .setActionUri(Uri.parse("https://www.example.com/entity_uri_for_ios"))
              .build()
 val platformSpecificPlaybackUris =
          Arrays.asList(playbackUriTv, playbackUriAndroid, playbackUriIos)

포스터 이미지에는 URI와 픽셀 크기 (높이 및 너비)가 필요합니다. 여러 포스터 이미지를 제공하여 다양한 폼 팩터를 타겟팅하되, 특히 Google의 엔터테인먼트 스페이스 내에서 '시청한 콘텐츠 이어서 보기' 항목을 올바르게 표시하려면 모든 이미지가 16:9 가로세로 비율과 최소 200픽셀의 높이를 유지해야 합니다. 높이가 200픽셀 미만인 이미지는 표시되지 않을 수 있습니다.


Image image1 = new Image.Builder()
            .setImageUri(Uri.parse("http://www.example.com/entity_image1.png");)
            .setImageHeightInPixel(300)
            .setImageWidthInPixel(169)
            .build()
Image image2 = new Image.Builder()
            .setImageUri(Uri.parse("http://www.example.com/entity_image2.png");)
            .setImageHeightInPixel(640)
            .setImageWidthInPixel(360)
            .build()
// And other images for different form factors.
val images = Arrays.asList(image1, image2)
MovieEntity

다음 예에서는 모든 필수 입력란이 포함된 MovieEntity를 만드는 방법을 보여줍니다.

val movieEntity = MovieEntity.Builder()
   .setWatchNextType(WatchNextType.TYPE_CONTINUE)
   .setName("Movie name")
   .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
   .addPosterImages(images)
   // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
   .setLastEngagementTimeMillis(1701388800000)
   // Suppose the duration is 2 hours, it is 72000000 in milliseconds
   .setDurationMills(72000000)
   // Suppose last playback offset is 1 hour, 36000000 in milliseconds
   .setLastPlayBackPositionTimeMillis(36000000)
   .build()

장르 및 콘텐츠 등급과 같은 세부정보를 제공하면 Google TV에서 콘텐츠를 더 역동적인 방식으로 표시하고 적합한 시청자와 연결할 수 있습니다.

val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build();
val contentRatings = Arrays.asList(rating1);
val movieEntity = MovieEntity.Builder()
    ...
    .addGenres(genres)
    .addContentRatings(contentRatings)
    .build()

더 짧은 만료 시간을 지정하지 않는 한 항목은 60일 동안 자동으로 계속 사용할 수 있습니다. 이 기본 기간 전에 항목을 삭제해야 하는 경우에만 맞춤 만료를 설정하세요.

// Set the expiration time to be now plus 30 days in milliseconds
val expirationTime = new DisplayTimeWindow.Builder()
             .setEndTimestampMillis(now().toMillis()+2592000000).build()
val movieEntity = MovieEntity.Builder()
    ...
    .addAvailabilityTimeWindow(expirationTime)
    .build()
TvEpisodeEntity

다음 예에서는 모든 필수 입력란이 포함된 TvEpisodeEntity를 만드는 방법을 보여줍니다.

val tvEpisodeEntity = TvEpisodeEntity.Builder()
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Episode name")
    .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMills(72000000) // 2 hours in milliseconds
    // 45 minutes and 15 seconds in milliseconds is 2715000
    .setLastPlayBackPositionTimeMillis(2715000)
    .setEpisodeNumber("2")
    .setSeasonNumber("1")
    .setShowTitle("Title of the show")
    .build();

에피소드 번호 문자열 (예: "2") 및 시즌 번호 문자열 (예: "1")은 연속 시청 카드에 표시되기 전에 적절한 형식으로 확장됩니다. 숫자 문자열이어야 합니다. 'e2', 'episode 2', 's1' 또는 'season 1'은 입력하지 마세요.

특정 TV 프로그램에 시즌이 하나만 있는 경우 시즌 번호를 1로 설정합니다.

시청자가 Google TV에서 내 콘텐츠를 찾을 가능성을 극대화하려면 장르, 콘텐츠 등급, 사용 가능 시간대와 같은 추가 데이터를 제공해 보세요. 이러한 세부정보는 디스플레이 및 필터링 옵션을 개선할 수 있습니다.

val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val tvEpisodeEntity = TvEpisodeEntity.Builder()
    ...
    .addGenres(genres)
    .addContentRatings(contentRatings)
    .setSeasonTitle("Season Title")
    .setShowTitle("Show Title)
    .build();
VideoClipEntity

다음은 모든 필수 입력란이 포함된 VideoClipEntity를 만드는 예입니다.

VideoClipEntity는 YouTube 동영상과 같은 사용자가 생성한 클립을 나타냅니다.

val videoClipEntity = VideoClipEntity.Builder()
    .setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform")
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Video clip name")
    .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMills(600000) //10 minutes in milliseconds
    .setLastPlayBackPositionTimeMillis(300000) //5 minutes in milliseconds
    .addContentRating(contentRating)
    .build();

원하는 경우 크리에이터, 크리에이터 이미지, 생성 시간(밀리초), 사용 가능 시간대를 설정할 수 있습니다 .

LiveStreamingVideoEntity

다음은 모든 필수 입력란이 포함된 LiveStreamingVideoEntity를 만드는 예입니다.

val liveStreamingVideoEntity = LiveStreamingVideoEntity.Builder()
    .setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform")
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Live streaming name")
    .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMills(72000000) //2 hours in milliseconds
    .setLastPlayBackPositionTimeMillis(36000000) //1 hour in milliseconds
    .addContentRating(contentRating)
    .build();

원하는 경우 라이브 스트리밍 항목의 시작 시간, 방송사, 방송사 아이콘 또는 사용 가능 시간대를 설정할 수 있습니다.

속성 및 요구사항에 관한 자세한 내용은 API 참조를 참고하세요.

연속 클러스터 데이터 제공

AppEngagePublishClient는 연속 클러스터를 게시합니다. publishContinuationCluster() 메서드를 사용하여 ContinuationCluster 객체를 게시합니다.

먼저 isServiceAvailable()를 사용하여 서비스를 통합할 수 있는지 확인해야 합니다.

client.publishContinuationCluster(
    PublishContinuationClusterRequest
        .Builder()
        .setContinuationCluster(
            ContinuationCluster
                .Builder()
                .setAccountProfile(accountProfile)
                .addEntity(movieEntity1)
                .addEntity(movieEntity2)
                .addEntity(tvEpisodeEntity1)
                .addEntity(tvEpisodeEntity2)
                .setSyncAcrossDevices(true)
                .build()
        )
        .build();
)

서비스가 요청을 수신하면 다음 작업이 한 트랜잭션 내에서 발생합니다.

  • 개발자 파트너의 기존 ContinuationCluster 데이터가 삭제됩니다.
  • 요청 데이터가 파싱되어, 업데이트된 ContinuationCluster에 저장됩니다.

오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.

게시 API는 upsert API입니다. 기존 콘텐츠를 대체합니다. ContinuationCluster에서 특정 항목을 업데이트해야 하는 경우 모든 항목을 다시 게시해야 합니다.

ContinuationCluster 데이터는 성인 계정에만 제공해야 합니다. AccountProfile이 성인 소유인 경우에만 게시합니다.

교차 기기 동기화

SyncAcrossDevices 플래그

이 플래그는 사용자의 ContinuationCluster 데이터가 기기 (TV, 휴대전화, 태블릿 등) 간에 동기화되는지 여부를 제어합니다. 기본값은 false이므로 교차 기기 동기화가 기본적으로 사용 중지됩니다.

값:

  • true: 원활한 시청 환경을 위해 ContinuationCluster 데이터가 모든 사용자 기기에서 공유됩니다. 최적의 교차 기기 환경을 위해 이 옵션을 사용하는 것이 좋습니다.
  • false: ContinuationCluster 데이터는 현재 기기로 제한됩니다.

미디어 애플리케이션은 교차 기기 동기화를 사용 설정/사용 중지하는 명확한 설정을 제공해야 합니다. 사용자에게 이점을 설명하고 사용자의 환경설정을 한 번 저장한 후 적절하게 publishContinuationCluster에 적용합니다.

// Example to allow cross device syncing.
client.publishContinuationCluster(
    PublishContinuationClusterRequest
        .Builder()
        .setContinuationCluster(
            ContinuationCluster
                .Builder()
                .setAccountProfile(accountProfile)
                .setSyncAcrossDevices(true)
                .build();
        )
        .build();
)

교차 기기 기능을 최대한 활용하려면 앱에서 사용자 동의를 얻고 SyncAcrossDevices를 true로 사용 설정하세요. 이를 통해 콘텐츠를 여러 기기에서 원활하게 동기화할 수 있으므로 사용자 환경이 개선되고 참여도가 높아집니다. 예를 들어 이 기능을 구현한 파트너는 콘텐츠가 여러 기기에 표시되어 '시청한 부분부터 다시 시작' 클릭수가 40% 증가했습니다.

동영상 탐색 데이터 삭제

표준 60일 보관 기간이 지나기 전에 Google TV 서버에서 사용자의 데이터를 수동으로 삭제하려면 client.deleteClusters() 메서드를 사용하세요. 요청을 수신하면 서비스는 계정 프로필 또는 전체 계정의 기존 동영상 검색 데이터를 모두 삭제합니다.

DeleteReason enum은 데이터 삭제 이유를 정의합니다. 다음 코드는 로그아웃 시 이어서 시청 데이터를 삭제합니다.


// If the user logs out from your media app, you must make the following call
// to remove continue watching data from the current google TV device,
// otherwise, the continue watching data will persist on the current
// google TV device until 60 days later.
client.deleteClusters(
  new DeleteClustersRequest.Builder()
        .setAccountProfile(AccountProfile())
        .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
        .setSyncAcrossDevices(true)
        .build()
)

테스트

인증 앱을 사용하여 Engage SDK 통합이 올바르게 작동하는지 확인합니다. 이 Android 애플리케이션은 데이터를 확인하고 브로드캐스트 인텐트가 올바르게 처리되고 있는지 확인하는 데 도움이 되는 도구를 제공합니다.

publish API를 호출한 후 인증 앱을 확인하여 데이터가 올바르게 게시되고 있는지 확인합니다. 연속 클러스터가 앱 인터페이스 내에 별도의 행으로 표시되어야 합니다.

  • Engage Service Flag가 앱의 Android 매니페스트 파일에서 프로덕션으로 설정되어 있지 않은지 확인합니다.
  • Engage Verify 앱을 설치하고 엽니다.
  • isServiceAvailablefalse이면 '전환' 버튼을 클릭하여 사용 설정합니다.
  • 게시를 시작하면 게시된 데이터를 자동으로 보려면 앱의 패키지 이름을 입력합니다.
  • 앱에서 다음 작업을 테스트합니다.
    • 로그인합니다.
    • 프로필 간 전환하기(해당하는 경우)
    • 동영상을 시작하거나 일시중지하거나 홈페이지로 돌아갑니다.
    • 동영상 재생 중에 앱을 닫습니다.
    • '시청한 항목' 행에서 항목을 삭제합니다 (지원되는 경우).
  • 각 작업 후 앱이 publishContinuationClusters API를 호출했는지, 데이터가 인증 앱에 올바르게 표시되는지 확인합니다.
  • 올바르게 구현된 항목에는 인증 앱에 녹색 '좋음' 체크가 표시됩니다.

    인증 앱 성공 스크린샷
    그림 1. 인증 앱 성공
  • 인증 앱에서 문제가 있는 항목을 표시합니다.

    인증 앱 오류 스크린샷
    그림 2. 인증 앱 오류
  • 오류가 있는 항목을 해결하려면 TV 리모컨을 사용하여 인증 앱에서 항목을 선택하고 클릭합니다. 검토를 위해 특정 문제가 표시되고 빨간색으로 강조 표시됩니다 (아래 예 참고).

    인증 앱 오류 세부정보
    그림 3. 인증 앱 오류 세부정보