用于视频推荐的 Engage SDK

本指南包含面向开发者的说明,介绍了如何使用 Engage SDK 集成推荐视频内容,以便在各种 Google 途径(例如电视、移动设备和平板电脑)中填充推荐内容体验。

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

准备工作

在开始之前,请完成以下步骤。 1. 请验证您的应用是否以 API 级别 19 或更高级别为目标平台,以便进行此集成。

  1. com.google.android.engage 库添加到您的应用中。

    集成时需要使用单独的 SDK:一个用于移动应用,另一个用于 TV 应用。

    适用于移动设备

    
      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>
    

    For tv apk

    
    <meta-data
        android:name="com.google.android.engage.service.ENV"
        android:value="PRODUCTION">
    </meta-data>
    
  3. 对前台服务执行发布操作。

  4. 最多每天发布一次推荐数据,由以下任一事件触发

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

集成

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

使用 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 请求中应用该偏好设置。如需充分利用跨设备功能,请验证应用是否已征得用户同意,并将 SyncAcrossDevices 设为 true

删除视频发现数据

如需在标准 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 都相同,请为每个平台重复使用该 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 的 Entertainment Space 中。高度小于 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

如果您已将媒体目录或媒体 Action Feed 与 Google TV 集成,则无需为电影或电视节目分别创建实体,而是可以创建包含必需字段 DataFeedElementId 的 MediaActionFeed 实体。此 ID 必须是唯一的,并且必须与 Media Actions 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 中,从而提高用户发现内容和互动度,并为用户提供一致且个性化的观看体验,无论用户使用的是哪种设备。