Amazon Simple Notification Service
开发人员指南 (API Version 2010-03-31)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。点 击 Getting Started with Amazon AWS to see specific differences applicable to the China (Beijing) Region.

创建平台终端节点和管理设备令牌

当应用程序和移动设备注册推送通知服务时,推送通知服务会返回设备令牌。Amazon SNS 使用该设备令牌来创建移动终端节点,能够改善直接推送通知消息。有关更多信息,请参阅 先决条件Amazon SNS 移动推送概括步骤

此部分介绍了创建平台终端节点和管理设备令牌的推荐方法。

创建平台终端节点

要使用 Amazon SNS 将通知推送到应用程序,必须先通过调用创建平台终端节点操作,将该应用程序的设备令牌注册到 Amazon SNS。此操作以参数的形式获取平台应用程序的 Amazon 资源名称 (ARN) 以及设备令牌,并返回所创建平台终端节点的 ARN。

创建平台终端节点操作执行以下任务:

  • 如果平台终端节点已存在,则不重新创建。向调用方返回现有平台终端节点的 ARN。

  • 如果存在具有相同设备令牌但不同设置的平台终端节点,则不重新创建。向调用方引发异常。

  • 如果平台终端节点不存在,则创建它。向调用方返回新创建的平台终端节点的 ARN。

您不应在每次应用程序启动时立即调用创建平台终端节点操作,因为此方法并不总是提供正常工作的终端节点。例如,在相同设备上卸载并重新安装了应用程序,并且其终端节点已存在但被禁用时,会出现这种情况。成功的注册过程应该完成以下任务:

  1. 确保此应用程序/设备组合存在平台终端节点。

  2. 确保平台终端节点中的设备令牌是最新的有效设备令牌。

  3. 确保平台终端节点已启用并且已准备好使用。

伪代码

以下伪代码介绍了在各种各样的开始条件中创建正常工作的、当前启用的平台终端节点的推荐做法。不论应用程序是否首次注册、此应用程序的平台终端节点是否已存在、平台终端节点是否已启用、是否具有正确的设备令牌等等,此方法均适用。连续多次调用该方法是安全的,因为它不会创建重复的平台终端节点;如果现有平台终端节点已是最新的并且已启用,也不会更改它。

Copy
retrieve the latest device token from the mobile operating system if (the platform endpoint ARN is not stored) # this is a first-time registration call create platform endpoint store the returned platform endpoint ARN endif call get endpoint attributes on the platform endpoint ARN if (while getting the attributes a not-found exception is thrown) # the platform endpoint was deleted call create platform endpoint with the latest device token store the returned platform endpoint ARN else if (the device token in the endpoint does not match the latest one) or (get endpoint attributes shows the endpoint as disabled) call set endpoint attributes to set the latest device token and then enable the platform endpoint endif endif

在应用程序希望注册或重新注册自身时,可以随时使用此方法。它还可在向 Amazon SNS 通知设备令牌更改时使用。在这种情况下,只需使用最新的设备令牌值调用操作即可。有关此方法需要说明的几点是:

  • 在两种情况下可能会调用创建平台终端节点操作。在刚开始时,应用程序不知道自己的平台终端节点 ARN 时可能会调用该方法;这种情况出现在首次注册期间。在初始获取终端节点属性操作失败并返回“未找到”异常时,也会调用该方法;这种情况发生在应用程序知道其终端节点 ARN 但该 ARN 已被删除时。

  • 调用获取终端节点属性操作来验证平台终端节点的状态,即使刚刚创建了平台终端节点。平台终端节点已存在但被禁用时会出现这种情况。在这种情况下,创建平台终端节点操作成功,但不启用平台终端节点,因此您必须在返回成功之前仔细检查平台终端节点的状态。

Java 示例

这是上述伪代码在 Java 中的实施:

