2013年10月25日金曜日

Google Cloud Messaging (GCM) で通知が来ない

GCMでNotifyを構築しているサービスやアプリはたくさんアリますが。たまに通知がこないなぁ、とか、googleのサーバに通知は投げられてて、レスポンスもsuccessなのに端末に届かない!とか。そういうことは多々あります。自分もその辺りをいろいろと調べていて、最近面白いアプリを見つけたのをきっかけに、このエントリを書いてます。

こちらのアプリ
PNF ( Push Notification Fixer )



通知が来ない理由はいつくか考えられますが、主に

3rd-partyサーバ側の問題
Clientの実装の問題
ネットワークの問題

が挙げられます。あと細かく言えばGoogleのサービスそのもの問題があるか。。

このなかで厄介なのはネットワークの問題と思います。3rd-partyサーバもクライアントもちゃんとリファレンスみて作ってるのに、通知が来ないときあるよね!とかそういう状況は、結構な確率でネットワーク側の問題を見落としている場合があります。

まずGCMの動作の前提として、TCPセッションをGoogleのサーバに対して張り続け、これを維持することで、リアルタイムなpush通知を実現しているので、このTCPセッションをヘルシーにキープできるネットワーク構造になっていないといけません。

よくはまるのはNATの問題です。NATは自宅のBBRにのってるNATや、キャリアが実行するCGN(キャリアグレードNAT)などですが。一回張られたセッションはNATを維持するための機能によって、一定時間通信が可能な状態に保持されます。この場合あて先とポート番号の組み合わせで管理されるのが一般的ですが、この情報は一定時間で破棄され、使用されていたりソースも開放されます。

つまりTCPセッションに何もパケットが通らない場合、NATは一定時間でこれを破棄します。GCMの場合もTCPセッションを双方向につかって通知をやりとりするわけですから、無通信が続けば(通知の送受信がなければ)NATによってはこのセッションを閉じようとします。

GCMの設定値を見てみましょう


WIFI : 15分
3G/LTE :  53分

これがGCMのベースになっているTCPセッションをKeepaliveするハートビートのタイミングのようです。いくつかの端末をサンプルしてしらべましたが、ほとんどこの値でした。これらの値は内部的なsqliteのDBに格納されるパラメータですので、これを書き換えることでハートビートのタイミングを変更することができますが、先ほどの面白いアプリというのはまさにこれをやってくれます。が、要rootです。

なのでネットワーク側でなんとかするとなるとNATテーブルの破棄のタイミングを少なくとも、WIFIでは15分以上に、3G/LTEの場合は53分以上にするのがいいと思われます。Androidの携帯を出している各キャリアはすでにプライベートIPを割り当てるネットワーク構成にほとんどなっていますので、このAndroidの実装を考えるとgoogleの通知サーバに対するTCPセッションはすくなくとも53分以上保持されるようになっているはずです。

さて、キャリア以外のMVNOの状況はどうでしょうか?ちゃんと考えてやってるかなぁ?
上記のアプリのサポートスレがXDAにありますが、喜びの書き込みをする人がかなりいますね。海外の3Gのユーザがほとんどだと思いますが、ここからわかるのは、CGNでexpireが53分以下のキャリアは普通にあるってことかもしれません。

ま、推測ですので、違ったらごめん。


これは GTalk Service Monitor の画面ですが、多くの端末では電話アプリから、*#*#8255#*#*でミルことができます(できない端末もあります)ので、Hertbeatの部分とc2dmの部分に着目してください。最後に通知を受け取ったのがどのくらい前か、ハートビートは次回いつ送信されるかがわかります。

ハートビートの送信タイミングはバッテリの減りにも影響があるので、単純に1分とかにはしないほうがいいですね。

PNFをつくってくれたandQlimaxに感謝!