开发者控制台

发送包含亚马逊额外信息的推荐 (Fire TV)

发送包含亚马逊额外信息的推荐 (Fire TV)

您可以通过ContentRecommendation.Builder()类创建ContentRecommendation对象,从而创建推荐。除了此类中的属性外,您还可以包含亚马逊特定的额外信息,以便更好地与亚马逊Fire TV集成。

此视频将指导您完成这个过程(附带中文字幕)。更多详细信息,请参阅页面下方的剩余部分。

创建推荐

亚马逊的推荐使用标准Android ContentRecommendation.Builder API。有关完整详细信息,请参阅有关推荐电视内容ContentRecommendation.Builder类的Android文档。

除了Android文档中包含的内容外,您还可以通过亚马逊特定的额外信息扩展通知对象中的推荐功能。这些额外信息有助于以更深入的方式将推荐集成到亚马逊Fire TV中。

示例推荐

在深入探讨代码示例之前,让我们来看一个示例推荐卡。这些数字显示通过Android API设置的多个属性以及通过亚马逊额外信息设置的一个属性。

setTitle。设置推荐的标题。(Android API)
setText。设置推荐的描述。(Android API)
setContentImage。设置用于推荐的图像。(Android API)
设置应用的缩写名称,该名称在启动菜单中使用。这由亚马逊的额外信息字段之一设置:com.amazon.extra.DISPLAY_NAME", "displayName"

例如,如果您的应用具有长名称,如“Fire TV世界顶级协会视频”,则此长标题将在启动菜单中被截断。您可以通过亚马逊额外信息(在本例中为DISPLAY_NAME)为您的应用指定缩短名称,而不是接受默认截断。

以下屏幕截图显示了AOL On应用如何使用亚马逊extra字段自定义启动菜单中的文本。

推荐的代码示例

以下代码显示了如何创建ContentRecommendation对象和包含亚马逊额外信息的getNotificationObject

mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 设置通知ID,以便它可以更新
int notifyID = int_value;

ContentRecommendation rec = new ContentRecommendation.Builder()
        .setContentImage(myBitmap) // 从API 23,此方法也接受图标作为参数。
        .setContentIntentData(ContentRecommendation.INTENT_TYPE_, mIntent, mRequestCode, mBundle) // 有关setContentIntentData()的更多信息,请参阅https://developer.android.com/reference/android/support/app/recommendation/ContentRecommendation.html
        .setText(mText)
        .setTitle(mTitle)
        .setBadgeIcon(R.drawable.<app_icon>)
        .setGenres(mGenres)
        .setContentTypes(mTypes)
        .setProgress(mMaxLength,mProgress)
        .setMaturityRating(mMaturityRating) // 此方法不影响Fire TV上的评级。改用com.amazon.extra.MATURITY_RATING设置。
        .setRunningTime(contentLength)
        .build();


Notification notification = rec.getNotificationObject(mContext);

// 其他亚马逊额外信息值将按如下所示添加:

// 为应用分配一个可能显示在UI上的业务名称
notification.extras.putString("com.amazon.extra.DISPLAY_NAME", mDisplayName);

// 为此推荐分配一个年龄评级
notification.extras.putString("com.amazon.extra.MATURITY_RATING", mMaturityRating);

// 指定对来自一个应用的推荐进行排序的方式。
notification.extras.putInt("com.amazon.extra.RANK", mRank);

// 为此推荐分配一个详细描述
notification.extras.putString("com.amazon.extra.LONG_DESCRIPTION", mLongDescription);

// 为此推荐分配最后一次观看时间
notification.extras.putLong("com.amazon.extra.LAST_WATCHED_DATETIME", mLastWatchedTime);

// 指定此推荐的预览视频或图像URL
notification.extras.putString("com.amazon.extra.PREVIEW_URL", mPreviewUrl);

