Parse.comでは、Push Notificationをサポートしています。
見た目にもわかりやすいUIのDashboardからPush notificationを送信できるのですが、
それ以外にREST APIを使って、アプリ側からPush notificationを送信できます。
DeviceTokenを使って細かく制御する方法が若干わかりにくかったので、それについて書きます。
##Parse APIへの送信
Push notificationは最低限alert
があればいいので、curl
を使うと下記のように指定して送信します。
X-Parse-Application-Id
(Application ID)とX-Parse-REST-API-Key
(REST API Key)は、DashboardのOverviewから取得出来ます。
後はなんとログインした状態で、Documentを見ている場合、コード例に直接Keyが埋め込まれているためそのまま実行出来ます!!
curl -X POST \
-H "X-Parse-Application-Id: <Application ID>" \
-H "X-Parse-REST-API-Key: <REST API Key>" \
-H "Content-Type: application/json" \
-d '{
"data": {
"alert": "The Giants won against the Mets 2-3."
}
}' \
https://api.parse.com/1/push
##ParseのNotificationフォーマットについて
簡単に表すと下記のJSONフォーマットになります。
where
のところに条件を指定するので、ここにdeviceToken
を指定すれば特定の端末にPush Notificaitonを送信することができます。
-
data
のところに、iOSまたはAndroidのnotificationデータを入れる - 送信日時、有効期限の指定が簡単
-
where
のところに、条件Queryを指定できる-
$lt
(less then)、$in
(containd in)など、一般的な条件演算子がひと通り揃っているので、柔軟なリクエストが可能
-
{'where': {'deviceToken': [], # Query APIを使った条件指定
},
'push_time': '2013-01-23T12:00:00Z', # 通知開始日時(iso)
'expiration_interval': '518400', # 有効期限
'expiration_time': '2013-01-23T21:08:39Z', # 有効期限日時指定(iso)
'data': {
'alert': 'message',
'badge': 'Increment', # Number or 'Increment'(iOS only).
'sound': 'sound bundle', # iOS only.
'content-available': '1', # Newsstand content count(iOS only).
'action': 'Intent', # Android only.
'title': 'Notification!!', # Android only.
}
}
条件演算子を指定した場合は、こんな感じです。
{'data': {'alert': 'push notification message!',
'badge': 'Increment',
'sound': 'default'},
'where': {'deviceToken': {'$in': [u'<deviceToken1>', u'<deviceToken2>']}}}
###コード例
Pythonで書くとこんな感じになります。
# coding: utf-8
PARSE_API_BASE = 'https://api.parse.com'
PARSE_PUSH_API = '/1/push'
PARSE_PUSH_URL = PARSE_API_BASE + PARSE_PUSH_API
# Push Notificationに必要なKeyをHTTP Headerで指定
HEADERS = {
"X-Parse-Application-Id": "<Application ID>",
"X-Parse-REST-API-Key": "<REST API Key>",
"X-Parse-Master-Key": "<Master Key>",
"Content-Type": "application/json"
}
class APNMessageQueue(object):
""" APN(Apple Push notification)用メッセージを貯める
"""
structure = {
'user_id': lambda x: (x is not None and len(x) > 0),
'notify_token': lambda x: (x is not None and len(x) > 0),
'message': lambda x: (x is not None and len(x) > 0),
}
def __init__(self, *args, **kwargs):
for k in self.structure.keys():
self.__setattr__(k, kwargs.get(k, None))
@classmethod
def create(cls, user_id, notify_token, message):
src_props = dict(
user_id=user_id,
notify_token=notify_token,
message=message,
)
props = {}
for k, func in cls.structure.iteritems():
value = src_props.get(k)
if func(value):
props[k] = value
if props:
return APNMessageQueue(**props)
return None
def create_notify_message(message, badge='Increment', sound='default'):
""" Notificationメッセージから、PushNotificationフォーマット作成
Args:
message: Alertメッセージ.
badge: バッチカウント('Increment'はParse.com独自).
sound: Notification効果音.
Return:
PushNotificationフォーマット文字列.
"""
return {'alert': message, 'badge': badge, 'sound': sound}
def create_request_data(notify_token, apn_data):
""" Parse Notificationフォーマットテンプレ形式のデータ作成
Args:
notify_token: デバイストークンかそれのリスト.
apn_data: Apple Push Notificationデータ.
Returns:
ParseNotificationフォーマットテンプレ形式のデータ.
"""
request_data = {'data': apn_data}
if isinstance(notify_token, list):
request_data['where'] = {'deviceToken': {'$in': notify_token}}
else:
request_data['where'] = {'deviceToken': notify_token}
return request_data
def process_do_send(request_data):
""" ParseNotificationフォーマットテンプレ形式のデータを渡してPushNotification送信
Args:
request_data: ParseNotificationフォーマットテンプレ形式のデータ
Returns:
正常終了かエラーかを返す
"""
import json
from urllib2 import Request, urlopen, URLError
payload = json.dumps(request_data)
request = Request(PARSE_PUSH_URL, payload, HEADERS)
try:
response = urlopen(request)
data = json.loads(response.read())
if isinstance(data, dict):
return data.get('result', False)
except URLError, e:
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: %s' % e.reason
elif hasattr(e, 'code'):
print 'The server couldn\'t fulfill the request.'
print 'Error code: %d' % e.code
return False
def send_notification(notify_queue_list):
""" APNsへPushNotificationを送信
APNsサーバーへPushNotificationメッセージを一斉送信
Args:
notify_queue_list: APNMessageQueueのlist
"""
from itertools import groupby
notify_sorted_queue_list = sorted(notify_queue_list, key=lambda x: x.message)
# 同じメッセージはまとめて送る
for message, group in groupby(notify_sorted_queue_list, key=lambda x: x.message):
distict_tokens = list(set([user.notify_token for user in group]))
aps_data = create_notify_message(message)
request_data = create_request_data(distict_tokens, aps_data)
print request_data
process_do_send(request_data)
使う側はこう
# coding: utf-8
def send_push_parse_for_apn(message):
import models
import apn
# ユーザーデータから、Notification用deviceToken一覧を取得
targets = [x for x in models.User.find_by_existing_notify_token() if x is not None]
notify_token_list = [apn.APNMessageQueue(x.user_id, x.notify_token, message) for x in targets]
if len(notify_token_list) > 0:
# 発射ー
apn.send_notification(notify_token_list)
if __name__ == '__main__':
send_push_parse_for_apn('あボーーん!!')