Engage SDK 视频推荐

本指南包含开发者说明,介绍如何使用 Engage SDK 集成他们推荐的视频内容,以填充 Google 平台(例如电视、移动设备和平板电脑)上的推荐体验。

推荐功能利用 推荐集群在一个 UI 分组中显示来自多个应用的电影和电视节目。每个开发者合作伙伴在每个推荐集群中最多可以广播 25 个实体,每个请求最多可以有 7 个推荐集群。

前期准备

在开始之前,请完成以下步骤。1. 验证您的应用针对此集成将 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. 在前台服务上执行发布。

  4. 每天最多发布一次推荐数据,触发条件为以下任一情况:

    1. 用户当天首次登录。(
    2. 用户开始与应用互动时。

集成

AppEngagePublishClient 发布推荐集群。使用 publishRecommendationClusters 方法发布推荐对象。

使用 isServiceAvailable()2 检查服务是否可用于集成。

val client = AppEngagePublishClient(context)

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.
      client.publishRecommendationClusters(recommendationRequest)
    } else {
      // Service is not available
    }
  } else {
    // The IPC call itself fails, proceed with error handling logic here,
    // such as retry.
  }
}

推荐集群和发布请求

集群是实体的逻辑分组。以下代码示例解释了如何根据您的偏好构建集群,以及如何为所有集群创建发布请求。

// cluster for popular movies
val recommendationCluster1 = RecommendationCluster
  .Builder()
  .addEntity(movie)
  .addEntity(tvShow)
  .setTitle("Popular Movies")
  .build()

// cluster for top searches
val recommendationCluster2 = RecommendationCluster
  .Builder()
  .addEntity(movie)
  .addEntity(tvShow)
  .setTitle("Top Searches")
  .build()

// creating a publishing request
val recommendationRequest = PublishRecommendationClustersRequest
  .Builder()
  .setSyncAcrossDevices(true)
  .setAccountProfile(accountProfile)
  .addRecommendationCluster(recommendationCluster1)
  .addRecommendationCluster(recommendationCluster2)
  .build()

创建帐号资料

为了在 Google TV 上提供个性化体验,请提供帐号和资料信息。使用 AccountProfile 提供:

  1. 帐号 ID:代表用户在您应用中的帐号的唯一标识符。可以是实际的帐号 ID,也可以是经过适当混淆的版本。
  2. 资料 ID(可选):如果您的应用支持单个帐号下的多个资料,请为特定的用户资料提供唯一标识符。
  3. 区域设置(可选):您可以选择提供用户的首选语言。如果您在 RecommendationRequest 中发送 MediaActionFeedEntity,此字段会很有用。
// If app only supports account
val accountProfile = AccountProfile.Builder()
  .setAccountId("account_id")
  .build();

// If app supports both account and profile
val accountProfile = AccountProfile.Builder()
  .setAccountId("account_id")
  .setProfileId("profile_id")
  .build();

// set Locale
val accountProfile = AccountProfile.Builder()
  .setAccountId("account_id")
  .setProfileId("profile_id")
  .setLocale("en-US")
  .build();

当服务收到请求时,会在一个事务中发生以下操作:

  • 删除开发者合作伙伴的现有 RecommendationsCluster 数据。
  • 请求中的数据会被解析并存储在更新后的 RecommendationsCluster 中。如果发生错误,整个请求将被拒绝,并保留现有状态。

跨设备同步

SyncAcrossDevices 标志控制用户的推荐集群数据是否与 Google TV 共享,并在其设备(如电视、手机、平板电脑)上可用。为了使推荐正常工作,此标志必须设置为 true。

媒体应用必须提供明确的设置以启用或禁用跨设备同步。向用户解释其好处,并一次性存储用户的偏好,然后相应地将其应用于 publishRecommendations 请求。为了充分利用跨设备功能,请验证应用是否获得了用户同意并启用了 SyncAcrossDevicestrue

删除视频发现数据

要在标准 60 天保留期之前手动从 Google TV 服务器删除用户数据,请使用 client.deleteClusters() 方法。收到请求后,服务将删除该帐号资料或整个帐号的所有现有视频发现数据。

DeleteReason 枚举定义了数据删除的原因。以下代码在退出登录时移除推荐。

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

// If the user revokes the consent to share data with Google TV,
// you must make the following call to remove recommendations data from
// all current google TV devices. Otherwise, the recommendations data persists
// until 60 days later.
client.deleteClusters(
  new DeleteClustersRequest.Builder()
    .setAccountProfile(AccountProfile())
    .setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
    .build()
)

创建实体

SDK 定义了不同的实体来表示每种项目类型。推荐集群支持以下实体:

  1. MediaActionFeedEntity
  2. MovieEntity
  3. TvShowEntity

说明

为每个实体提供简短说明;当用户将鼠标悬停在实体上时,此说明将显示,为他们提供更多详细信息。

平台专用播放 URI

为每个受支持的平台(Android TV、Android 或 iOS)创建播放 URI。这允许系统选择适合在相应平台上播放视频的 URI。

在极少数情况下,如果所有平台的播放 URI 相同,请为每个平台重复设置。

// Required. Set this when you want recommended 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()

// Optional. Set this when you want recommended entities to show up on
// Google TV Android app
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 recommended 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)