Copy
class RegistrationExample { AmazonSNSClient client = new AmazonSNSClient(); //provide credentials here private void registerWithSNS() { String endpointArn = retrieveEndpointArn(); String token = "Retrieved from the mobile operating system"; boolean updateNeeded = false; boolean createNeeded = (null == endpointArn); if (createNeeded) { // No platform endpoint ARN is stored; need to call createEndpoint. endpointArn = createEndpoint(); createNeeded = false; } System.out.println("Retrieving platform endpoint data..."); // Look up the platform endpoint and make sure the data in it is current, even if // it was just created. try { GetEndpointAttributesRequest geaReq = new GetEndpointAttributesRequest() .withEndpointArn(endpointArn); GetEndpointAttributesResult geaRes = client.getEndpointAttributes(geaReq); updateNeeded = !geaRes.getAttributes().get("Token").equals(token) || !geaRes.getAttributes().get("Enabled").equalsIgnoreCase("true"); } catch (NotFoundException nfe) { // We had a stored ARN, but the platform endpoint associated with it // disappeared. Recreate it. createNeeded = true; } if (createNeeded) { createEndpoint(); } System.out.println("updateNeeded = " + updateNeeded if (updateNeeded) { // The platform endpoint is out of sync with the current data; // update the token and enable it. System.out.println("Updating platform endpoint " + endpointArn); Map attribs = new HashMap(); attribs.put("Token", token); attribs.put("Enabled", "true"); SetEndpointAttributesRequest saeReq = new SetEndpointAttributesRequest() .withEndpointArn(endpointArn) .withAttributes(attribs); client.setEndpointAttributes(saeReq); } } /** * @return never null * */ private String createEndpoint() { String endpointArn = null; try { System.out.println("Creating platform endpoint with token " + token); CreatePlatformEndpointRequest cpeReq = new CreatePlatformEndpointRequest() .withPlatformApplicationArn(applicationArn) .withToken(token); CreatePlatformEndpointResult cpeRes = client .createPlatformEndpoint(cpeReq); endpointArn = cpeRes.getEndpointArn(); } catch (InvalidParameterException ipe) { String message = ipe.getErrorMessage(); System.out.println("Exception message: " + message); Pattern p = Pattern .compile(".*Endpoint (arn:aws:sns[^ ]+) already exists " + "with the same token.*"); Matcher m = p.matcher(message); if (m.matches()) { // The platform endpoint already exists for this token, but with // additional custom data that // createEndpoint doesn't want to overwrite. Just use the // existing platform endpoint. endpointArn = m.group(1); } else { // Rethrow the exception, the input is actually bad. throw ipe; } } storeEndpointArn(endpointArn); return endpointArn; } /** * @return the ARN the app was registered under previously, or null if no * platform endpoint ARN is stored. */ private String retrieveEndpointArn() { // Retrieve the platform endpoint ARN from permanent storage, // or return null if null is stored. return arnStorage; } /** * Stores the platform endpoint ARN in permanent storage for lookup next time. * */ private void storeEndpointArn(String endpointArn) { // Write the platform endpoint ARN to permanent storage. arnStorage = endpointArn; } }

关于此实施,需要说明的有趣的一点是在 createEndpoint 方法中如何处理 InvalidParameterException。当现有平台终端节点具有相同的设备令牌和非空 CustomUserData 字段时,Amazon SNS 将拒绝创建平台终端节点请求,否则会覆盖(进而丢失)CustomUserData。上述代码中的 createEndpoint 方法会捕获 Amazon SNS 引发的 InvalidParameterException,检查是否由于此特殊原因而引发;如果是,则从异常中提取现有平台终端节点的 ARN。这会成功,因为存在具有正确设备令牌的平台终端节点。

有关更多信息,请参阅 使用 Amazon SNS 移动推送 API

故障排除

使用过期设备令牌重复调用创建平台终端节点操作

特别是对于 GCM 终端节点,您可能会认为最好是存储应用程序发布的第一个设备令牌,然后在每次应用程序启动时,使用该设备令牌调用创建平台终端节点操作。这似乎正确,因为它会使得应用程序无需管理设备令牌的状态,Amazon SNS 自动将设备令牌更新为其最新值。但是,此解决方案存在多个严重问题:

  • Amazon SNS 依靠来自 GCM 的反馈将失效的设备令牌更新为新的设备令牌。GCM 会保留旧的设备令牌一段时间,但并非无限期保留。GCM 忘掉旧设备令牌与新设备令牌之间的联系之后,Amazon SNS 无法再将存储在平台终端节点中的设备令牌更新为其正确值,而只是改为禁用平台终端节点。

  • 平台应用程序将包含与同一个设备令牌对应的多个平台终端节点。

  • Amazon SNS 对使用相同设备令牌创建的平台终端节点数量施加了限制。最终,新终端节点的创建将会失败,引发无效参数异常并显示以下错误消息:“此终端节点已注册到其他令牌。”

重新启用与无效设备令牌关联的平台终端节点

当移动平台(例如 APNS 或 GCM)通知 Amazon SNS 在发布请求中使用的设备令牌无效时,Amazon SNS 将禁用与该设备令牌关联的平台终端节点。然后,Amazon SNS 将拒绝对该设备令牌的后续发布。虽然您可能会认为最好的方法是简单地重新启用平台终端节点并保持发布,但大多数情况下这样做不会有成效:发布的消息不会被传输,平台终端节点随后很快会再次被禁用。

这是因为与平台终端节点关联的设备令牌已真正无效。由于它不再对应于任何已安装的应用程序,因此以它为目标的传输操作不会成功。下次发布到该平台终端节点时,移动平台将再次通知 Amazon SNS 设备令牌无效,Amazon SNS 将再次禁用该平台终端节点。

要重新启用已禁用的平台终端节点,该终端节点需要关联到有效的设备令牌(使用设置终端节点属性操作调用),然后再启用。只有这样,以该平台终端节点为目标的传输操作才会成功。要在不更新设备令牌的情况下重新启用平台终端节点,这种方法只有当与终端节点关联的设备令牌曾经无效但重新变得有效时才有起作用。例如,在相同移动设备上卸载、然后重新安装了某个应用程序并收到了相同的设备令牌时,会出现这种情况。上述方法会执行此操作,确保只有在验证与某个平台终端节点关联的设备令牌是最新可用的设备令牌时,才重新启用该平台终端节点。