// 分配超高清标签以将您的推荐放在4K超高清行上
ArrayList<String> tagList = new ArrayList<String>();
tagList.add("UHD");
notification.extras.putStringArrayList("com.amazon.extra.TAGS", tagList);

// 为此推荐分配一个直播内容。
notification.extras.putInt(com.amazon.extra.LIVE_CONTENT, 1);

// 为此推荐指定发布日期
notification.extras.putString(com.amazon.extra.CONTENT_RELEASE_DATE, "2016");

// 为此推荐分配字幕可用性
notification.extras.putInt(com.amazon.extra.CONTENT_CAPTION_AVAILABILITY, 1);

// 为此推荐分配一个客户评级
notification.extras.putInt(com.amazon.extra.CONTENT_CUSTOMER_RATING, 5);

// 为此推荐分配一个客户评级计数
notification.extras.putInt(com.amazon.extra.CONTENT_CUSTOMER_RATING_COUNT, 10);

// 为此推荐分配一个imdbid
notification.extras.putString(com.amazon.extra.IMDB_ID, "tt0417148");

// 为此推荐分配直播内容的开始时间
notification.extras.putLong(com.amazon.extra.CONTENT_START_TIME, System.currentTimeMillis());

// 为此推荐分配直播内容的结束时间
notification.extras.putLong(com.amazon.extra.CONTENT_END_TIME, System.currentTimeMillis() + 10000);

mNotificationManager.notify(notifyID, notification);

亚马逊额外信息将添加到通知对象中。传递给方法和额外信息(如mTextmContext)的值假定在代码中的其他位置设置。(因为空间原因,未显示代码的这一部分。) 有关使用Android推荐API和亚马逊额外信息的更多信息,请参阅以下部分。

Fire OS 7中的推荐

从Android Level 8.0(API级别26)开始,必须为应用发送的通知分配一个通道。(推荐是一种通知。) 若应用发送通知或推荐,必须创建一个通道并将通道与通知关联。没有通道ID的通知将被删除。

从更高层次上说,如需向通知添加通道,需进行以下操作:

  1. 步骤1: 创建通知通道,并在通知管理器中注册
  2. 步骤2: 设置通知的通道ID,使用以下方法之一:

以下章节提供更多详细信息和代码示例。

步骤1: 创建通知通道,并在通知管理器中注册

以下内容来自Android文档中的创建通知通道

创建通知通道

如需创建通知通道,请进行以下步骤:

  1. 构建具有唯一通道ID、用户可见名称和重要性级别的NotificationChannel对象。
  2. 或使用setDescription指定用户在系统设置中看到的描述。
  3. 通过将通知通道传递给createNotificationChannel,注册通知通道。

    private void createNotificationChannel() {
        // 创建通知通道,但仅限于API 26+,因为
        // NotificationChannel类是新的,不在支持库中
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.channel_name);
            String description = getString(R.string.channel_description);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // 在系统中注册通道;无法更改重要性
            // 或之后其他通知行为
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
    

步骤2: 设置通知的通道ID

有两个方法可用于设置通知的通道ID。可使用ContentRecommendation和反射,设置通道ID,也可以使用Notification.Builder

方法1: 通过使用createContentRecommendation和反射,设置通道ID

Notification notification = createContentRecommendation(largeIcon, notificationId);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    Log.d(TAG, "SDK version is >= Android O");

    try {
        Field channel = notification.getClass().getDeclaredField("mChannelId");
        channel.setAccessible(true);
        channel.set(notification, StringTerms.CHANNEL_ID);
    }
    catch (Exception e) {
        Log.d(TAG, "Can't set ChannelId", e);
    }
}

方法2: 将Notification.Builder与通道ID结合使用

请注意,以下代码是由Google Git上的Android开源项目改编而成。

