步骤4: 集成Amazon Device Messaging (ADM) (VSK Fire TV)
Amazon Device Messaging (ADM) 是一种推送通知技术,让您的应用可以与您的Lambda进行交互。您的Lambda将使用ADM向您的应用发送指令。
请注意,视频技能使用ADM的方式与ADM的最常见用例不同。视频技能仅使用ADM将消息从Lambda传送到您的应用(以单向方式)。因此,此处仅嵌入了ADM文档中的相关部分。如果您直接阅读ADM的文档,会发现许多其他用法和细节,这些用法和细节可能与Fire TV上的视频技能无关。
如果您使用的是示例Fire TV应用,则ADM已经集成到代码中,并且已经添加了ADM JAR(如果您在Android Studio中切换到项目视图并转到app [应用] > libs [库],会看到amazon-device-messaging-1.1.0.jar)。因此,您可以跳到下一步: 步骤5: 对应用签名并配置安全配置文件。但是,如果您想更好地了解用于集成ADM的代码,请参阅
AndroidManifest.xml
、MainActivity.java
和VSKFireTVMessageHandler.java
文件。更新您的应用清单
在接收通过ADM发送的消息时,第一步是更新您的AndroidManifest.xml
文件。对现有文件进行以下更改。
-
打开
AndroidManifest.xml
文件并添加亚马逊命名空间:xmlns:amazon="http://schemas.amazon.com/apk/res/android"
-
要声明支持ADM所需的权限,请在
manifest
元素后面添加permission
和uses-permission
元素。<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:amazon="http://schemas.amazon.com/apk/res/android" package="[您的程序包名称]" android:versionCode="1" android:versionName="1.0"> <!-- This permission ensures that no other application can intercept your ADM消息。 --> <permission android:name="[您的程序包名称].permission.RECEIVE_ADM_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="[您的程序包名称].permission.RECEIVE_ADM_MESSAGE" /> <!-- This permission allows your app access to receive push notifications 来自ADM的推送通知。 --> <uses-permission android:name="com.amazon.device.messaging.permission.RECEIVE" /> <uses-permission android:name="amazon.speech.permission.SEND_DATA_TO_ALEXA" /> <!--ADM使用WAKE_LOCK来防止处理器在收到消息时进入休眠状态。--> <uses-permission android:name="android.permission.WAKE_LOCK" /> ... </manifest>
-
显式启用ADM,并声明您的应用是需要ADM才能运行(
android:required="true"
),还是在没有ADM的情况下也可以运行(android:required="false"
)。如果您指定android:required="false"
,则您的应用必须在ADM不可用的情况下优雅降级。在清单的application
节点中,添加amazon:enable-feature
元素。... <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <!-- 您必须显式启用ADM,并声明您的应用在没有 ADM的情况下无法工作(android:required="true"),还是在没有ADM的情况下可以工作(android:required="false")。 如果您指定android:required="false",则您的应用在ADM不可用的情况下 必须优雅降级。 --> <amazon:enable-feature android:name="com.amazon.device.messaging" android:required="true"/> ...
-
声明一个广播接收器以处理ADM发送的
REGISTRATION
和RECEIVE
意图。ADM要求在AndroidManifest.xml文件中定义该接收器,而不是以编程方式定义。在amazon:enable-feature
后面添加以下元素。<!-- You must replace the names in the service and receiver tags 适合您程序包的名称。 -->D <service android:name="[您的服务名称]" android:exported="false" /> <receiver android:name="[您的服务名称]" <!-- 此权限可确保只有ADM可以发送您的应用注册广播。 --> android:permission="com.amazon.device.messaging.permission.SEND" > <!-- 若要与ADM交互,您的应用必须侦听以下意图。 --> <intent-filter> <action android:name="com.amazon.device.messaging.intent.REGISTRATION" /> <action android:name="com.amazon.device.messaging.intent.RECEIVE" /> <!-- 将类别标签中的名称替换为您的应用程序包名称。 --> <category android:name="[您的程序包名称]" /> </intent-filter> </receiver>
-
更新AndroidManifest.xml文件后,您可以通过调用
ADMManifest.checkManifestAuthoredProperly()
来确认这些更改是否适合ADM。如果收到
java.lang.NoClassDefFoundError: com.amazon.device.messaging.ADM
错误,请检查清单,确认已将amazon:enable-feature
元素添加到步骤3中指定的位置。
以下代码是为ADM启用的AndroidManifest.xml文件的完整示例。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:amazon="http://schemas.amazon.com/apk/res/android"
package="[您的程序包名称]"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="15" />
<permission
android:name="[您的程序包名称].permission.RECEIVE_ADM_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="[您的程序包名称].permission.RECEIVE_ADM_MESSAGE" />
<uses-permission android:name="com.amazon.device.messaging.permission.RECEIVE" />
<uses-permission android:name="amazon.speech.permission.SEND_DATA_TO_ALEXA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<amazon:enable-feature
android:name="com.amazon.device.messaging"
android:required="true"/>
<service
android:name="[您的服务名称]"
android:exported="false" />
<receiver
android:name="[您的接收器名称]"
android:permission="com.amazon.device.messaging.permission.SEND" >
<intent-filter>
<action android:name="com.amazon.device.messaging.intent.REGISTRATION" />
<action android:name="com.amazon.device.messaging.intent.RECEIVE" />
<category android:name="[您的程序包名称]" />
</intent-filter>
</receiver>
</application>
</manifest>
处理注册和消息
清单中所声明的广播接收器会侦听意图,并在意图到达时调用应用。您的应用会通过com.amazon.device.messaging.ADMMessageHandlerBase
类中定义的以下回调方法,与广播接收器进行通信:
-
onRegistered
:在应用实例的注册ID准备就绪时调用。您的应用必须将此注册ID传输到服务器。这样做即可让您的服务器向该应用实例发送消息。 -
onUnregistered
。在应用实例已从ADM注销时调用。 -
onRegistrationError
。在应用的ADM注册请求因某一原因(例如,亚马逊用户未登录设备)而失败时调用。 -
onMessage
。在ADM客户端将消息传送到应用实例时调用。
当您实现com.amazon.device.messaging.ADMMessageHandlerBase
和com.amazon.device.messaging.ADMMessageReceiver
的子类时,您的应用必须覆盖这些回调,如以下代码示例中所示:
public class MyADMMessageHandler extends ADMMessageHandlerBase
{
public static class Receiver extends ADMMessageReceiver
{
public Receiver()
{
super(MyADMMessageHandler.class);
}
// 此处不需要其他内容;广播接收器会将意图自动
// 转发到您的服务以进行处理。
}
@Override
protected void onRegistered(final String newRegistrationId)
{
// 通过在主要活动中调用startRegister()来启动注册
// 过程。当注册ID就绪时,ADM将对您的应用
// 调用onRegistered()。将传入的注册ID传输到您的服务器,以便
// 服务器可以将消息发送到此应用实例。如果
// 您的注册ID因任何原因发生轮换或更改,ADM也会调用onRegistered();
// 如果出现这种情况,您的应用应将新的注册ID传递到您的服务器。
// 您的服务器需要能够处理长达1536个字符的
// 注册ID。
// 将获得的ADM注册ID提供给Alexa客户端库。
AlexaClientManager.getSharedInstance().setDownChannelReady(true, newRegistrationId);
}
@Override
protected void onUnregistered(final String registrationId)
{
// 如果您的应用在此台设备上已注销,请通知服务器
// 此应用实例不再是有效的消息发送目标。
}
@Override
protected void onRegistrationError(final String errorId)
{
// 注册错误应视为严重错误。因此,您的应用可
// 优雅降级,或者您可通知用户
// 应用的这项功能不可用。
}
@Override
protected void onMessage(final Intent intent)
{
// 从附加到com.amazon.device.messaging.intent.RECEIVE意图
// 的额外信息集中提取消息内容。
// 创建字符串以访问JSON数据中的message和timeStamp字段。
final String msgKey = getString(R.string.json_data_msg_key);
final String timeKey = getString(R.string.json_data_time_key);
// 获取将在onMessage()回调中触发的意图操作。
final String intentAction = getString(R.string.intent_msg_action);
// 获取意图中包含的额外信息。
final Bundle extras = intent.getExtras();
// 从意图中的额外信息中提取消息和时间。
// ADM既不会保证消息能够送达,也不会保证消息能够按顺序送达。
// 由于网络条件的变化,消息可能会被多次传送。
// 您的应用必须能够处理重复消息的实例。
final String msg = extras.getString(msgKey);
final String time = extras.getString(timeKey);
}
}
在ADM不可用时正常降级
请在清单文件中声明您的应用在没有ADM的情况下可以运行(android:required="false"
)还是不可以运行(android:required="true"
)。如果您指定android:required="false"
,则您的应用必须在ADM不可用的情况下优雅降级。
通过将应用设计为适应缺少ADM的情况,您只需构建一个APK,无论设备是否包含ADM,该APK均可在其上安装并运行。
修改您的应用以正常降级
-
使用如下所示的代码检查ADM。
ADMAvailable = false ; try { Class.forName( "com.amazon.device.messaging.ADM" ); ADMAvailable = true ; } catch (ClassNotFoundException e) { // 处理异常。 }
-
将以下代码添加到所有需要ADM库运行时的代码中。
if (ADMAvailable) { // 在此处放置需要ADM的代码。 }
-
在AndroidManifest.xml文件中,确认应用元素指定了以下内容:
amazon:enable-feature android:name="com.amazon.device.messaging" android:required="false" /
ADM的替代方案
除了使用ADM将指令从Lambda函数发送到您的应用,您还可以使用自己的协议和云服务向您的应用发送操作。使用此选项,您将有权向应用传递命令。通信的协议和特性完全由您决定,可以通过您的Lambda代码或对您基础设施的服务调用对其进行管理。
此方法要求在初始化时向Alexa客户端提供该应用实例专属的标识符。当向您的Lambda代码发送指令时,此标识符将用于以此应用实例为目标。(如果您还没有应用实例的标识符或者不希望将其传递给Alexa,可考虑为此使用ANDROID_ID
。)
如果您选择此方法,您将需要自己制定大部分实现代码。这些步骤将涉及以下内容:
- 将Alexa客户端库添加到您的项目
- 初始化时将应用实例标识符传递至客户端库
- 确保您的云已知应用实例标识符
- 根据需要实现Lambda函数和应用通信机制
- Alexa客户端库的完整应用集成要求
后续步骤
继续执行步骤5: 对应用签名并配置安全配置文件。
(如果遇到任何问题而无法继续,请参阅云端集成故障排除。)
Last updated: 2021年10月13日