メニュー

2014年3月17日

Apple Push Notifications (APNs) のPythonライブラリを作りました

iOSデバイスにプッシュ通知をする仕組みとして Apple Push Notifications (通称APNs) というものが用意されています。これを利用するためのライブラリを作成しました。

https://github.com/najeira/pyapns

使い方は上記のリポジトリのREADMEやソースを読んでください。

作る前にGithubやPyPIでPythonのライブラリを探してみたのですが、エラーハンドリングをちゃんとしているライブラリが見当たらなかったため作りました。

なぜライブラリでエラーをちゃんと処理しているものが見当たらなかったかというと、APNsの仕様が関係していると思います。

APNsによるプッシュ通信は、バイナリプロトコルのメッセージを、TCPで順次送っていくようになっています。

そして、エラーが返ってこなかったら成功、エラーが返ってきたらエラーという仕様になっています。つまりエラーが返ってきていない時に「成功したからエラーが返ってこない」のか「まだエラーが返ってきていない」のか区別が出来ません。それともちろん非同期です。

例えばHTTPのような1リクエスト対1レスポンスの仕組みだったら楽なのですが……。

仮にAPNsのための同期APIを実装しようとすると、ソケットに対してWriteしたあとに1秒ほど待ってからReadしてみて、エラーが返ってきていなければ成功とするような実装になってしまいます。これだと1回のAPIの呼び出しに1秒以上かかってしまいます。とても大量のプッシュ通知をすることはできません。

あるいはエラー応答を無視すれば、待ち時間なく大量にプッシュ通知をできるので、これで解決……と思いきや、そうはうまく行きません。というのは、APNsではエラーが発生すると、それ以降のリクエストもすべて失敗します。よってエラーを無視すると、どこまで成功して、どこから失敗したか分からなくなります。

他にも1メッセージごとに接続と切断を繰り返す実装にすると、エラーが後続に波及しないので、うまくいくかに思えますが、接続はSSLなのでオーバーヘッドが大きくて難しい。

そういうわけで、ソケットに対してWriteでメッセージを送りつつ、向こうからの応答があればReadしてエラーを検知し、どのメッセージがエラーだったのかを遡って判定して、エラー箇所の次のメッセージからリトライする必要があります。面倒ですね。

AppleはKeep−AliveなHTTPでのAPIを提供すればいいのにと、つくづく思いました。