开发者控制台

步骤6: 报告应用的动态功能(VSK Fire TV)

步骤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是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添加到您的项目中

  1. 下载VSK Agent Client Library(AAR文件):

    请注意,一旦下载VSK Agent Client Library,即表示您同意亚马逊的程序材料许可协议

    (请注意,“VSK Agent Client Library” 与云端集成中使用的 “Alexa客户端库” 不同。)

  2. 将VSK Agent Client Library添加到您的项目中。在Android Studio中,前往Find(查找)> New(新建)> Module(模块)。然后选择Import .JAR/.AAR Package(导入.JAR/.AAR程序包),再选择VSKApplicationAgentClientLibrary文件。

  3. 当您导入AAR文件时,Android Studio会将VSKApplicationAgentClientLibrary添加到settings.gradle (Project Settings)中,这样它就可以作为依赖项添加到您应用的build.gradle文件中。展开Gradle Scripts(Gradle脚本)并前往settings.gradle (Project Settings)。确保已包含VSKApplicationAgentClientLibrary

    include ':VSKApplicationAgentClientLibrary'
    
  4. 展开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是您可以在其中报告您的应用支持的语音功能的类。
  1. 创建VSK Agent客户端的新实例:

    public DynamicCapabilityReporter(final Context context) {
        this.context = context;
        //创建VSKAgentClient的实例
        client = new VSKAgentClient(context);
    }
    
  2. 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);
        }            
    

    Alexa将发送与此处列出的这些功能相关的指令。例如,如果您指明remote_video_player_capability,Alexa将发送与RemoteVideoPlayer接口相关的指令。如果您没有声明该功能,Alexa将不会发送与该功能相关的指令。

  3. 前面的代码通过使用诸如Utils.getTextForRawResource(R.raw.remote_video_player)的代码引用文件来声明功能。上面示例代码中的引用如下:

    app/res/raw中,根据您的应用支持的接口,使用这些名称和功能声明创建必要的文件。每种功能的JSON对象的详细信息在仅限应用的集成支持的功能中进行了描述。

    示例应用注意事项

    在示例应用中,您可以在app/res/raw中查看这些功能。您可以根据需要将这些示例JSON对象复制到自己的应用中。
  4. 使用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功能部分。请注意,目前不支持此功能,但将来会支持。

报告动态功能的完整代码示例

以下是用于报告动态功能的完整样板代码示例。

示例应用注意事项

另请参阅示例应用中的DynamicCapabilityReporter类示例,以查看环境中更真实的示例。
// -------------------------------\
// 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;
}

选项2的步骤: 通过VSKApplicationAgentAPI程序包集成VSK Agent

如果您更倾向于使用VSKApplicationAgentAPI程序包(不依赖于VSK Agent Client Library)自行集成VSK Agent,请执行以下操作:

  1. 下载VSKApplicationAgentAPI(AAR文件)。

    请注意,一旦下载VSKApplicationAgentAPI,即表示您同意亚马逊的程序材料许可协议

  2. 将VSKApplicationAgentAPI添加到您的项目中。在Android Studio中,前往Find(查找)> New(新建)> Module(模块)。然后选择Import .JAR/.AAR Package(导入.JAR/.AAR程序包),再选择VSKApplicationAgentAPI文件。

  3. 当您导入AAR文件时,Android Studio会将文件添加到settings.gradle (Project Settings)中,这样它就可以作为依赖项添加到您应用的build.gradle文件中。展开Gradle Scripts(Gradle脚本)并打开settings.gradle (Project Settings)文件。确保已包含VSKApplicationAgentAPI

    include ':VSKApplicationAgentAPI'
    
  4. 展开Gradle Scripts(Gradle脚本),然后前往build.gradle (Module: App),并在dependencies对象中添加VSKApplicationAgentAPI的依赖项:

    dependencies {
         implementation project(path: ':VSKApplicationAgentAPI')
    }
    
  5. 在您的应用清单中声明必要的权限。
  6. 在创建应用时,通过addOrUpdateCapabilities()方法报告当前支持的功能。
  7. 一旦应用状态更改会导致您支持的功能发生变化,也请调用addOrUpdateCapabilities()

最佳实践: 动态功能报告

当您向Alexa App Agent报告动态功能时,它会确定您的应用的功能自上次报告以来是否发生了变化,然后向Alexa云报告所有变化。因此,最好在每次启动应用时报告您的动态功能。但是,这些功能不应在不同报告中发生变化。当应用或客户状态的长期变化会影响处理客户请求的能力时,应报告动态功能的变化。

例如,当客户退出您的应用时,您可以删除播放内容的功能。报告动态功能的变化会导致向Alexa报告的功能出现不必要的流失,并可能影响您的客户。如果您的应用因发现流量过大而受到限制,则尤其容易出现该情况。为避免这种情况,我们强烈建议您在报告动态功能时遵循以下指南:

  1. 不要根据未知状态报告功能。例如,如果您的应用报告的动态功能取决于用户是否登录并且对此是异步确定的,请等到处于已知该状态后再进行报告。在报告动态功能时,不要像对客户进行注销只是为了片刻之后再来报告那样。
  2. 不要根据可能经常变化的短暂状态来报告功能。例如,您不需要根据内容是否在播放来添加或删除PlaybackController/SeekController。您的应用能够执行功能接口声明的操作就足够满足要求。
  3. 不要根据应用逻辑之外的状态添加或删除功能。例如,无需根据您的应用是否在前台或客户是否在FireTV上切换了输入来更改应用的功能。

后续步骤

转到下一步: 步骤7: 添加BroadcastReceiver


Last updated: 2023年2月15日