プラットフォームエンドポイントを作成する - Amazon Simple Notification Service

プラットフォームエンドポイントを作成する

プッシュ通知サービスへのアプリケーションおよびモバイルデバイスの登録時に、プッシュ通知サービスはデバイストークンを返します。Amazon SNS はデバイストークンを使用して、モバイルエンドポイントを作成します。ここに直接プッシュ通知メッセージを送信できます。詳細については、「Amazon SNS ユーザー通知の前提条件」および「ユーザー通知プロセスの概要」を参照してください。

このセクションでは、プラットフォームエンドポイントの推奨作成方法について説明します。

プラットフォームエンドポイントの作成

Amazon SNS を使用してアプリケーションにプッシュ通知を送信するには、まずプラットフォームエンドポイントの作成アクションを呼び出すことで、そのアプリケーションのデバイストークンを Amazon SNS に登録する必要があります。このアクションは、パラメーターとしてプラットフォームアプリケーションの Amazon リソースネーム (ARN) およびデバイストークンを使用し、作成されたプラットフォームエンドポイントの ARN を返します。

プラットフォームエンドポイントの作成アクションは、次の処理を行います。

  • プラットフォームエンドポイントが既に存在する場合、再度作成しないでください。呼び出し元に既存のプラットフォームエンドポイントの ARN を返します。

  • デバイストークンが同じだが設定が異なるプラットフォームエンドポイントが既に存在する場合、再度作成しないでください。呼び出し元に例外をスローします。

  • プラットフォームエンドポイントが存在しない場合は、作成します。呼び出し元に新しく作成したプラットフォームエンドポイントの ARN を返します。

このアプローチでは、作業エンドポイントが常に提供されるとは限らないため、アプリケーションが起動するたびにプラットフォームエンドポイントの作成アクションを呼び出さないでください。これは、例えばアプリケーションがアンインストールされて同じデバイスに再インストールされ、そのアプリケーションのエンドポイントが既に存在しているが無効な場合などに発生する可能性があります。登録プロセスに成功すると、以下のことが達成されます。

  1. このアプリケーションデバイスの組み合わせにプラットフォームエンドポイントが存在することを確認します。

  2. プラットフォームエンドポイントのデバイストークンが最新の有効なデバイストークンであることを確認します。

  3. プラットフォームエンドポイントが有効であり、使用できる状態にあることを確認します。

擬似コード

次の擬似コードは、さまざまな開始条件において有効な最新の作業プラットフォームエンドポイントを作成するための推奨される方法について説明します。このアプローチは、アプリケーションが初めて登録されるかどうか、このアプリケーションのプラットフォームエンドポイントが既に存在するかどうか、プラットフォームエンドポイントが有効かどうか、適切なデバイストークンがあるかどうかなどに関係なく機能します。重複するプラットフォームエンドポイントが作成されたり、既に最新のプラットフォームエンドポイントが有効になっている場合に既存のプラットフォームエンドポイントが変更されたりしないため、連続して複数回呼び出しても安全です。

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 に通知するときも使用できます。この場合、最新のデバイストークン値を持つアクションを呼び出すだけです。このアプローチについて注意が必要な点は次のとおりです。

  • プラットフォームエンドポイントの作成アクションの呼び出しが考えられる 2 つのケースがあります。アプリケーションが自身のプラットフォームエンドポイント ARN を認識していない、ごく最初の時点で呼び出される可能性があります。これは初回登録時に発生します。さらに、最初のエンドポイント属性の取得アクションが not-found 例外で失敗した場合にも呼び出されます。これは、アプリケーションがエンドポイント ARN を認識しているが、削除された場合に発生する可能性があります。

  • エンドポイント属性の取得アクションは、プラットフォームエンドポイントが作成されたばかりの場合でもプラットフォームエンドポイントの状態を確認するために呼び出されます。これは、プラットフォームエンドポイントが既に存在するが無効になっている場合に発生します。この場合、プラットフォームエンドポイントの作成アクションが成功しますが、プラットフォームエンドポイントは有効にならないため、成功を返す前にプラットフォームエンドポイントの状態をもう一度確認する必要があります。

AWS SDK の例:

以下の例では、AWS SDK で提供されている Amazon SNS クライアントを使用して前の疑似コードを実装する方法について説明します。

AWS SDK を使用するには、認証情報を使用して設定する必要があります。詳細については、『AWS SDK とツールのリファレンスガイド』の「共有設定ファイルおよび認証情報ファイル」を参照してください。

Java
SDK for Java 1.x

class RegistrationExample { AmazonSNSClient client = new AmazonSNSClient(); //provide credentials here String arnStorage = null; public 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(token); } 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 token) { 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 [Tt]oken.*"); 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. Use the // existing platform endpoint. endpointArn = m.group(1); } else { // Rethrow the exception, because 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; } }
  • 手順とその他のコードについては GitHub でご確認いただけます。

詳細については、「モバイルプッシュ API アクション」を参照してください。

Troubleshooting

古いデバイストークンを使用してプラットフォームエンドポイントの作成を繰り返し呼び出す

特に FCM エンドポイントの場合、アプリケーションを発行した最初のデバイストークンを保存してから、アプリケーションが起動するたびにそのデバイストークンを使用してプラットフォームエンドポイントの作成を呼び出すのが最適に思えるかもしれません。これは、アプリケーションがデバイストークンの状態を管理する必要がなくなり、Amazon SNS がサービストークンを最新の値に自動的に更新するため、適切に思えるかもしれません。しかし、この解決策には多くの深刻な問題があります。

  • Amazon SNS は、有効期限切れのデバイストークンを新しいデバイストークンに更新するために FCM からのフィードバックが必要です。FCM は、古いデバイストークンの情報を当分の間保持しますが、無期限に保持するわけではありません。FCM が古いデバイストークンと新しいデバイストークンの関連性の認識を失うと、Amazon SNS はプラットフォームエンドポイントに保存されたデバイストークンを適切な値に更新することができなくなります。代わりに、プラットフォームエンドポイントが無効になるだけです。

  • プラットフォームアプリケーションには、同じデバイストークンに対応する複数のプラットフォームエンドポイントが含められます。

  • Amazon SNS では、同じデバイストークンを使用して作成できるプラットフォームエンドポイントの数に限度が適用されます。最終的に、新しいエンドポイントの作成は無効なパラメータの例外によって失敗し、「This endpoint is already registered with a different token.」 というエラーメッセージが表示されます。

無効なデバイストークンに関連付けられたプラットフォームエンドポイントを再度有効にする

モバイルプラットフォーム (APN や FCM など) が、発行リクエストで使用されたデバイストークンが無効であったことを Amazon SNS に通知すると、Amazon SNS はそのデバイストークンに関連付けられたプラットフォームエンドポイントを無効にします。その後、Amazon SNS はそのデバイストークンへのその後の発行を拒否します。プラットフォームエンドポイントを再度に有効にして発行を継続すれば最適と思うかもしれませんが、ほとんどの場合これはうまくいきません。発行されるメッセージは配信されず、プラットフォームエンドポイントはその後まもなく無効になります。

これは、プラットフォームエンドポイントに関連付けられたデバイストークンが間違いなく無効であるためです。プラットフォームエンドポイントは、インストールされているどのアプリケーションにも応答しないため、配信が成功することはありません。次回発行されると、モバイルプラットフォームはデバイストークンが無効であることを Amazon SNS にもう一度通知し、Amazon SNS はプラットフォームエンドポイントをもう一度無効にします。

無効なプラットフォームエンドポイントを再度有効にするには、有効なデバイストークンに関連付けた後 (エンドポイント属性の設定アクションを呼び出して)、有効にする必要があります。その場合のみ、そのプラットフォームエンドポイントへの配信は正常に行われます。デバイストークンを更新しないでプラットフォームエンドポイントを有効にできるのは、そのエンドポイントに関連付けられたデバイストークンが無効であったが、再度有効となった場合のみです。これは、例えばアプリケーションがアンインストールされて同じモバイルデバイスに再インストールされ、同じデバイストークンを受け取った場合などに発生します。上に示したアプローチではこれが行われます。関連付けられたデバイストークンが使用可能な最新のものであると確認してから、プラットフォームエンドポイントを再度有効にすることのみ確実に行ってください。