2013-10-05

botoを使ってAWS SNSのMobile Pushを利用する (APNs編)

boto自体使うのが初めてだったので、おかしい所があるかもしれないが動作はした。APNsのSSL証明書作成等は毎度の事なので省略。Application ARNはAWS Consoleから既に作成してあるとする。

デバイス指定でメッセージ送信する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -*- coding: utf-8 -*-
 
import boto.sns
 
AWS_ACCESS_KEY = 'xxxx'
AWS_SECRET_ACCESS_KEY = 'yyyyyyyy'
APPLICATION_ARN = \
    'arn:aws:sns:ap-northeast-1:0000:app/APNS_SANDBOX/aaaa'
 
# SNSに接続
sns_connection = boto.sns.connect_to_region('ap-northeast-1',
        aws_access_key_id=AWS_ACCESS_KEY,
        aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
 
# 送信先デバイスを指定してendpointを作成
res = sns_connection.create_platform_endpoint(
        platform_application_arn=APPLICATION_ARN,
        token='xxxxxxxx')
endpoint = res.get('CreatePlatformEndpointResponse')\
              .get('CreatePlatformEndpointResult').get('EndpointArn')
 
# endpointに送信
sns_connection.publish(target_arn=endpoint, message=u"Hello World")
endpointは一度作成したら、保存しておけば再度 create_platform_endpoint する必要は無い。

Topic経由でメッセージ送信する

Topicをsubscribeしているデバイスに一斉送信するパターン、Topicをsubscribeする際の第二引数はbotoのソースを読んでもわからなかったが、AWSコンソールのTopic管理画面から推測すると "application" を指定したら良い気がする。そして実際に動作する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# -*- coding: utf-8 -*-
 
import boto.sns
 
AWS_ACCESS_KEY = 'xxxx'
AWS_SECRET_ACCESS_KEY = 'yyyyyyyy'
APPLICATION_ARN = \
    'arn:aws:sns:ap-northeast-1:0000:app/APNS_SANDBOX/aaaa'
 
# SNSに接続
sns_connection = boto.sns.connect_to_region('ap-northeast-1',
        aws_access_key_id=AWS_ACCESS_KEY,
        aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
 
# 送信先デバイスを指定してEndpointを作成
res = sns_connection.create_platform_endpoint(
        platform_application_arn=APPLICATION_ARN,
        token='xxxxxxxx')
endpoint = res.get('CreatePlatformEndpointResponse')\
              .get('CreatePlatformEndpointResult').get('EndpointArn')
 
# Topicを作成
res = sns_connection.create_topic('test_topic')
topic = res.get('CreateTopicResponse')\
           .get('CreateTopicResult').get('TopicArn')
 
# TopicをSubscribe
sns_connection.subscribe(topic, 'application', endpoint)
 
# Topicに送信
sns_connection.publish(topic=topic,
                       message=u"Hello World for Topic subscriber")
Topicにぶらさげるデバイスの数は1万が上限との事なので、アプリのユーザー全員に送信するといった場合にはTopicを分けるか、全てのEndpointに送信するかどちらかになる。あまり楽させてはくれない様だ。Endpointを削除した場合、Topicから勝手にunsubscribeされると思いきやそうでもなかった。

JSON形式でbadgeやalertを送る

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Payloadの中身
message = json.dumps({
    "aps": {
        "alert": {
            "body": "Hey Hey",
            "action-loc-key": None
            },
        "badge": 100
        }
    })
 
# Payloadの長さチェック
if len(message) > 255:
    raise "APNs payload over 255 bytes!!!!"
 
# 送信先プラットフォームの指定、本番であればAPNS
# Android向けのPushもここで同時に指定できる
data = json.dumps({"APNS_SANDBOX": message})
 
# message_structure='json'を指定してPublish
try:
    sns_con.publish(
            target_arn=endpoint,
            message=data,
            message_structure='json')
except BotoServerError, e:
    logger.warn(
        "BotoServerError status:%s %s %s",
        e.status, e.reason, e.error_message)
Payloadを一度作った後、文字列にして再度JSONにつっこむという面倒な事が必要。

APNsのFeedback Serviceはいつ呼ばれるか

SNSの内部でよろしくやってくれてるようだが、その結果をboto経由で参照する方法は見つからなかった。Feedback Serviceの結果から、どの程度アプリがデバイスから削除されたかモニタリングしたいといった場合にはSNSは使えないだろう。