boto自体使うのが初めてだったので、おかしい所があるかもしれないが動作はした。APNsのSSL証明書作成等は毎度の事なので省略。Application ARNはAWS Consoleから既に作成してあるとする。
デバイス指定でメッセージ送信する
# -*- 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" を指定したら良い気がする。そして実際に動作する。# -*- 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を送る
# 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につっこむという面倒な事が必要。