Google 正在构建一个设备上的界面,它根据垂直领域组织用户的应用,并为个性化应用内容消费和发现提供新的沉浸式体验。这种全屏体验为开发人员合作伙伴提供了一个机会,让他们能够在应用之外的专用频道中展示其最佳的丰富内容。
本指南包含开发人员合作伙伴使用 Engage SDK 填充此新界面区域和现有 Google 界面的视频内容的集成说明。
集成细节
术语
此集成包括以下三种集群类型:**推荐**、**延续**和**特色**。
**推荐**集群显示来自单个开发人员合作伙伴的个性化内容观看建议。
您的推荐采用以下结构
**推荐集群:**包含来自同一开发人员合作伙伴的一组推荐的 UI 视图。
**实体:**代表集群中单个项目的对象。实体可以是电影、电视剧、电视剧集、直播视频等。请参见提供实体数据部分,了解支持的实体类型列表。
**延续**集群显示来自多个开发人员合作伙伴的未完成视频和相关的最新发布剧集,这些剧集在一个 UI 分组中。每个开发人员合作伙伴将被允许在延续集群中广播最多 10 个实体。研究表明,个性化推荐和个性化延续内容可以创造最佳的用户参与度。
**特色**集群在一个 UI 分组中展示来自多个开发人员合作伙伴的实体精选。将有一个单独的特色集群,该集群位于 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 定义了不同的实体来表示每个项目类型。我们支持以下用于观看类别的实体
以下图表概述了每种类型的属性和要求。
MovieEntity
属性 | 要求 | 备注 |
---|---|---|
名称 | 必需 | |
海报图片 | 必需 | 至少需要一张图片,并且必须以宽高比提供。(横向是首选,但建议在不同情况下传递横向和纵向图像。) 有关指南,请参阅图片规格。 |
播放 URI | 必需 |
启动播放电影的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
信息页 URI | 可选 |
显示有关电影详细信息的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
发布日期 | 必需 | 以毫秒为单位的 Unix 时间戳。 |
可用性 | 必需 | AVAILABLE:内容对用户可用,无需任何进一步操作。 FREE_WITH_SUBSCRIPTION:用户购买订阅后即可使用该内容。 PAID_CONTENT:内容需要用户购买或租赁。 PURCHASED:用户已购买或租赁该内容。 |
优惠价格 | 可选 | 自由文本 |
时长 | 必需 | 以毫秒为单位。 |
类型 | 必需 | 自由文本 |
内容分级 | 必需 | 自由文本,遵循行业标准。(示例) |
观看下一项类型 | 有条件地需要 | 当项目位于延续集群中时必须提供,并且必须是以下四种类型之一 CONTINUE:用户已经观看过此内容超过 1 分钟。 NEW:用户已观看过某些情景内容的所有可用剧集,但已发布新的剧集,并且只有一个未观看的剧集。这适用于电视剧、系列中录制的足球比赛等等。 NEXT:用户已观看过某些情景内容的一个或多个完整剧集,但仍剩余一个或多个剧集,或者只有一个剧集剩余,其中最后一个剧集不是“NEW”,并且是在用户开始观看情景内容之前发布的。 WATCHLIST:用户已明确选择将电影、活动或系列添加到观看列表中,以手动整理他们接下来要观看的内容。 |
上次参与时间 | 有条件地需要 | 当项目位于延续集群中时必须提供。以毫秒为单位的 Unix 时间戳。 |
上次播放位置时间 | 有条件地需要 | 当项目位于延续集群中并且 WatchNextType 为 CONTINUE 时必须提供。以毫秒为单位的 Unix 时间戳。 |
TvShowEntity
属性 | 要求 | 备注 |
---|---|---|
名称 | 必需 | |
海报图片 | 必需 | 至少需要一张图片,并且必须以宽高比提供。(横向是首选,但建议在不同情况下传递横向和纵向图像。) 有关指南,请参阅图片规格。 |
信息页 URI | 必需 |
显示电视剧详细信息的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
播放 URI | 可选 |
启动播放电视剧的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
第一集首播日期 | 必需 | 以毫秒为单位的 Unix 时间戳。 |
最新剧集首播日期 | 可选 | 以毫秒为单位的 Unix 时间戳。 |
可用性 | 必需 | AVAILABLE:内容对用户可用,无需任何进一步操作。 FREE_WITH_SUBSCRIPTION:用户购买订阅后即可使用该内容。 PAID_CONTENT:内容需要用户购买或租赁。 PURCHASED:用户已购买或租赁该内容。 |
优惠价格 | 可选 | 自由文本 |
季数 | 必需 | 正整数 |
类型 | 必需 | 自由文本 |
内容分级 | 必需 | 自由文本,遵循行业标准。(示例) |
观看下一项类型 | 有条件地需要 | 当项目位于延续集群中时必须提供,并且必须是以下四种类型之一 CONTINUE:用户已经观看过此内容超过 1 分钟。 NEW:用户已观看过某些情景内容的所有可用剧集,但已发布新的剧集,并且只有一个未观看的剧集。这适用于电视剧、系列中录制的足球比赛等等。 NEXT:用户已观看过某些情景内容的一个或多个完整剧集,但仍剩余一个或多个剧集,或者只有一个剧集剩余,其中最后一个剧集不是“NEW”,并且是在用户开始观看情景内容之前发布的。 WATCHLIST:用户已明确选择将电影、活动或系列添加到观看列表中,以手动整理他们接下来要观看的内容。 |
上次参与时间 | 有条件地需要 | 当项目位于延续集群中时必须提供。以毫秒为单位的 Unix 时间戳。 |
上次播放位置时间 | 有条件地需要 | 当项目位于延续集群中并且 WatchNextType 为 CONTINUE 时必须提供。以毫秒为单位的 Unix 时间戳。 |
TvSeasonEntity
属性 | 要求 | 备注 |
---|---|---|
名称 | 必需 | |
海报图片 | 必需 | 至少需要一张图片,并且必须以宽高比提供。(横向是首选,但建议在不同情况下传递横向和纵向图像。) 有关指南,请参阅图片规格。 |
信息页 URI | 必需 |
显示电视剧季数详细信息的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
播放 URI | 可选 |
启动播放电视剧季数的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
显示季数 |
可选 在 v1.3.1 中可用 |
字符串 |
第一集首播日期 | 必需 | 以毫秒为单位的 Unix 时间戳。 |
最新剧集首播日期 | 可选 | 以毫秒为单位的 Unix 时间戳。 |
可用性 | 必需 | AVAILABLE:内容对用户可用,无需任何进一步操作。 FREE_WITH_SUBSCRIPTION:用户购买订阅后即可使用该内容。 PAID_CONTENT:内容需要用户购买或租赁。 PURCHASED:用户已购买或租赁该内容。 |
优惠价格 | 可选 | 自由文本 |
剧集数量 | 必需 | 正整数 |
类型 | 必需 | 自由文本 |
内容分级 | 必需 | 自由文本,遵循行业标准。(示例) |
观看下一项类型 | 有条件地需要 | 当项目位于延续集群中时必须提供,并且必须是以下四种类型之一 CONTINUE:用户已经观看过此内容超过 1 分钟。 NEW:用户已观看过某些情景内容的所有可用剧集,但已发布新的剧集,并且只有一个未观看的剧集。这适用于电视剧、系列中录制的足球比赛等等。 NEXT:用户已观看过某些情景内容的一个或多个完整剧集,但仍剩余一个或多个剧集,或者只有一个剧集剩余,其中最后一个剧集不是“NEW”,并且是在用户开始观看情景内容之前发布的。 WATCHLIST:用户已明确选择将电影、活动或系列添加到观看列表中,以手动整理他们接下来要观看的内容。 |
上次参与时间 | 有条件地需要 | 当项目位于延续集群中时必须提供。以毫秒为单位的 Unix 时间戳。 |
上次播放位置时间 | 有条件地需要 | 当项目位于延续集群中并且 WatchNextType 为 CONTINUE 时必须提供。以毫秒为单位的 Unix 时间戳。 |
TvEpisodeEntity
属性 | 要求 | 备注 |
---|---|---|
名称 | 必需 | |
海报图片 | 必需 | 至少需要一张图片,并且必须以宽高比提供。(横向是首选,但建议在不同情况下传递横向和纵向图像。) 有关指南,请参阅图片规格。 |
播放 URI | 必需 |
启动播放剧集的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
信息页 URI | 可选 |
显示有关电视剧剧集详细信息的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
显示剧集数 |
可选 在 v1.3.1 中可用 |
字符串 |
首播日期 | 必需 | 以毫秒为单位的 Unix 时间戳。 |
可用性 | 必需 | AVAILABLE:内容对用户可用,无需任何进一步操作。 FREE_WITH_SUBSCRIPTION:用户购买订阅后即可使用该内容。 PAID_CONTENT:内容需要用户购买或租赁。 PURCHASED:用户已购买或租赁该内容。 |
优惠价格 | 可选 | 自由文本 |
时长 | 必需 | 必须是毫秒为单位的正值。 |
类型 | 必需 | 自由文本 |
内容分级 | 必需 | 自由文本,遵循行业标准。(示例) |
观看下一项类型 | 有条件地需要 | 当项目位于延续集群中时必须提供,并且必须是以下四种类型之一 CONTINUE:用户已经观看过此内容超过 1 分钟。 NEW:用户已观看过某些情景内容的所有可用剧集,但已发布新的剧集,并且只有一个未观看的剧集。这适用于电视剧、系列中录制的足球比赛等等。 NEXT:用户已观看过某些情景内容的一个或多个完整剧集,但仍剩余一个或多个剧集,或者只有一个剧集剩余,其中最后一个剧集不是“NEW”,并且是在用户开始观看情景内容之前发布的。 WATCHLIST:用户已明确选择将电影、活动或系列添加到观看列表中,以手动整理他们接下来要观看的内容。 |
上次参与时间 | 有条件地需要 | 当项目位于延续集群中时必须提供。以毫秒为单位的 Unix 时间戳。 |
上次播放位置时间 | 有条件地需要 | 当项目位于延续集群中并且 WatchNextType 为 CONTINUE 时必须提供。以毫秒为单位的 Unix 时间戳。 |
LiveStreamingVideoEntity
属性 | 要求 | 备注 |
---|---|---|
名称 | 必需 | |
海报图片 | 必需 | 至少需要一张图片,并且必须以宽高比提供。(横向是首选,但建议在不同情况下传递横向和纵向图像。) 有关指南,请参阅图片规格。 |
播放 URI | 必需 |
启动播放视频的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
广播公司 | 必需 | 自由文本 |
开始时间 | 可选 | 以毫秒为单位的 Unix 时间戳。 |
结束时间 | 可选 | 以毫秒为单位的 Unix 时间戳。 |
观看次数 | 可选 | 自由文本,必须是本地化的。 |
观看下一项类型 | 有条件地需要 | 当项目位于延续集群中时必须提供,并且必须是以下四种类型之一 CONTINUE:用户已经观看过此内容超过 1 分钟。 NEW:用户已观看过某些情景内容的所有可用剧集,但已发布新的剧集,并且只有一个未观看的剧集。这适用于电视剧、系列中录制的足球比赛等等。 NEXT:用户已观看过某些情景内容的一个或多个完整剧集,但仍剩余一个或多个剧集,或者只有一个剧集剩余,其中最后一个剧集不是“NEW”,并且是在用户开始观看情景内容之前发布的。 WATCHLIST:用户已明确选择将电影、活动或系列添加到观看列表中,以手动整理他们接下来要观看的内容。 |
上次参与时间 | 有条件地需要 | 当项目位于延续集群中时必须提供。以毫秒为单位的 Unix 时间戳。 |
上次播放位置时间 | 有条件地需要 | 当项目位于延续集群中并且 WatchNextType 为 CONTINUE 时必须提供。以毫秒为单位的 Unix 时间戳。 |
VideoClipEntity
VideoClipEntity
对象代表来自社交媒体(例如 TikTok 或 YouTube)的视频实体。
属性 | 要求 | 备注 |
---|---|---|
名称 | 必需 | |
海报图片 | 必需 | 至少需要一张图片,并且必须以宽高比提供。(横向是首选,但建议在不同情况下传递横向和纵向图像。) 有关指南,请参阅图片规格。 |
播放 URI | 必需 |
启动播放视频的提供商应用程序的深层链接。 注意:您可以使用深层链接进行归因。 请参阅此常见问题解答 |
创建时间 | 必需 | 以毫秒为单位的 Unix 时间戳。 |
时长 | 必需 | 必须是毫秒为单位的正值。 |
创建者 | 必需 | 自由文本 |
创建者图片 | 可选 | 创建者头像的图片 |
观看次数 | 可选 | 自由文本,必须是本地化的。 |
观看下一项类型 | 有条件地需要 | 当项目位于延续集群中时必须提供,并且必须是以下四种类型之一 CONTINUE:用户已经观看过此内容超过 1 分钟。 NEW:用户已观看过某些情景内容的所有可用剧集,但已发布新的剧集,并且只有一个未观看的剧集。这适用于电视剧、系列中录制的足球比赛等等。 NEXT:用户已观看过某些情景内容的一个或多个完整剧集,但仍剩余一个或多个剧集,或者只有一个剧集剩余,其中最后一个剧集不是“NEW”,并且是在用户开始观看情景内容之前发布的。 WATCHLIST:用户已明确选择将电影、活动或系列添加到观看列表中,以手动整理他们接下来要观看的内容。 |
上次参与时间 | 有条件地需要 | 当项目位于延续集群中时必须提供。以毫秒为单位的 Unix 时间戳。 |
上次播放位置时间 | 有条件地需要 | 当项目位于延续集群中并且 WatchNextType 为 CONTINUE 时必须提供。以毫秒为单位的 Unix 时间戳。 |
图片规格
以下部分列出了图片资产的必需规格
文件格式
PNG、JPG、静态 GIF、WebP
最大文件大小
5120 KB
其他建议
- 图片安全区域:将重要的内容放在图片中心 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 | 必需 | 操作的深层链接(即,导航到应用程序登录页面) |
图片 | 可选 - 如果未提供,则必须提供标题 |
卡片上显示的图片 宽高比为 16x9 的图片,分辨率为 1264x712 |
标题 | 可选 - 如果未提供,则必须提供图片 | 卡片上的标题 |
操作文本 | 可选 | 在 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
数据。 - 解析请求中的数据并将其存储在更新后的用户帐户管理集群集群中。
如果出现错误,整个请求将被拒绝,并且会保留现有状态。
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
如果内容未发布是由于用户未登录,Google 建议发布登录卡片。如果出于任何原因提供者无法发布登录卡片,那么我们建议使用状态代码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 用于删除用户帐户管理集群的内容。
Kotlin
client.deleteUserManagementCluster()
Java
client.deleteUserManagementCluster();
当服务收到请求时,它会从用户帐户管理集群中删除现有数据。如果发生错误,整个请求将被拒绝,并且保持现有状态。
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
返回,并包含错误代码作为原因。
错误代码 | 注意 |
---|---|
SERVICE_NOT_FOUND |
该服务在给定设备上不可用。 |
SERVICE_NOT_AVAILABLE |
该服务在给定设备上可用,但在调用时不可用(例如,它被明确禁用)。 |
SERVICE_CALL_EXECUTION_FAILURE |
任务执行由于线程问题而失败。在这种情况下,可以重试。 |
SERVICE_CALL_PERMISSION_DENIED |
调用者无权进行服务调用。 |
SERVICE_CALL_INVALID_ARGUMENT |
请求包含无效数据(例如,超过允许的集群数量)。 |
SERVICE_CALL_INTERNAL |
服务端发生错误。 |
SERVICE_CALL_RESOURCE_EXHAUSTED |
服务调用过于频繁。 |
步骤 3:处理广播意图
除了通过作业进行内容发布 API 调用之外,还需要设置一个 BroadcastReceiver
来接收内容发布请求。
广播意图的主要目的是应用程序重新激活和强制数据同步。广播意图并非设计为频繁发送。它仅在 Engage 服务确定内容可能过时(例如,一周前)时触发。这样,即使应用程序很长时间没有执行,用户也可以更放心地获得新鲜的内容体验。
需要通过以下两种方式设置 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 开发人员集成工作流程。
常见问题解答
有关常见问题解答,请参阅 Engage SDK 常见问题解答。
联系我们
如果在集成过程中有任何问题,请联系 [email protected]。
下一步
完成此集成后,您的下一步操作如下
- 发送电子邮件至 [email protected],并附上您已集成的 APK,以便 Google 进行测试。
- Google 会进行验证和内部审查,以确保集成按预期工作。如果需要更改,Google 会与您联系并提供任何必要的详细信息。
- 测试完成后,如果不需要进行任何更改,Google 会与您联系,通知您您可以开始将更新后的集成 APK 发布到 Play 商店。
- Google 确认您已将更新后的 APK 发布到 Play 商店后,您的推荐、精选和延续集群可能会发布并对用户可见。