Help us understand the problem. What is going on with this article?

[PHP]Amazon SNS を使い、iOS・AndroidへPUSH通知 - デバイストークン登録・更新編 -

More than 1 year has passed since last update.

サーバ側の処理

AWS SDK for PHPをインストール

いくつか方法がありますが、今回はpharでインストールします。
以下のページの"download the packaged phar"からダウンロードしてください。
https://docs.aws.amazon.com/aws-sdk-php/v3/guide/getting-started/installation.html

AWS SDK読み込み

require APP. 'Vendor/aws.phar';
use Aws\Sns\SnsClient;

サーバーに設置して読み込むだけです。
パスは環境によって適宜変更してください。

SNSクライアントを生成

$sns = SnsClient::factory(array(
    'version' => 'latest',
    'credentials' => array(
        'key' => AWS_KEY,
        'secret'  => AWS_SECRET,
    ),
    'region' => 'ap-northeast-1'
    )
);

SNS APIにリクエストするときに必要となります。
key と secret にはAWSから取得した、アクセスキーIDとシークレットアクセスキーを設定します。

デバイストークン登録とプラットフォームエンドポイント取得

$options = array(
    'PlatformApplicationArn' => APP_ARN,
    'Token' => $push_token,
    'CustomUserData' => $user_id, 
    'Attributes' => ['Enabled' => 'true'],
);

// デバイストークンをAmazon SNSに登録する
$result = $sns->createPlatformEndpoint($options);

if (isset($result['EndpointArn'])) {
    $endpoint = $result['EndpointArn'];
}

・PlatformApplicationArn
 iOSならiOSのアプリケーションARN、AndroidならAndroidのアプリケーションARNを設定します。
・Token
 アプリから送られてきたデバイストークンです。
・CustomUserData
 ユーザーの識別子です。ユーザーIDを入れておくといいと思います。

登録が完了するとプラットフォームエンドポイントが生成されるので、DBに保存しておきます。

注意点

既にSNSに登録されているデバイストークンで "createPlatformEndpoint" を実行した場合、
CustomUserData が同じであれば正常に登録されたときと同じようにエンドポイントが返却されます。
この場合はエンドポイントが無効になっていても、自動的に有効にはならないので、別途有効にする処理が必要となります。

CustomUserData が異なる場合はエラーとなり、エラーメッセージに "already exists" が入ります。
この場合はエラーメッセージの中からエンドポイントを抜き出して、DB更新やエンドポイントの有効化を行います。

ALLトピックに追加

$sns->subscribe(array(
  'Endpoint' => $endpoint,
  'Protocol' => 'Application',
  'TopicArn' => $topic_arn,
));

・TopicArn
 前回作成した全配信用のトピックARNを設定します。
 iOSならiOS用のトピックARN、AndroidならAndroid用のトピックARNです。

デバイストークン更新

アプリ側でデバイストークンが更新されている場合があったり、エンドポイントが無効になっている場合があるので、アプリ起動時に毎回実行するといいと思います。

$sns->setEndpointAttributes(array(
    'EndpointArn' => $endpoint,
    'Attributes' => array(
        'Enabled' => 'true',
        'Token' => $push_token,
    )
));

・EndpointArn
 上記の登録APIから取得したエンドポイントを設定します。
・Attributes
 エンドポイントが無効になっている場合もあるので、"'Enabled' => 'true',"を設定します。
 デバイストークンもここで設定します。

登録・更新共通ロジック

登録も更新も同時にできるfunctionを作成しました。
新規の場合はデバイストークンのみ、更新の場合はエンドポイントも付与します。

// デバイストークンをSNSに登録する
private function add_sns_endpoint($device_type, $user_id, $push_token, $endpoint = NULL) {
    $app_arn = '';
    $topic_arn = '';

    if ($device_type == '1') {
        $app_arn = IOS_APP_ARN;
        $topic_arn = IOS_ALL_TOPIC_ARN;
    } else {
        $app_arn = ANDROID_APP_ARN;
        $topic_arn = ANDROID_ALL_TOPIC_ARN;
    }

    // SNSクライアント生成
    $sns = SnsClient::factory(array(
        'version' => 'latest',
        'credentials' => array(
            'key' => AWS_KEY,
            'secret'  => AWS_SECRET,
        ),
        'region' => 'ap-northeast-1'
        )
    );

    if ($endpoint) {
        // DBにendpointが登録されている場合は Enabled と Token を更新
        try{
            $sns->setEndpointAttributes(array(
                'EndpointArn' => $endpoint,
                'Attributes' => array(
                    'Enabled' => 'true',
                    'Token' => $push_token,
                )
            ));
            return $endpoint;
        }
        catch (Exception $e) {
            // 何か問題があれば新規登録する
        }
    }

    $options = array(
        'PlatformApplicationArn' => $app_arn,
        'Token' => $push_token,
        'CustomUserData' => $user_id, //User Data
        'Attributes' => ['Enabled' => 'true'],
    );

    $endpoint = '';

    try {
        // デバイストークンをAmazon SNSに登録する
        $result = $sns->createPlatformEndpoint($options);

        if (isset($result['EndpointArn'])) {
            $endpoint = $result['EndpointArn'];

            // OS別のALLトピックに登録
            $sns->subscribe(array(
              'Endpoint' => $endpoint,
              'Protocol' => 'Application',
              'TopicArn' => $topic_arn,
            ));
        } else {
            return false;
        }
    } catch (Exception $e) {
        // 同じデバイストークンが既に登録済みで、CustomUserDataが異なる場合はエラーが発生する
        $message = $e->getMessage();

        preg_match("/.+Endpoint (.+) already.+/",$message,$matches);

        if (count($matches) > 1) {
            // エラーメッセージからエンドポイントを取得
            $endpoint = $matches[1];

            try{
                // エンドポイントを Enabled に変更する
                $sns->setEndpointAttributes(array(
                    'EndpointArn' =>$endpoint,
                    'Attributes' => array(
                        'Enabled' => 'true',
                        'Token' => $push_token,
                    )
                ));
            }
            catch (Exception $e) {
                return false;
            }
        } else {
            return false;
        }
    }

    return $endpoint;
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした