Google에서는 사용자의 앱을 카테고리별로 정리하고 맞춤형 앱 콘텐츠 소비와 검색을 위한 새로운 몰입형 환경을 제공하는 기기 내 노출 영역을 구축하고 있습니다. 이 전체 화면 환경을 통해 개발자 파트너는 앱 외부의 전용 채널에서 최고의 리치 콘텐츠를 선보일 수 있습니다.
이 가이드에는 개발자 파트너가 Engage SDK를 사용하여 이 새로운 표시 경로 영역과 기존 Google 표시 경로를 모두 채우는 방식으로 동영상 콘텐츠를 통합하는 방법에 관한 안내가 포함되어 있습니다.
통합 세부정보
용어
이 통합에는 맞춤 콘텐츠, 연속, 추천이라는 세 가지 클러스터 유형이 포함되어 있습니다.
맞춤 콘텐츠 클러스터에는 개별 개발자 파트너가 제안하는 시청할 만한 콘텐츠가 맞춤형으로 표시됩니다.
맞춤 콘텐츠의 구조는 다음과 같습니다.
맞춤 콘텐츠 클러스터: 동일한 개발자 파트너의 맞춤 콘텐츠 그룹이 포함된 UI 뷰입니다.
항목: 클러스터에 있는 단일 항목을 나타내는 객체입니다. 항목은 영화, TV 프로그램, TV 시리즈, 라이브 동영상 등이 될 수 있습니다. 지원되는 항목 유형 목록은 항목 데이터 제공 섹션을 참고하세요.
연속 클러스터에는 완료되지 않은 동영상과 여러 개발자 파트너의 새로 출시된 관련 에피소드가 하나의 UI 그룹으로 표시됩니다. 각 개발자 파트너는 연속 클러스터에서 최대 10개의 항목을 브로드캐스트할 수 있습니다. 연구에 따르면 맞춤형 연속 콘텐츠와 함께 맞춤 콘텐츠를 사용하면 최상의 사용자 참여를 이끌어낼 수 있습니다.
추천 클러스터는 여러 개발자 파트너의 선별된 항목을 하나의 UI 그룹으로 보여줍니다. 추천 클러스터는 1개가 표시되며 모든 맞춤 콘텐츠 클러스터보다 높은 우선순위로 UI 상단에 표시됩니다. 각 개발자 파트너는 추천 클러스터에서 최대 10개의 항목을 브로드캐스트할 수 있습니다.
사전 작업
최소 API 수준: 19
다음과 같이 com.google.android.engage:engage-core
라이브러리를 앱에 추가합니다.
dependencies {
// Make sure you also include that repository in your project's build.gradle file.
implementation 'com.google.android.engage:engage-core:1.5.2'
}
자세한 내용은 Android 11의 패키지 공개 상태를 참고하세요.
요약
설계는 바인드된 서비스의 구현을 기반으로 합니다.
클라이언트가 게시할 수 있는 데이터에는 다음과 같은 다양한 클러스터 유형의 제한이 적용됩니다.
클러스터 유형 | 클러스터 제한 | 클러스터의 최대 항목 제한 |
---|---|---|
맞춤 콘텐츠 클러스터 | 최대 5개 | 최대 50개 |
연속 클러스터 | 최대 1개 | 최대 10개 |
추천 클러스터 | 최대 1개 | 최대 10개 |
0단계: 기존 Media Home SDK 통합에서 이전
기존 통합의 데이터 모델 매핑
기존 Media Home 통합에서 이전하는 경우 기존 SDK의 데이터 모델을 새 Engage SDK에 매핑하는 방법이 다음 표에 요약되어 있습니다.
MediaHomeVideoContract 통합 대응 라이브러리 | Engage SDK 통합 대응 라이브러리 |
---|---|
com.google.android.mediahome.video.PreviewChannel
|
com.google.android.engage.common.datamodel.RecommendationCluster
|
com.google.android.mediahome.video.PreviewChannel.Builder
|
com.google.android.engage.common.datamodel.RecommendationCluster.Builder
|
com.google.android.mediahome.video.PreviewChannelHelper
|
com.google.android.engage.video.service.AppEngageVideoClient
|
com.google.android.mediahome.video.PreviewProgram |
별도의 클래스(EventVideo , LiveStreamingVideo , Movie , TvEpisode , TvSeason , TvShow , VideoClipEntity )로 나뉨
|
com.google.android.mediahome.video.PreviewProgram.Builder
|
별도의 클래스(EventVideo , LiveStreamingVideo , Movie , TvEpisode , TvSeason , TvShow , VideoClipEntity )의 빌더로 나뉨
|
com.google.android.mediahome.video.VideoContract |
더 이상 필요하지 않음 |
com.google.android.mediahome.video.WatchNextProgram |
별도의 클래스(EventVideoEntity , LiveStreamingVideoEntity , MovieEntity , TvEpisodeEntity , TvSeasonEntity , TvShowEntity , VideoClipEntity )의 속성으로 나뉨 |
com.google.android.mediahome.video.WatchNextProgram.Builder
|
별도의 클래스(EventVideoEntity , LiveStreamingVideoEntity , MovieEntity , TvEpisodeEntity , TvSeasonEntity , TvShowEntity , VideoClipEntity )의 속성으로 나뉨 |
Media Home SDK와 Engage SDK의 클러스터 게시 비교
Media Home SDK를 사용하여 클러스터와 항목이 별도의 API를 통해 게시되었습니다.
// 1. Fetch existing channels
List<PreviewChannel> channels = PreviewChannelHelper.getAllChannels();
// 2. If there are no channels, publish new channels
long channelId = PreviewChannelHelper.publishChannel(builder.build());
// 3. If there are existing channels, decide whether to update channel contents
PreviewChannelHelper.updatePreviewChannel(channelId, builder.build());
// 4. Delete all programs in the channel
PreviewChannelHelper.deleteAllPreviewProgramsByChannelId(channelId);
// 5. publish new programs in the channel
PreviewChannelHelper.publishPreviewProgram(builder.build());
Engage SDK를 사용하면 클러스터와 항목 게시가 단일 API 호출로 결합됩니다. 클러스터에 속하는 모든 항목은 해당 클러스터와 함께 게시됩니다.
Kotlin
RecommendationCluster.Builder() .addEntity(MOVIE_ENTITY) .addEntity(MOVIE_ENTITY) .addEntity(MOVIE_ENTITY) .setTitle("Top Picks For You") .build()
Java
new RecommendationCluster.Builder() .addEntity(MOVIE_ENTITY) .addEntity(MOVIE_ENTITY) .addEntity(MOVIE_ENTITY) .setTitle("Top Picks For You") .build();
1단계: 항목 데이터 제공
SDK는 각 항목 유형을 나타내는 여러 항목을 정의했습니다. Watch 카테고리에는 다음 항목이 지원됩니다.
다음 차트에는 각 유형의 속성과 요구사항이 요약되어 있습니다.
MovieEntity
속성 | 요구사항 | 참고 |
---|---|---|
이름 | 필수 항목 | |
포스터 이미지 | 필수 항목 | 이미지가 하나 이상 필요하며 가로세로 비율이 제공되어야 합니다. 가로 모드가 선호되지만 여러 시나리오를 지원하기 위해 세로 모드 이미지와 가로 모드 이미지를 모두 전달하는 것이 좋습니다.
자세한 내용은 이미지 사양을 참고하세요. |
재생 URI | 필수 항목 |
영화 재생을 시작할 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
정보 페이지 URI | 선택사항 |
영화에 관한 세부정보를 표시하는 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
출시일 | 필수 항목 | 에포크 밀리초 단위로 표시합니다. |
사용 가능 여부 | 필수 항목 | AVAILABLE: 사용자가 추가 작업 없이 콘텐츠를 사용할 수 있습니다. FREE_WITH_SUBSCRIPTION: 사용자가 정기 결제를 신청한 후에 콘텐츠를 사용할 수 있습니다. PAID_CONTENT: 사용자가 콘텐츠를 구매하거나 대여해야 합니다. PURCHASED: 사용자가 콘텐츠를 구매하거나 대여했습니다. |
제공 가격 | 선택사항 | 자유 형식의 텍스트로 표시합니다. |
시간 | 필수 항목 | 밀리초 단위로 표시합니다. |
장르 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. |
콘텐츠 등급 | 필수 항목 | 자유 형식의 텍스트로 표시하며 업계 표준을 따릅니다. (예) |
다음 볼만한 동영상 보기 유형 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 하며 다음 4가지 유형 중 하나여야 합니다. CONTINUE: 사용자가 이 콘텐츠를 1분을 초과하여 이미 시청했습니다. NEW: 사용자가 에피소드 형식 콘텐츠에서 제공되는 모든 에피소드를 시청했지만 새 에피소드가 제공되었으며 시청하지 않은 에피소드가 정확히 1개 있습니다. 이는 TV 프로그램, 시리즈로 녹화된 축구 경기 등에 적합합니다. NEXT: 사용자가 에피소드 형식 콘텐츠에서 에피소드를 하나 이상 완전히 시청했지만 에피소드가 두 개 이상 남아 있거나, 정확히 하나 남아 있는데 마지막 에피소드가 'NEW'가 아니며 사용자가 에피소드 형식 콘텐츠 시청을 시작하기 전에 공개되었습니다. WATCHLIST: 사용자가 다음 볼만한 동영상을 수동으로 선별하기 위해 관심 목록에 영화나 이벤트, 시리즈를 추가하는 것을 명시적으로 선택했습니다. |
최근 참여 시간 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
마지막 재생 위치 시간 | 조건부 필수 | 항목이 연속 클러스터에 있고 WatchNextType이 CONTINUE인 경우 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
TvShowEntity
속성 | 요구사항 | 참고 |
---|---|---|
이름 | 필수 항목 | |
포스터 이미지 | 필수 항목 | 이미지가 하나 이상 필요하며 가로세로 비율이 제공되어야 합니다. 가로 모드가 선호되지만 여러 시나리오를 지원하기 위해 세로 모드 이미지와 가로 모드 이미지를 모두 전달하는 것이 좋습니다.
자세한 내용은 이미지 사양을 참고하세요. |
정보 페이지 URI | 필수 항목 |
TV 프로그램 세부정보를 표시하는 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
재생 URI | 선택사항 |
TV 프로그램 재생을 시작할 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
첫 에피소드 방영일 | 필수 항목 | 에포크 밀리초 단위로 표시합니다. |
최신 에피소드 방영일 | 선택사항 | 에포크 밀리초 단위로 표시합니다. |
사용 가능 여부 | 필수 항목 | AVAILABLE: 사용자가 추가 작업 없이 콘텐츠를 사용할 수 있습니다. FREE_WITH_SUBSCRIPTION: 사용자가 정기 결제를 신청한 후에 콘텐츠를 사용할 수 있습니다. PAID_CONTENT: 사용자가 콘텐츠를 구매하거나 대여해야 합니다. PURCHASED: 사용자가 콘텐츠를 구매하거나 대여했습니다. |
제공 가격 | 선택사항 | 자유 형식의 텍스트로 표시합니다. |
시즌 개수 | 필수 항목 | 양의 정수로 표시합니다. |
장르 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. |
콘텐츠 등급 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. 업계 표준을 따르세요. (예) |
다음 볼만한 동영상 보기 유형 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 하며 다음 4가지 유형 중 하나여야 합니다. CONTINUE: 사용자가 이 콘텐츠를 1분을 초과하여 이미 시청했습니다. NEW: 사용자가 에피소드 형식 콘텐츠에서 제공되는 모든 에피소드를 시청했지만 새 에피소드가 제공되었으며 시청하지 않은 에피소드가 정확히 1개 있습니다. 이는 TV 프로그램, 시리즈로 녹화된 축구 경기 등에 적합합니다. NEXT: 사용자가 에피소드 형식 콘텐츠에서 에피소드를 하나 이상 완전히 시청했지만 에피소드가 두 개 이상 남아 있거나, 정확히 하나 남아 있는데 마지막 에피소드가 'NEW'가 아니며 사용자가 에피소드 형식 콘텐츠 시청을 시작하기 전에 공개되었습니다. WATCHLIST: 사용자가 다음 볼만한 동영상을 수동으로 선별하기 위해 관심 목록에 영화나 이벤트, 시리즈를 추가하는 것을 명시적으로 선택했습니다. |
최근 참여 시간 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
마지막 재생 위치 시간 | 조건부 필수 | 항목이 연속 클러스터에 있고 WatchNextType이 CONTINUE인 경우 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
TvSeasonEntity
속성 | 요구사항 | 참고 |
---|---|---|
이름 | 필수 항목 | |
포스터 이미지 | 필수 항목 | 이미지가 하나 이상 필요하며 가로세로 비율이 제공되어야 합니다. 가로 모드가 선호되지만 여러 시나리오를 지원하기 위해 세로 모드 이미지와 가로 모드 이미지를 모두 전달하는 것이 좋습니다.
자세한 내용은 이미지 사양을 참고하세요. |
정보 페이지 URI | 필수 항목 |
TV 프로그램 시즌의 세부정보를 표시하는 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고 |
재생 URI | 선택사항 |
TV 프로그램 시즌 재생을 시작할 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
시즌 번호 표시 |
선택사항 v1.3.1에서 사용 가능 |
문자열 |
첫 에피소드 방영일 | 필수 항목 | 에포크 밀리초 단위로 표시합니다. |
최신 에피소드 방영일 | 선택사항 | 에포크 밀리초 단위로 표시합니다. |
사용 가능 여부 | 필수 항목 | AVAILABLE: 사용자가 추가 작업 없이 콘텐츠를 사용할 수 있습니다. FREE_WITH_SUBSCRIPTION: 사용자가 정기 결제를 신청한 후에 콘텐츠를 사용할 수 있습니다. PAID_CONTENT: 사용자가 콘텐츠를 구매하거나 대여해야 합니다. PURCHASED: 사용자가 콘텐츠를 구매하거나 대여했습니다. |
제공 가격 | 선택사항 | 자유 형식의 텍스트로 표시합니다. |
에피소드 개수 | 필수 항목 | 양의 정수로 표시합니다. |
장르 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. |
콘텐츠 등급 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. 업계 표준을 따르세요. (예) |
다음 볼만한 동영상 보기 유형 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 하며 다음 4가지 유형 중 하나여야 합니다. CONTINUE: 사용자가 이 콘텐츠를 1분을 초과하여 이미 시청했습니다. NEW: 사용자가 에피소드 형식 콘텐츠에서 제공되는 모든 에피소드를 시청했지만 새 에피소드가 제공되었으며 시청하지 않은 에피소드가 정확히 1개 있습니다. 이는 TV 프로그램, 시리즈로 녹화된 축구 경기 등에 적합합니다. NEXT: 사용자가 에피소드 형식 콘텐츠에서 에피소드를 하나 이상 완전히 시청했지만 에피소드가 두 개 이상 남아 있거나, 정확히 하나 남아 있는데 마지막 에피소드가 'NEW'가 아니며 사용자가 에피소드 형식 콘텐츠 시청을 시작하기 전에 공개되었습니다. WATCHLIST: 사용자가 다음 볼만한 동영상을 수동으로 선별하기 위해 관심 목록에 영화나 이벤트, 시리즈를 추가하는 것을 명시적으로 선택했습니다. |
최근 참여 시간 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
마지막 재생 위치 시간 | 조건부 필수 | 항목이 연속 클러스터에 있고 WatchNextType이 CONTINUE인 경우 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
TvEpisodeEntity
속성 | 요구사항 | 참고 |
---|---|---|
이름 | 필수 항목 | |
포스터 이미지 | 필수 항목 | 이미지가 하나 이상 필요하며 가로세로 비율이 제공되어야 합니다. 가로 모드가 선호되지만 여러 시나리오를 지원하기 위해 세로 모드 이미지와 가로 모드 이미지를 모두 전달하는 것이 좋습니다.
자세한 내용은 이미지 사양을 참고하세요. |
재생 URI | 필수 항목 |
에피소드 재생을 시작할 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
정보 페이지 URI | 선택사항 |
TV 프로그램 에피소드에 관한 세부정보를 표시하는 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고 |
에피소드 번호 표시 |
선택사항 v1.3.1에서 사용 가능 |
문자열 |
방영일 | 필수 항목 | 에포크 밀리초 단위로 표시합니다. |
사용 가능 여부 | 필수 항목 | AVAILABLE: 사용자가 추가 작업 없이 콘텐츠를 사용할 수 있습니다. FREE_WITH_SUBSCRIPTION: 사용자가 정기 결제를 신청한 후에 콘텐츠를 사용할 수 있습니다. PAID_CONTENT: 사용자가 콘텐츠를 구매하거나 대여해야 합니다. PURCHASED: 사용자가 콘텐츠를 구매하거나 대여했습니다. |
제공 가격 | 선택사항 | 자유 형식의 텍스트로 표시합니다. |
시간 | 필수 항목 | 밀리초 단위의 양수여야 합니다. |
장르 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. |
콘텐츠 등급 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. 업계 표준을 따르세요. (예) |
다음 볼만한 동영상 보기 유형 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 하며 다음 4가지 유형 중 하나여야 합니다. CONTINUE: 사용자가 이 콘텐츠를 1분을 초과하여 이미 시청했습니다. NEW: 사용자가 에피소드 형식 콘텐츠에서 제공되는 모든 에피소드를 시청했지만 새 에피소드가 제공되었으며 시청하지 않은 에피소드가 정확히 1개 있습니다. 이는 TV 프로그램, 시리즈로 녹화된 축구 경기 등에 적합합니다. NEXT: 사용자가 에피소드 형식 콘텐츠에서 에피소드를 하나 이상 완전히 시청했지만 에피소드가 두 개 이상 남아 있거나, 정확히 하나 남아 있는데 마지막 에피소드가 'NEW'가 아니며 사용자가 에피소드 형식 콘텐츠 시청을 시작하기 전에 공개되었습니다. WATCHLIST: 사용자가 다음 볼만한 동영상을 수동으로 선별하기 위해 관심 목록에 영화나 이벤트, 시리즈를 추가하는 것을 명시적으로 선택했습니다. |
최근 참여 시간 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
마지막 재생 위치 시간 | 조건부 필수 | 항목이 연속 클러스터에 있고 WatchNextType이 CONTINUE인 경우 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
LiveStreamingVideoEntity
속성 | 요구사항 | 참고 |
---|---|---|
이름 | 필수 항목 | |
포스터 이미지 | 필수 항목 | 이미지가 하나 이상 필요하며 가로세로 비율이 제공되어야 합니다. 가로 모드가 선호되지만 여러 시나리오를 지원하기 위해 세로 모드 이미지와 가로 모드 이미지를 모두 전달하는 것이 좋습니다.
자세한 내용은 이미지 사양을 참고하세요. |
재생 URI | 필수 항목 |
동영상 재생을 시작할 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
방송사 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. |
시작 시간 | 선택사항 | 에포크 밀리초 단위로 표시합니다. |
종료 시간 | 선택사항 | 에포크 밀리초 단위로 표시합니다. |
조회수 | 선택사항 | 자유 형식의 텍스트로 표시하며 현지화해야 합니다. |
다음 볼만한 동영상 보기 유형 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 하며 다음 4가지 유형 중 하나여야 합니다. CONTINUE: 사용자가 이 콘텐츠를 1분을 초과하여 이미 시청했습니다. NEW: 사용자가 에피소드 형식 콘텐츠에서 제공되는 모든 에피소드를 시청했지만 새 에피소드가 제공되었으며 시청하지 않은 에피소드가 정확히 1개 있습니다. 이는 TV 프로그램, 시리즈로 녹화된 축구 경기 등에 적합합니다. NEXT: 사용자가 에피소드 형식 콘텐츠에서 에피소드를 하나 이상 완전히 시청했지만 에피소드가 두 개 이상 남아 있거나, 정확히 하나 남아 있는데 마지막 에피소드가 'NEW'가 아니며 사용자가 에피소드 형식 콘텐츠 시청을 시작하기 전에 공개되었습니다. WATCHLIST: 사용자가 다음 볼만한 동영상을 수동으로 선별하기 위해 관심 목록에 영화나 이벤트, 시리즈를 추가하는 것을 명시적으로 선택했습니다. |
최근 참여 시간 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
마지막 재생 위치 시간 | 조건부 필수 | 항목이 연속 클러스터에 있고 WatchNextType이 CONTINUE인 경우 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
VideoClipEntity
VideoClipEntity
객체는 TikTok 또는 YouTube와 같은 소셜 미디어의 동영상 항목을 나타냅니다.
속성 | 요구사항 | 참고 |
---|---|---|
이름 | 필수 항목 | |
포스터 이미지 | 필수 항목 | 이미지가 하나 이상 필요하며 가로세로 비율이 제공되어야 합니다. 가로 모드가 선호되지만 여러 시나리오를 지원하기 위해 세로 모드 이미지와 가로 모드 이미지를 모두 전달하는 것이 좋습니다.
자세한 내용은 이미지 사양을 참고하세요. |
재생 URI | 필수 항목 |
동영상 재생을 시작할 제공업체 앱의 딥 링크입니다. 참고: 기여 분석에 딥 링크를 사용할 수 있습니다. 이 FAQ 참고하기 |
만든 시간 | 필수 항목 | 에포크 밀리초 단위로 표시합니다. |
시간 | 필수 항목 | 밀리초 단위의 양수여야 합니다. |
크리에이터 | 필수 항목 | 자유 형식의 텍스트로 표시합니다. |
크리에이터 이미지 | 선택사항 | 크리에이터 아바타 이미지 |
조회수 | 선택사항 | 자유 형식의 텍스트로 표시하며 현지화해야 합니다. |
다음 볼만한 동영상 보기 유형 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 하며 다음 4가지 유형 중 하나여야 합니다. CONTINUE: 사용자가 이 콘텐츠를 1분을 초과하여 이미 시청했습니다. NEW: 사용자가 에피소드 형식 콘텐츠에서 제공되는 모든 에피소드를 시청했지만 새 에피소드가 제공되었으며 시청하지 않은 에피소드가 정확히 1개 있습니다. 이는 TV 프로그램, 시리즈로 녹화된 축구 경기 등에 적합합니다. NEXT: 사용자가 에피소드 형식 콘텐츠에서 에피소드를 하나 이상 완전히 시청했지만 에피소드가 두 개 이상 남아 있거나, 정확히 하나 남아 있는데 마지막 에피소드가 'NEW'가 아니며 사용자가 에피소드 형식 콘텐츠 시청을 시작하기 전에 공개되었습니다. WATCHLIST: 사용자가 다음 볼만한 동영상을 수동으로 선별하기 위해 관심 목록에 영화나 이벤트, 시리즈를 추가하는 것을 명시적으로 선택했습니다. |
최근 참여 시간 | 조건부 필수 | 항목이 연속 클러스터에 있으면 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
마지막 재생 위치 시간 | 조건부 필수 | 항목이 연속 클러스터에 있고 WatchNextType이 CONTINUE인 경우 제공해야 합니다. 에포크 밀리초 단위로 표시합니다. |
이미지 사양
다음 섹션에는 이미지 확장 소재의 필수 사양이 나와 있습니다.
파일 형식
PNG, JPG, 정적 GIF, WebP
최대 파일 크기
5120KB
추가 권장사항
- 이미지 안전 영역: 중요한 콘텐츠를 이미지의 중앙 80%에 배치합니다.
예
Kotlin
var movie = MovieEntity.Builder() .setName("Avengers") .addPosterImage(Image.Builder() .setImageUri(Uri.parse("http://www.x.com/image.png")) .setImageHeightInPixel(960) .setImageWidthInPixel(408) .build()) .setPlayBackUri(Uri.parse("http://tv.com/playback/1")) .setReleaseDateEpochMillis(1633032895L) .setAvailability(ContentAvailability.AVAILABILITY_AVAILABLE) .setDurationMillis(12345678L) .addGenre("action") .addContentRating("R") .setWatchNextType(WatchNextType.TYPE_NEW) .setLastEngagementTimeMillis(1664568895L) .build()
Java
MovieEntity movie = new MovieEntity.Builder() .setName("Avengers") .addPosterImage( new Image.Builder() .setImageUri(Uri.parse("http://www.x.com/image.png")) .setImageHeightInPixel(960) .setImageWidthInPixel(408) .build()) .setPlayBackUri(Uri.parse("http://tv.com/playback/1")) .setReleaseDateEpochMillis(1633032895L) .setAvailability(ContentAvailability.AVAILABILITY_AVAILABLE) .setDurationMillis(12345678L) .addGenre("action") .addContentRating("R") .setWatchNextType(WatchNextType.TYPE_NEW) .setLastEngagementTimeMillis(1664568895L) .build();
2단계: 클러스터 데이터 제공
콘텐츠 게시 작업을 백그라운드에서 실행하고(예: WorkManager 사용) 정기적으로 또는 이벤트를 기반으로 예약하는 것이 좋습니다(예: 사용자가 앱을 열 때마다 또는 사용자가 장바구니에 상품을 추가했을 때).
AppEngagePublishClient
는 클러스터 게시를 담당합니다. 클라이언트에서 사용할 수 있는 API는 다음과 같습니다.
isServiceAvailable
publishRecommendationClusters
publishFeaturedCluster
publishContinuationCluster
publishUserAccountManagementRequest
updatePublishStatus
deleteRecommendationsClusters
deleteFeaturedCluster
deleteContinuationCluster
deleteUserManagementCluster
deleteClusters
isServiceAvailable
이 API는 서비스를 통합에 사용할 수 있는지, 콘텐츠를 기기에 표시할 수 있는지 확인하는 데 사용됩니다.
Kotlin
client.isServiceAvailable.addOnCompleteListener { task -> if (task.isSuccessful) { // Handle IPC call success if(task.result) { // Service is available on the device, proceed with content publish // calls. } else { // Service is not available, no further action is needed. } } else { // The IPC call itself fails, proceed with error handling logic here, // such as retry. } }
Java
client.isServiceAvailable().addOnCompleteListener(task - > { if (task.isSuccessful()) { // Handle success if(task.getResult()) { // Service is available on the device, proceed with content publish // calls. } else { // Service is not available, no further action is needed. } } else { // The IPC call itself fails, proceed with error handling logic here, // such as retry. } });
publishRecommendationClusters
이 API는 RecommendationCluster
객체 목록을 게시하는 데 사용됩니다.
Kotlin
client.publishRecommendationClusters( PublishRecommendationClustersRequest.Builder() .addRecommendationCluster( RecommendationCluster.Builder() .addEntity(entity1) .addEntity(entity2) .setTitle("Top Picks For You") .build() ) .build() )
Java
client.publishRecommendationClusters( new PublishRecommendationClustersRequest.Builder() .addRecommendationCluster( new RecommendationCluster.Builder() .addEntity(entity1) .addEntity(entity2) .setTitle("Top Picks For You") .build()) .build());
서비스가 요청을 수신하면 다음 작업이 한 트랜잭션 내에서 발생합니다.
- 개발자 파트너의 기존
RecommendationCluster
데이터가 삭제됩니다. - 요청 데이터가 파싱되어, 업데이트된 맞춤 콘텐츠 클러스터에 저장됩니다.
오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
publishFeaturedCluster
이 API는 FeaturedCluster
객체 목록을 게시하는 데 사용됩니다.
Kotlin
client.publishFeaturedCluster( PublishFeaturedClusterRequest.Builder() .setFeaturedCluster( FeaturedCluster.Builder() .addEntity(entity1) .addEntity(entity2) .build()) .build())
Java
client.publishFeaturedCluster( new PublishFeaturedClustersRequest.Builder() .addFeaturedCluster( new FeaturedCluster.Builder() .addEntity(entity1) .addEntity(entity2) .build()) .build());
서비스가 요청을 수신하면 다음 작업이 한 트랜잭션 내에서 발생합니다.
- 개발자 파트너의 기존
FeaturedCluster
데이터가 삭제됩니다. - 요청 데이터가 파싱되어, 업데이트된 추천 클러스터에 저장됩니다.
오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
publishContinuationCluster
이 API는 ContinuationCluster
객체를 게시하는 데 사용됩니다.
Kotlin
client.publishContinuationCluster( PublishContinuationClusterRequest.Builder() .setContinuationCluster( ContinuationCluster.Builder() .addEntity(entity1) .addEntity(entity2) .build()) .build())
Java
client.publishContinuationCluster( new PublishContinuationClusterRequest.Builder() .setContinuationCluster( new ContinuationCluster.Builder() .addEntity(entity1) .addEntity(entity2) .build()) .build());
서비스가 요청을 수신하면 다음 작업이 한 트랜잭션 내에서 발생합니다.
- 개발자 파트너의 기존
ContinuationCluster
데이터가 삭제됩니다. - 요청 데이터가 파싱되어, 업데이트된 연속 클러스터에 저장됩니다.
오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
publishUserAccountManagementRequest
이 API는 로그인 카드를 게시하는 데 사용됩니다. 로그인 작업은 앱이 콘텐츠를 게시하거나 더 맞춤설정된 콘텐츠를 제공할 수 있도록 사용자를 앱의 로그인 페이지로 안내합니다.
다음 메타데이터는 로그인 카드의 일부입니다.
속성 | 요구사항 | 설명 |
---|---|---|
작업 URI | 필수 | 작업으로 연결되는 딥 링크(앱 로그인 페이지로 이동) |
이미지 | 선택사항 - 제공되지 않은 경우 제목을 입력해야 합니다. |
카드에 표시된 이미지 해상도 1264x712의 16x9 가로세로 비율 이미지 |
제목 | 선택사항 - 제공되지 않은 경우 이미지를 제공해야 합니다. | 카드상의 제목 |
작업 텍스트 | 선택사항 | CTA에 표시된 텍스트(로그인) |
부제 | 선택사항 | 카드의 부제목(선택사항) |
Kotlin
var SIGN_IN_CARD_ENTITY = SignInCardEntity.Builder() .addPosterImage( Image.Builder() .setImageUri(Uri.parse("http://www.x.com/image.png")) .setImageHeightInPixel(500) .setImageWidthInPixel(500) .build()) .setActionText("Sign In") .setActionUri(Uri.parse("http://xx.com/signin")) .build() client.publishUserAccountManagementRequest( PublishUserAccountManagementRequest.Builder() .setSignInCardEntity(SIGN_IN_CARD_ENTITY) .build());
Java
SignInCardEntity SIGN_IN_CARD_ENTITY = new SignInCardEntity.Builder() .addPosterImage( new Image.Builder() .setImageUri(Uri.parse("http://www.x.com/image.png")) .setImageHeightInPixel(500) .setImageWidthInPixel(500) .build()) .setActionText("Sign In") .setActionUri(Uri.parse("http://xx.com/signin")) .build(); client.publishUserAccountManagementRequest( new PublishUserAccountManagementRequest.Builder() .setSignInCardEntity(SIGN_IN_CARD_ENTITY) .build());
서비스가 요청을 수신하면 다음 작업이 한 트랜잭션 내에서 발생합니다.
- 개발자 파트너의 기존
UserAccountManagementCluster
데이터가 삭제됩니다. - 요청 데이터가 파싱되어, 업데이트된 UserAccountManagementCluster 클러스터에 저장됩니다.
오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
updatePublishStatus
내부적인 이유로 어떠한 클러스터도 게시되지 않는 경우 updatePublishStatus API를 사용하여 게시 상태를 업데이트할 것을 적극 권장합니다. 이는 다음과 같은 이유로 중요합니다.
- 콘텐츠가 게시되는 경우에도(STATUS == PUBLISHED) 모든 시나리오에서 상태를 제공하는 것은 이 명시적 상태를 사용하여 통합의 상태 및 기타 측정항목을 전달하는 대시보드를 채우는 데 중요합니다.
- 게시된 콘텐츠는 없지만 통합 상태가 손상되지 않은 경우(STATUS == NOT_PUBLISHED) Google은 앱 상태 대시보드에서 알림을 트리거하지 않을 수 있습니다. 이는 제공업체의 관점에서 예상되는 상황으로 인해 콘텐츠가 게시되지 않음을 확인합니다.
- 이를 통해 개발자는 데이터가 게시되는 시점과 게시되지 않는 시점에 관한 유용한 정보를 제공할 수 있습니다.
- Google에서는 상태 코드를 사용하여 사용자가 앱에서 특정 작업을 하도록 유도할 수 있습니다. 따라서 사용자가 앱 콘텐츠를 보거나 극복할 수 있습니다.
적합한 게시 상태 코드 목록은 다음과 같습니다.
// Content is published
AppEngagePublishStatusCode.PUBLISHED,
// Content is not published as user is not signed in
AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN,
// Content is not published as user is not subscribed
AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SUBSCRIPTION,
// Content is not published as user location is ineligible
AppEngagePublishStatusCode.NOT_PUBLISHED_INELIGIBLE_LOCATION,
// Content is not published as there is no eligible content
AppEngagePublishStatusCode.NOT_PUBLISHED_NO_ELIGIBLE_CONTENT,
// Content is not published as the feature is disabled by the client
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_FEATURE_DISABLED_BY_CLIENT,
// Content is not published as the feature due to a client error
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_CLIENT_ERROR,
// Content is not published as the feature due to a service error
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_SERVICE_ERROR,
// Content is not published due to some other reason
// Reach out to engage-developers@ before using this enum.
AppEngagePublishStatusCode.NOT_PUBLISHED_OTHER
로그인하지 않은 사용자로 인해 콘텐츠가 게시되지 않은 경우 로그인 카드를 게시하는 것이 좋습니다. 어떠한 이유로든 제공업체가 로그인 카드를 게시할 수 없는 경우 상태 코드 NOT_PUBLISHED_REQUIRES_SIGN_IN을 사용하여 updatePublishStatus API를 호출하는 것이 좋습니다.
Kotlin
client.updatePublishStatus( PublishStatusRequest.Builder() .setStatusCode(AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN) .build())
Java
client.updatePublishStatus( new PublishStatusRequest.Builder() .setStatusCode(AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN) .build());
deleteRecommendationClusters
이 API는 맞춤 콘텐츠 클러스터의 콘텐츠를 삭제하는 데 사용됩니다.
Kotlin
client.deleteRecommendationClusters()
Java
client.deleteRecommendationClusters();
서비스가 요청을 수신하면 맞춤 콘텐츠 클러스터에서 기존 데이터를 삭제합니다. 오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
deleteFeaturedCluster
이 API는 추천 클러스터의 콘텐츠를 삭제하는 데 사용됩니다.
Kotlin
client.deleteFeaturedCluster()
Java
client.deleteFeaturedCluster();
서비스가 요청을 수신하면 추천 클러스터에서 기존 데이터를 삭제합니다. 오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
deleteContinuationCluster
이 API는 연속 클러스터의 콘텐츠를 삭제하는 데 사용됩니다.
Kotlin
client.deleteContinuationCluster()
Java
client.deleteContinuationCluster();
서비스가 요청을 수신하면 연속 클러스터에서 기존 데이터를 삭제합니다. 오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
deleteUserManagementCluster
이 API는 UserAccountManagement 클러스터의 콘텐츠를 삭제하는 데 사용됩니다.
Kotlin
client.deleteUserManagementCluster()
Java
client.deleteUserManagementCluster();
서비스가 요청을 수신하면 UserAccountManagement 클러스터에서 기존 데이터를 삭제합니다. 오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
deleteClusters
이 API는 특정 클러스터 유형의 콘텐츠를 삭제하는 데 사용됩니다.
Kotlin
client.deleteClusters( DeleteClustersRequest.Builder() .addClusterType(ClusterType.TYPE_CONTINUATION) .addClusterType(ClusterType.TYPE_FEATURED) .addClusterType(ClusterType.TYPE_RECOMMENDATION) .build())
Java
client.deleteClusters( new DeleteClustersRequest.Builder() .addClusterType(ClusterType.TYPE_CONTINUATION) .addClusterType(ClusterType.TYPE_FEATURED) .addClusterType(ClusterType.TYPE_RECOMMENDATION) .build());
서비스가 요청을 수신하면 지정된 클러스터 유형과 일치하는 모든 클러스터에서 기존 데이터가 삭제됩니다. 클라이언트는 하나 이상의 클러스터 유형을 전달하도록 선택할 수 있습니다. 오류가 발생하면 전체 요청이 거부되고 기존 상태가 유지됩니다.
오류 처리
후속 작업을 실행하여 성공적인 작업을 복구하고 다시 제출할 수 있도록 게시 API의 작업 결과를 수신 대기하는 것이 좋습니다.
Kotlin
client.publishRecommendationClusters( PublishRecommendationClustersRequest.Builder() .addRecommendationCluster(..) .build()) .addOnCompleteListener { task -> if (task.isSuccessful) { // do something } else { val exception = task.exception if (exception is AppEngageException) { @AppEngageErrorCode val errorCode = exception.errorCode if (errorCode == AppEngageErrorCode.SERVICE_NOT_FOUND) { // do something } } } }
Java
client.publishRecommendationClusters( new PublishRecommendationClustersRequest.Builder() .addRecommendationCluster(...) .build()) .addOnCompleteListener( task -> { if (task.isSuccessful()) { // do something } else { Exception exception = task.getException(); if (exception instanceof AppEngageException) { @AppEngageErrorCode int errorCode = ((AppEngageException) exception).getErrorCode(); if (errorCode == AppEngageErrorCode.SERVICE_NOT_FOUND) { // do something } } } });
오류는 AppEngageException
으로 반환되며 원인은 오류 코드로 포함됩니다.
오류 코드 | 오류 이름 | 참고 |
---|---|---|
1 |
SERVICE_NOT_FOUND |
지정된 기기에서 서비스를 사용할 수 없습니다. |
2 |
SERVICE_NOT_AVAILABLE |
서비스는 특정 기기에서 사용할 수 있지만 호출 시점에는 사용할 수 없습니다(예: 명시적으로 사용 중지됨). |
3 |
SERVICE_CALL_EXECUTION_FAILURE |
스레딩 문제로 인해 작업을 실행할 수 없습니다. 이 경우 재시도할 수 있습니다. |
4 |
SERVICE_CALL_PERMISSION_DENIED |
호출자가 서비스를 호출할 수 없습니다. |
5 |
SERVICE_CALL_INVALID_ARGUMENT |
요청에 잘못된 데이터가 포함되어 있습니다(예: 허용된 클러스터 수를 초과함). |
6 |
SERVICE_CALL_INTERNAL |
서비스 측에 오류가 있습니다. |
7 |
SERVICE_CALL_RESOURCE_EXHAUSTED |
서비스 호출이 너무 자주 이루어집니다. |
3단계: 브로드캐스트 인텐트 처리
작업을 통해 게시 콘텐츠 API를 호출하는 것 외에도 콘텐츠 게시 요청을 수신하도록 BroadcastReceiver
를 설정해야 합니다.
브로드캐스트 인텐트의 목표는 주로 앱 재활성화 및 데이터 동기화 강제입니다. 브로드캐스트 인텐트는 자주 전송되지 않도록 설계되었습니다. 이는 참여 서비스에서 콘텐츠가 오래되었을 수 있다고 판단할 때만(예: 1주일) 트리거됩니다. 이렇게 하면 애플리케이션이 장기간 실행되지 않은 경우에도 사용자에게 새로운 콘텐츠 환경을 제공할 수 있습니다.
BroadcastReceiver
는 다음 두 가지 방법으로 설정해야 합니다.
Context.registerReceiver()
를 사용하여BroadcastReceiver
클래스의 인스턴스를 동적으로 등록합니다. 이렇게 하면 여전히 메모리에 있는 애플리케이션의 통신이 가능해집니다.
Kotlin
class AppEngageBroadcastReceiver : BroadcastReceiver(){ // Trigger recommendation cluster publish when PUBLISH_RECOMMENDATION broadcast // is received // Trigger featured cluster publish when PUBLISH_FEATURED broadcast is received // Trigger continuation cluster publish when PUBLISH_CONTINUATION broadcast is // received } fun registerBroadcastReceivers(context: Context){ var context = context context = context.applicationContext // Register Recommendation Cluster Publish Intent context.registerReceiver(AppEngageBroadcastReceiver(), IntentFilter(Intents.ACTION_PUBLISH_RECOMMENDATION)) // Register Featured Cluster Publish Intent context.registerReceiver(AppEngageBroadcastReceiver(), IntentFilter(Intents.ACTION_PUBLISH_FEATURED)) // Register Continuation Cluster Publish Intent context.registerReceiver(AppEngageBroadcastReceiver(), IntentFilter(Intents.ACTION_PUBLISH_CONTINUATION)) }
Java
class AppEngageBroadcastReceiver extends BroadcastReceiver { // Trigger recommendation cluster publish when PUBLISH_RECOMMENDATION broadcast // is received // Trigger featured cluster publish when PUBLISH_FEATURED broadcast is received // Trigger continuation cluster publish when PUBLISH_CONTINUATION broadcast is // received } public static void registerBroadcastReceivers(Context context) { context = context.getApplicationContext(); // Register Recommendation Cluster Publish Intent context.registerReceiver(new AppEngageBroadcastReceiver(), new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_RECOMMENDATION)); // Register Featured Cluster Publish Intent context.registerReceiver(new AppEngageBroadcastReceiver(), new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_FEATURED)); // Register Continuation Cluster Publish Intent context.registerReceiver(new AppEngageBroadcastReceiver(), new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_CONTINUATION)); }
AndroidManifest.xml
파일에서<receiver>
태그를 사용하여 구현을 정적으로 선언합니다. 이를 통해 애플리케이션이 실행 중이 아닐 때 브로드캐스트 인텐트를 수신할 수 있고, 애플리케이션이 콘텐츠를 게시할 수 있습니다.
<application>
<receiver
android:name=".AppEngageBroadcastReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="com.google.android.engage.action.PUBLISH_RECOMMENDATION" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.engage.action.PUBLISH_FEATURED" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.engage.action.PUBLISH_CONTINUATION" />
</intent-filter>
</receiver>
</application>
다음 인텐트가 서비스에서 전송됩니다.
com.google.android.engage.action.PUBLISH_RECOMMENDATION
이 인텐트를 수신할 때publishRecommendationClusters
호출을 시작하는 것이 좋습니다.com.google.android.engage.action.PUBLISH_FEATURED
이 인텐트를 수신할 때publishFeaturedCluster
호출을 시작하는 것이 좋습니다.com.google.android.engage.action.PUBLISH_CONTINUATION
이 인텐트를 수신할 때publishContinuationCluster
호출을 시작하는 것이 좋습니다.
통합 워크플로
통합 완료 후 통합 확인에 관한 단계별 안내는 Engage 개발자 통합 워크플로를 참고하세요.
FAQ
FAQ에 관해서는 Engage SDK 관련 자주 묻는 질문(FAQ)을 참고하세요.
문의
통합 과정에서 궁금한 점이 있으면 engage-developers@google.com으로 문의해 주세요.
다음 단계
이 통합을 완료한 후 단계는 다음과 같습니다.
- engage-developers@google.com으로 Google의 테스트를 받을 준비가 된 통합 APK를 첨부하여 이메일을 보냅니다.
- Google은 내부적으로 인증 및 검토를 실행하여 통합이 예상대로 작동하는지 확인합니다. 변경이 필요한 경우 Google에서는 필요한 세부정보와 함께 연락을 드립니다.
- 테스트가 완료되고 아무것도 변경할 필요가 없으면 Google에서는 업데이트된 통합 APK를 Play 스토어에 게시할 수 있음을 알려 드립니다.
- 업데이트된 APK가 Play 스토어에 게시되었음을 Google에서 확인한 후에는 맞춤 콘텐츠, 추천, 연속 클러스터가 게시되고 사용자에게 표시될 수 있습니다.