// Provide appropriate rating for the system.
val contentRating = new RatingSystem
  .Builder()
  .setAgencyName("MPAA")
  .setRating("PG-13")
  .build()

海报图片

海报图片需要 URI 和像素尺寸(高度和宽度)。通过提供多张海报图片来针对不同的外形规格,但请验证所有图片都保持 16:9 的纵横比和至少 200 像素的高度,以正确显示“推荐”实体,尤其是在 Google 的娱乐空间中。高度小于 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)

推荐原因

(可选)提供推荐原因,Google TV 可使用此原因来构建向用户建议特定电影或电视节目的理由。

//Allows us to construct reason: "Because it is top 10 on your Channel"
val topOnPartner = RecommendationReasonTopOnPartner
  .Builder()
  .setNum(10) //any valid integer value
  .build()

//Allows us to construct reason: "Because it is popular on your Channel"
val popularOnPartner = RecommendationReasonPopularOnPartner
  .Builder()
  .build()

//Allows us to construct reason: "New to your channel, or Just added"
val newOnPartner = RecommendationReasonNewOnPartner
  .Builder()
  .build()

//Allows us to construct reason: "Because you watched Star Wars"
val watchedSimilarTitles = RecommendationReasonWatchedSimilarTitles
  .addSimilarWatchedTitleName("Movie or TV Show Title")
  .addSimilarWatchedTitleName("Movie or TV Show Title")
  .Builder()
  .build()

//Allows us to construct reason: "Recommended for you by ChannelName"
val recommendedForUser = RecommendationReasonRecommendedForUser
  .Builder()
  .build()

val watchAgain = RecommendationReasonWatchAgain
  .Builder()
  .build()

val fromUserWatchList = RecommendationReasonFromUserWatchlist
  .Builder()
  .build()

val userLikedOnPartner = RecommendationReasonUserLikedOnPartner
  .Builder()
  .setTitleName("Movie or TV Show Title")
  .build()

val generic = RecommendationReasonGeneric.Builder().build()

显示时间窗口

如果实体只能在有限时间内可用,请设置自定义有效期。如果没有明确的有效期,实体将在 60 天后自动过期并被删除。因此,仅当实体需要更快过期时才设置有效期。指定多个此类可用性窗口。

val window1 = DisplayTimeWindow
  .Builder()
  .setStartTimeStampMillis(now()+ 1.days.toMillis())
  .setEndTimeStampMillis(now()+ 30.days.toMillis())

val window2 = DisplayTimeWindow
  .Builder()
  .setEndTimeStampMillis(now()+ 30.days.toMillis())

val availabilityTimeWindows: List<DisplayTimeWindow> = listof(window1,window2)

DataFeedElementId

如果您已将媒体目录或媒体操作 Feed 与 Google TV 集成,则无需为电影或电视节目创建单独的实体,您可以改为创建包含必填字段 DataFeedElementId 的 MediaActionFeed 实体。此 ID 必须是唯一的,并且必须与媒体操作 Feed 中的 ID 匹配,因为它有助于识别已摄取的 Feed 内容并执行媒体内容查找。

val id = "dataFeedEleemntId"

MovieEntity

这是创建包含所有必填字段的 MovieEntity 的示例:


val movieEntity = MovieEntity.Builder()
  .setName("Movie name")
  .setDescription("A sentence describing movie.")
  .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
  .addPosterImages(images)
  // Suppose the duration is 2 hours, it is 72000000 in milliseconds
  .setDurationMills(72000000)
  .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);
//Suppose release date is 11-02-2025
val releaseDate  = 1739233800000L
val movieEntity = MovieEntity.Builder()
  ...
  .addGenres(genres)
  .setReleaseDateEpochMillis(releaseDate)
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addAllAvailabilityTimeWindows(availabilityTimeWindows)
  .build()

TvShowEntity

这是创建包含所有必填字段的 TvShowEntity 的示例:

val tvShowEntity = TvShowEntity.Builder()
  .setName("Show title")
  .setDescription("A sentence describing TV Show.")
  .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
  .addPosterImages(images)
  .build();

(可选)提供其他数据,例如类型、内容分级、推荐原因、优惠价格、季数或可用时间窗口,Google TV 可能会使用这些数据来增强显示或用于过滤目的。

val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build();
val price = Price.Builder()
  .setCurrentPrice("$14.99")
  .setStrikethroughPrice("$16.99")
  .build();
val contentRatings = Arrays.asList(rating1);
val seasonCount = 5;
val tvShowEntity = TvShowEntity.Builder()
  ...
  .addGenres(genres)
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addAllAvailabilityTimeWindows(availabilityTimeWindows)
  .setSeasonCount(seasonCount)
  .setPrice(price)
  .build()

MediaActionFeedEntity

这是创建包含所有必填字段的 MediaActionFeedEntity 的示例:


val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
  .setDataFeedElementId(id)
  .build()

(可选)提供其他数据,例如说明、推荐原因和显示时间窗口,Google TV 可能会使用这些数据来增强显示或用于过滤目的。

val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
  .setName("Movie name or TV Show name")
  .setDescription("A sentence describing an entity")
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addPosterImages(images)
  .build()

通过实施这些步骤,开发者可以将视频内容推荐成功集成到 Google TV 中,从而提升用户发现和互动,为用户在所有设备上提供一致且个性化的观看体验。