public Notification getNotificationObject(Context context) {
    Notification.Builder builder = new Notification.Builder(context, "channelId");
    RecommendationExtender recExtender = new RecommendationExtender();

    // 对通知对象中的所有内容推荐数据进行编码

    builder.setCategory(Notification.CATEGORY_RECOMMENDATION);
    builder.setContentTitle(mTitle);
    builder.setContentText(mText);
    builder.setContentInfo(mSourceName);
    builder.setLargeIcon(mContentImage);
    builder.setSmallIcon(mBadgeIconId);
    if (mBackgroundImageUri != null) {
        builder.getExtras().putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, mBackgroundImageUri);
    }
    builder.setColor(mColor);
    builder.setGroup(mGroup);
    builder.setSortKey(mSortKey);
    builder.setProgress(mProgressMax, mProgressAmount, false);
    builder.setAutoCancel(mAutoDismiss);

    if (mContentIntentData != null) {
        PendingIntent contentPending;
        if (mContentIntentData.mType == INTENT_TYPE_ACTIVITY) {
            contentPending = PendingIntent.getActivity(context, mContentIntentData.mRequestCode,
            mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT,
            mContentIntentData.mOptions);
        }
        else if (mContentIntentData.mType == INTENT_TYPE_SERVICE) {
            contentPending = PendingIntent.getService(context, mContentIntentData.mRequestCode,
            mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
            else { // Default:INTENT_TYPE_BROADCAST{
            contentPending = PendingIntent.getBroadcast(context,
            mContentIntentData.mRequestCode,
            mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
        builder.setContentIntent(contentPending);
    }

    if (mDismissIntentData != null) {
        PendingIntent dismissPending;
        if (mDismissIntentData.mType == INTENT_TYPE_ACTIVITY) {
            dismissPending = PendingIntent.getActivity(context, mDismissIntentData.mRequestCode,
            mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT,
            mDismissIntentData.mOptions);
        }
        else if (mDismissIntentData.mType == INTENT_TYPE_SERVICE) {
            dismissPending = PendingIntent.getService(context, mDismissIntentData.mRequestCode,
            mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
            else { // Default:INTENT_TYPE_BROADCAST{
                dismissPending = PendingIntent.getBroadcast(context,
                mDismissIntentData.mRequestCode,
                mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
        builder.setDeleteIntent(dismissPending);
    }

    recExtender.setContentTypes(mContentTypes);
    recExtender.setGenres(mContentGenres);
    recExtender.setPricingInformation(mPriceType, mPriceValue);
    recExtender.setStatus(mStatus);
    recExtender.setMaturityRating(mMaturityRating);
    recExtender.setRunningTime(mRunningTime);

    builder.extend(recExtender);
    Notification notif = builder.build();
    return notif;
}

有关更多详细信息,请参阅关于创建和管理通知通道的Android文档。

发送适用于Android 14的推荐

请遵循以下指南来发送推荐,以添加运行Android 14的设备。

确保推荐的兼容性

主屏幕会根据Fire OS版本,以两种不同的方式接受来自应用的推荐:

为了能够在所有版本的Fire OS上显示推荐,请实现这两个推荐API。测试当前的系统API级别,然后使用相应的API来构建推荐。

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
  // 遵循Android 14推荐指南
} else {
  //  遵循Fire OS 7推荐指南
}

使用TVProvider发送推荐

在Android 14上,亚马逊的推荐采用Android TV推荐库(即TV Provider)将推荐发送到RECOMMENDED BY YOUR APPS(由我的应用推荐)行。有关发送推荐的完整详细信息,请参阅有关主屏幕上的频道Channel(仅提供英⽂版)和PreviewProgram(仅提供英⽂版)类的Android文档。

Android 14上推荐的代码示例

要创建推荐,您需要完成2个步骤:

  1. 创建推荐频道
  2. 使用频道ID向频道发送推荐
步骤1: 创建推荐频道
  1. 创建Channel.Builder并设置其属性。
  2. 将频道插入到相应的提供商中。
  3. 保存频道ID,以便稍后向该频道添加节目。
Channel.Builder builder = new Channel.Builder();
// 创建的每个频道类型为TYPE_PREVIEW
builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
        .setDisplayName("频道名称")
        
        
 Uri channelUri = context.getContentResolver().insert(
        TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues());
       
 // 可以存储此频道ID,稍后用来更新该频道
 // 或者向其添加节目
 long channelId = ContentUris.parseId(channelUri);
val builder = Channel.Builder()
// 创建的每个频道类型为TYPE_PREVIEW
builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
    .setDisplayName("频道名称")

val channelUri = context.contentResolver.insert(
    TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues()
)

// 可以存储此频道ID,稍后用来更新该频道
// 或者向其添加节目
val channelId = ContentUris.parseId(channelUri)
步骤2: 向频道发送推荐
  1. 创建PreviewProgram.Builder并设置其属性。
  2. 将节目插入到相应的提供商中。
  3. 可以选择检索节目ID以供稍后引用。
// 其他可选的亚马逊额外信息值将按如下所示添加

// 创建Bundle
Bundle bundle = new Bundle();
bundle.putInt("com.amazon.extra.CONTENT_CAPTION_AVAILABILITY", 1);
bundle.putString("com.amazon.extra.DISPLAY_NAME", "display_name");
bundle.putInt("com.amazon.extra.ACTION_OPTION", 1);

// 将Bundle转换为字节数组 (Blob)
Parcel parcel = Parcel.obtain();
bundle.writeToParcel(parcel, 0);
byte[] extrasBlob = parcel.marshall();
parcel.recycle(); // 使用Parcel后将其回收

// 发送推荐
PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE)
        .setTitle("标题")
        .setDescription("节目描述")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderData(extrasBlob);
        
Uri programUri = context.getContentResolver().insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
      builder.build().toContentValues());
      
// 稍后可以使用此节目ID来更新节目
long programId = ContentUris.parseId(programUri);
// 其他可选的亚马逊额外信息值将按如下所示添加:

// 创建Bundle
val extras = Bundle().apply {
    putInt("com.amazon.extra.CONTENT_CAPTION_AVAILABILITY", 1)
    putString("com.amazon.extra.DISPLAY_NAME", "display_name");
    putInt("com.amazon.extra.ACTION_OPTION", 1)
}
 
// 将Bundle转换为字节数组 (Blob)
 val parcel = Parcel.obtain()
bundle.writeToParcel(parcel, 0)
val extrasBlob = parcel.marshall()
parcel.recycle() // 使用Parcel后将其回收

val builder = PreviewProgram.Builder()
    .setChannelId(channelId)
    .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE)
    .setTitle("标题")
    .setDescription("节目描述")
    .setPosterArtUri(uri)
    .setIntentUri(uri)
    .setInternalProviderData(extrasBlob)

val programUri = context.contentResolver.insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
    builder.build().toContentValues()) 

// 稍后可以使用此节目ID来更新节目
val programId = ContentUris.parseId(programUri)

Android API代码的推荐属性

使用Android API中的PreviewProgram.Builder(仅提供英⽂版)时,请遵循以下指南。这些指南将帮助您的推荐与亚马逊Fire TV的外观和风格保持一致。

API 描述 必需(是/否)
setTitle(java.lang.String title) 设置推荐的内容标题。长度限制为125个字符。其他文本将被截断。
setDescription(java.lang.String description) 设置推荐的描述文本。长度限制为125个字符。其他文本将被截断。
setThumbnailUri(Uri thumbnailUri) 设置推荐的图像。对于大图标图像,请使用以下规格:

尺寸: 252像素高或更高
宽高比: 16:9
标题: 嵌入在图像中
透明度: 不透明

没有图像的推荐将不会显示,或者将收到默认占位符。宽高比不是16:9的图像将采用信箱模式。(宽银幕边框模式是指两侧或顶部会出现黑条,以补偿空白空间。) 大于指定尺寸的图像将缩小以适应空间,并保持16:9的宽高比。
setContentRatings(TvContentRating contentRatings[]) 在标题下方显示评级。亚马逊Fire TV上的“家长监护”设置也使用该评级来确定播放内容是否需要PIN。没有此值的任何推荐都将被视为“成人”内容,可能需要PIN,具体取决于设备上的家长监护设置。目前支持TvContentRating(仅提供英⽂版)中提及的值。
setReleaseDate(java.lang.String releaseDate)

setReleaseDate(java.util.Date releaseDate)
设置内容发布年份。
setReviewRating(java.lang.String reviewRating) 客户评分,可能值范围为0到10。
setIntentUri(Uri intentUri) 设置用户选择推荐后启动的意图URI。
setPosterArtUri(Uri posterArtUri) 设置推荐的背景图片URL。
setStartTimeUtcMillis(long startTime) 用于设置内容的运行时间(如果适用)。
setEndTimeUtcMillis(long endTime) 用于设置内容的运行时间(如果适用)。

亚马逊对推荐的改进

下表列出了可以添加到通知对象的额外信息。

下表列出了可以添加到PreviewProgram对象的额外信息。

额外项名称 数据类型 详情
com.amazon.extra.DISPLAY_NAME 字符串 Launch(启动)菜单中显示的较短应用名称(在选择推荐时按菜单按钮会显示该名称)。长度限制为15个字符。其他字符将被截断,且被截断字符不会显示为省略号。
com.amazon.extra.ACTION_OPTION 整数 确定为每个推荐显示的上下文菜单选项。支持并可配置一个上下文菜单操作。当用户单击推荐磁贴或其第一个上下文菜单选项后,亚马逊Fire TV会使用随推荐传递的相应内容意图数据启动应用。注意:​ 如果您的应用提供了操作数组列表,则必须提供com.amazon.extra.DISPLAY_NAME(如上所述)。ACTION_OPTION包含的可能值如下所示:

1: Watch with <应用名称>(使用<应用名称>观看)
2: Watch(观看)
3: Resume with <应用名称>(使用<应用名称>继续)
4: Resume(继续)
5: Switch <应用名称> Profile(切换<应用名称>配置文件)
6: Change <应用名称> Settings(更改<应用名称>设置)
7: Change Settings(更改设置)
8: View with <应用名称>(使用<应用名称>查看)
9: View(查看)
10: Play with <应用名称>(使用<应用名称>播放)
11: Play(播放)
12: Listen with <应用名称>(使用<应用名称>收听)
13: Listen(收听)

如果未提供任何值,则默认操作将为Open(打开),下面是Launch <应用名称>(启动<应用名称>)。
com.amazon.extra.CONTENT_CAPTION_AVAILABILITY 整数 内容的字幕可用性:
0: 内容没有字幕可用。
1: 内容有字幕可用。

配置清单

要在设备启动时发送推荐,您的应用必须具有RECEIVE_BOOT_COMPLETED权限。此权限允许您的应用接收和处理告知应用您的设备已启动的广播。

要接收广播,请将以下权限作为<manifest>元素的子项添加到Android清单:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

支持性推荐的初始启动点是创建BroadcastReceiver的一个子类。在清单中,将接收方注册为处理ACTION_BOOT_COMPLETED意图。系统首次启动时,所有相关应用都会获得一个初始的“ping”来生成推荐。有关更多详细信息,请参阅Stacktips.com上的如何在设备启动时启动Android系统中的应用教程。

为了使广播可靠工作,请确保您的应用未安装在外部存储器上。有关存储位置的详细信息,请参阅以下内容:

删除推荐

最佳实践是在用户观看推荐内容后删除推荐。您可以为特定通知ID调用cancel()来删除推荐。

以下代码示例显示如何删除推荐:

mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

//使用您在创建此通知时使用的相同通知ID
mNotificationManager.cancel(notifyID);

后续步骤

要了解更多信息,请参阅以下内容:


Last updated: 2025年1月17日