9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-04-19

サーバ側の処理

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;
}
9
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?