步骤6: 报告应用的动态功能(VSK Fire TV)
对于动态功能集成,您应用的功能取决于用户的状态(例如登录状态或订阅级别)。因此,您需要集成VSK Agent才能报告功能。如果要集成VSK Agent,建议的方法是通过VSK Agent Client Library来进行。
示例应用报告动态功能,因此您无需在该步骤中进行任何编码。在示例应用中,请参阅
DynamicCapabilityReporter
类、AndroidManifest.xml
、VSK Agent Client Library和功能文件(在res/raw
中)了解详细信息。- 关于VSK Agent
- 选择集成VSK Agent的方式
- 选项1的步骤: 通过VSK Agent Client Library集成VSK Agent服务
- 选项2的步骤: 通过VSKApplicationAgentAPI程序包集成VSK Agent
- 最佳实践: 动态功能报告
- 后续步骤
关于VSK Agent
VSK Agent是Fire OS上的设备端路由代理。您的Fire TV应用使用VSKAgentClient
类向VSK Agent报告其动态功能。这些功能让VSK Agent知道它可以向您的应用广播哪种指令。VSK Agent通过Android界面设计语言API或AIDL与Fire OS通信。
VSK Agent将仅发送您的应用能够支持的指令。例如,如果您没有指明您的应用能够支持PlaybackController
接口,那么Alexa就不会向您发送PlaybackController
指令。
选择集成VSK Agent的方式
对于如何集成VSK Agent,您有两个选项:
选项1: VSK Agent Client Library(建议方法)
建议的方法是使用亚马逊提供的VSK Agent Client Library。VSK Agent Client Library为您提供VSK Agent的全部功能,同时简化了一些Android进程间通信(IPC)细节。VSK Agent Client Library减少了与Fire TV VSK Agent集成时的代码编写工作。简而言之,它为您处理连接到该服务的工作,为您提供可以调用的常规Java方法。
使用VSK Agent Client Library时,您可以随时有选择地动态添加或删除功能。如果您计划将来支持更高级的方式来传达应用的UI状态或其他动态状态更新,则应选择此选项。利用VSK Agent Client Library来集成VSK Agent,是在应用中启用VSK功能的最快、最简单的方法。(请注意,即便使用VSK Agent Client Library,仍然可以通过遵循静态功能集成在静态资源中声明始终支持的功能。)
VSK Agent提供了两种以动态方式报告应用功能的方法:
AddOrUpdateCapabilities()
- 用于声明您支持的功能的方法。sendCapabilityTestDirective()
- 测试集成的方法。
请参阅下面的选项1的步骤: 通过VSK Agent Client Library集成VSK Agent服务了解实现步骤。
选项2: VSKApplicationAgentAPI
与VSK Agent连接的另一个选项是仅使用服务定义并自己管理此连接代码。VSK Agent Client Library与后台的绑定服务进行通信。如果您愿意,可以自己使用VSKApplicationAgentAPI
程序包,自行集成此后台服务。
此VSKApplicationAgentAPI
程序包内有与该服务通信所需的必要.aidl
文件(作为Android接口定义库的一部分)和Java类。虽然并非建议方式,但亚马逊意识到,在某些情况下,您可能需要自己管理所有代码。如果您可能因为想避免任何依赖关系或出于其他要求不想在项目中使用任何Amazon库或代码,则此选项可能会很有吸引力。
请参阅选项2的步骤: 通过VSKApplicationAgentAPI程序包集成VSK Agent,了解一些简短步骤。有关具体如何使用VSKApplicationAgentAPI
程序包的更多详细信息,不在本文档的讨论范围之内。
选项1的步骤: 通过VSK Agent Client Library集成VSK Agent服务
要集成VSK Agent Client Library以与VSK Agent通信(上面的选项1),请执行以下步骤:
将VSK Agent Client Library添加到您的项目中
-
下载VSK Agent Client Library(AAR文件):
请注意,一旦下载VSK Agent Client Library,即表示您同意亚马逊的程序材料许可协议。
(请注意,“VSK Agent Client Library” 与云端集成中使用的 “Alexa客户端库” 不同。)
-
将VSK Agent Client Library添加到您的项目中。在Android Studio中,前往Find(查找)> New(新建)> Module(模块)。然后选择Import .JAR/.AAR Package(导入.JAR/.AAR程序包),再选择VSKApplicationAgentClientLibrary文件。
-
当您导入AAR文件时,Android Studio会将VSKApplicationAgentClientLibrary添加到
settings.gradle (Project Settings)
中,这样它就可以作为依赖项添加到您应用的build.gradle
文件中。展开Gradle Scripts(Gradle脚本)并前往settings.gradle (Project Settings)
。确保已包含VSKApplicationAgentClientLibrary
:include ':VSKApplicationAgentClientLibrary'
-
展开Gradle Scripts(Gradle脚本),打开
build.gradle (Module: App)
,然后在dependencies
对象中添加VSKApplicationAgentClientLibrary
的依赖项:dependencies { implementation project(path: ':VSKApplicationAgentClientLibrary') }
请注意,VSK Agent Client Library在Maven或JCenter上不可用。
示例应用注意事项
示例应用加入了VSK Agent Client Library。在Android Studio中,切换到Project(项目)视图并寻找VSKApplicationAgentClientLibrary
文件夹。
配置您的清单
您应用的清单(AndroidManifest.xml
)包含您的应用执行的活动的声明。在您的应用清单中,添加以下权限以允许您的应用集成VSK Agent:
<uses-permission android:name="com.amazon.alexa.vsk_app_agent_api.permission.BIND_SERVICE_PERMISSION" />
有关应用清单的完整示例,请参阅示例应用中的
AndroidManifest.xml
文件(位于app/manifests
)。初始化VSK Agent Client Library
下一步是在您的代码库中初始化VSK Agent Client Library。
在示例应用中,此初始化在
DynamicCapabilityReporter
类中进行(参见src/java/com/example/vskfiretv/reporter
)。DynamicCapabilityReporter
是您可以在其中报告您的应用支持的语音功能的类。-
创建VSK Agent客户端的新实例:
public DynamicCapabilityReporter(final Context context) { this.context = context; //创建VSKAgentClient的实例 client = new VSKAgentClient(context); }
-
在
reportDynamicCapabilities()
方法中声明您的功能,然后使用AddOrUpdateCapabilities()
方法创建功能报告请求。用户登录后,在您的应用中调用此方法。public void reportDynamicCapabilities() { //创建应用中支持的功能的列表。 final List<AlexaCapability> supportedCapabilities = new ArrayList<>(); supportedCapabilities.add(getAlexaCapability(R.raw.remote_video_player_capability)); // RemoteVideoPlayer功能 // supportedCapabilities.add(getAlexaCapability(R.raw.play_back_controller_capability)); // PlaybackController功能--在此处注释掉,因为和PlaybackController相比更建议媒体会话 //supportedCapabilities.add(getAlexaCapability(R.raw.channel_controller_capability)); // ChannelController功能(仅限应用的集成尚不支持) //supportedCapabilities.add(getAlexaCapability(R.raw.seek_controller_capability)); // SeekController功能 //supportedCapabilities.add(getAlexaCapability(R.raw.keypad_controller_capability)); // KeypadController功能(仅限应用的集成尚不支持) //创建功能报告请求 final AddOrUpdateCapabilitiesRequest request = new AddOrUpdateCapabilitiesRequest(supportedCapabilities); }
注意: 上面的代码中注释掉了许多功能,因为不建议将它们用于Fire TV实现。RemoteVideoPlayer
是唯一建议用于VSK Fire TV集成的功能。(不建议使用的接口可能与Fire TV之外的VSK集成有关,例如有线机顶盒。)Alexa将发送与此处列出的这些功能相关的指令。例如,如果您指明
remote_video_player_capability
,Alexa将发送与RemoteVideoPlayer
接口相关的指令。如果您没有声明该功能,Alexa将不会发送与该功能相关的指令。 -
前面的代码通过使用诸如
Utils.getTextForRawResource(R.raw.remote_video_player)
的代码引用文件来声明功能。上面示例代码中的引用如下:remote_video_player_capability
(指的是RemoteVideoPlayer
)seek_controller_capability
(指的是SeekController
)play_back_controller_capability
(指的是PlaybackController
)keypad_controller
(指的是KeypadController
)channel_controller_capability
(指的是ChannelController
)
在
app/res/raw
中,根据您的应用支持的接口,使用这些名称和功能声明创建必要的文件。每种功能的JSON对象的详细信息在仅限应用的集成支持的功能中进行了描述。示例应用注意事项
在示例应用中,您可以在app/res/raw
中查看这些功能。您可以根据需要将这些示例JSON对象复制到自己的应用中。 -
使用
addOrUpdateCapabilities()
方法,向VSK Agent报告应用的动态功能:Log.i(TAG, “正在向VSK Agent报告动态功能...”); final boolean reportingStatus = client.addOrUpdateCapabilities(request); if(reportingStatus) { Log.i(TAG, "Successfully reported dynamic capabilities to the VSK Agent"); return; } Log.e(TAG, "向VSK Agent报告动态功能失败"); }
现在VSK Agent将知道您的应用支持这些功能。当您稍后在Fire TV上运行应用并查看日志时(在步骤10: 测试表述和观察日志中),您将看到
DynamicCapabilityReporter
类向VSK Agent报告的这些功能。展望未来: 根据用户状态指定不同的目录
如果需要,将来您可以根据用户的订阅或状态指定不同的目录。例如,您可以在一个目录ID(例如acme_free
)上提供免费内容,对另一个目录(例如acme_premium
)提供高级版内容。为此,您需要根据不同的用户状态报告不同的功能。
例如,对于具有高级版订阅级别的用户,您可以报告功能文件中包含不同catalogs
属性的功能。对于这些用户,您可以指向一个带有acme_premium
的功能文件。对于未登录的用户,您可以指向一个catalogs属性包含acme_free
的功能文件。有关catalogs
属性的更多详细信息,请参阅 “仅限应用的集成支持的功能” 中的RemoteVideoPlayer功能部分。请注意,目前不支持此功能,但将来会支持。
报告动态功能的完整代码示例
以下是用于报告动态功能的完整样板代码示例。
// -------------------------------\
// MyApplication.java
// -------------------------------/
public class MyApplication extends Application {
private static MyApplication sTheApp;
private VSKAgentClient client;
private HandlerThread vskAgentThread;
private Handler vskAgentHandler;...
public static MyApplication getInstance() {
return sTheApp;
}
@Override
public void onCreate() {
super.onCreate();
//...
vskAgentThread = new HandlerThread("VSKAgentThread");
vskAgentThread.start()
vskAgentHandler = new Handler(vskAgentThread.getLooper);
client = new VSKAgentClient(this);
reportCapabilities();
//...
}
//...
public void reportCapabilities() {
//应该在后台线程上进行api调用
vskAgentHandler.post(new Runnable() {
public void run() {
reportCapabilitiesInternal()
}
});
}
private void reportCapabilitiesInternal() {
//根据当前应用状态确定
//当前支持的Alexa功能。您可以动态构造
//功能json,或者直接在资源文件中引用json(和我们这里的做法一样)
List < AlexaCapability > supportedCapabilities = new ArrayList < >();
if (accountManager.isLoggedIn()) supportedCapabilities.add(new AlexaCapability(Utils.getTextForRawResource(R.raw.remote_video_player)));
//supportedCapabilities.add(new AlexaCapability(Utils.getTextForRawResource(R.raw.playback_controller)));
if (accountManager.geteCurrentCustomer().hasSubscription(Subscription.LIVE_TV) {
supportedCapabilities.add(new AlexaCapability(Utils.getTextForRawResource(R.raw.channel_controller)));
}
}
AddOrUpdateCapabilitiesRequest request = new AddOrUpdateCapabilitiesRequest(supportedCapabilities);
boolean success = client.addOrUpdateCapabilities(request);
if (!success) {
//句柄错误
}
}
private String getTextForRawResource(int resId) {
InputStream inputStream = getResources().openRawResource(resId);
String line;
StringBuilder result = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
while ((line = reader.readLine()) != null) {
result.append(line).append('\n');
}
return result.toString();
} catch(IOException e) {
//错误
}
return null;
}
VSKAgentClient
类,否则它将引发异常。一般而言,应在应用启动时以及功能发生变化时报告动态功能。在继续下一步之前,请务必阅读下面提到的最佳实践。选项2的步骤: 通过VSKApplicationAgentAPI程序包集成VSK Agent
如果您更倾向于使用VSKApplicationAgentAPI
程序包(不依赖于VSK Agent Client Library)自行集成VSK Agent,请执行以下操作:
-
下载VSKApplicationAgentAPI(AAR文件)。
请注意,一旦下载VSKApplicationAgentAPI,即表示您同意亚马逊的程序材料许可协议。
-
将VSKApplicationAgentAPI添加到您的项目中。在Android Studio中,前往Find(查找)> New(新建)> Module(模块)。然后选择Import .JAR/.AAR Package(导入.JAR/.AAR程序包),再选择VSKApplicationAgentAPI文件。
-
当您导入AAR文件时,Android Studio会将文件添加到
settings.gradle (Project Settings)
中,这样它就可以作为依赖项添加到您应用的build.gradle
文件中。展开Gradle Scripts(Gradle脚本)并打开settings.gradle (Project Settings)
文件。确保已包含VSKApplicationAgentAPI
:include ':VSKApplicationAgentAPI'
-
展开Gradle Scripts(Gradle脚本),然后前往
build.gradle (Module: App)
,并在dependencies
对象中添加VSKApplicationAgentAPI
的依赖项:dependencies { implementation project(path: ':VSKApplicationAgentAPI') }
- 在您的应用清单中声明必要的权限。
- 在创建应用时,通过
addOrUpdateCapabilities()
方法报告当前支持的功能。 - 一旦应用状态更改会导致您支持的功能发生变化,也请调用
addOrUpdateCapabilities()
。
最佳实践: 动态功能报告
当您向Alexa App Agent报告动态功能时,它会确定您的应用的功能自上次报告以来是否发生了变化,然后向Alexa云报告所有变化。因此,最好在每次启动应用时报告您的动态功能。但是,这些功能不应在不同报告中发生变化。当应用或客户状态的长期变化会影响处理客户请求的能力时,应报告动态功能的变化。
例如,当客户退出您的应用时,您可以删除播放内容的功能。报告动态功能的变化会导致向Alexa报告的功能出现不必要的流失,并可能影响您的客户。如果您的应用因发现流量过大而受到限制,则尤其容易出现该情况。为避免这种情况,我们强烈建议您在报告动态功能时遵循以下指南:
- 不要根据未知状态报告功能。例如,如果您的应用报告的动态功能取决于用户是否登录并且对此是异步确定的,请等到处于已知该状态后再进行报告。在报告动态功能时,不要像对客户进行注销只是为了片刻之后再来报告那样。
- 不要根据可能经常变化的短暂状态来报告功能。例如,您不需要根据内容是否在播放来添加或删除
PlaybackController
/SeekController
。您的应用能够执行功能接口声明的操作就足够满足要求。 - 不要根据应用逻辑之外的状态添加或删除功能。例如,无需根据您的应用是否在前台或客户是否在FireTV上切换了输入来更改应用的功能。
后续步骤
转到下一步: 步骤7: 添加BroadcastReceiver。
Last updated: 2023年2月15日