channel9で公開されているde:code2014のセッション動画で、エヴァの井上さんが話された「Azure Mobile Services & Notification Hubs で全てのデバイスにプッシュ通知を送る」をまとめた投稿です。
プッシュ通知とは?
アプリが非アクティブでもバックエンドでデバイスに新しい情報を表示することができる機能が、プッシュ通知です。好きなタイミングで好きなメッセージを送れる機能です。プッシュ通知によって、アプリケーションの起動きっかけを作るのです。
プッシュ通知の仕組み
バックエンドのアプリケーションから直接、端末のアプリケーションに通知を送っているわけではないのです。
バックエンドから、各ベンダーが提供するPNS(Platform Notification Services)経由で端末にプッシュ通知します。Windows 8の場合はWNS、iOSの場合はAPNs、Androidの場合はGCMとそれぞれおベンダーごとにPNSが異なり、プロトコルも異なります。
バックエンドからPNSには、ハンドルごとにリクエストをします。ハンドルは端末固有のトークンで、端末1つにつき1リクエスト送信する必要があります。たとえば、10万台のデバイスに通知する場合には、10万回リクエストを送信しないといけないのです。あるお客さんの例では、リクエストを送信し始めてから送信終了まで、4時間かかったケースもあります。
ハンドルは、アプリケーションがPNSから取得して、それをバックエンドのサーバーに保存して使用するという流れになります。
ハンドルは上記例のように、単なる文字れるです。一番上がAndroid、二つ目がWindowsのハンドルです。
一般的な課題としては、4つです。
プラットフォームごとに対応をしないといけないので、マルチプラットフォーム対応が必要になります。また、正常に送信できたのか失敗したのかをトレースしたいのでエラー処理が必要です。さらに、端末はどんどん買い換えていくのでハンドルが変わっていくので、サーバーにゴミデータがたまるので、データのライフサイクル管理が必要です。そして、大量の宛先に素早く送信するためのリアルタイム大量通知が課題になります。
Azureの2つの通知サービス
Microsoft Azureには2つの通知サービスが提供されています。
2種類の通知サービスが提供されているので、度々理解の混乱のもととなっています。
最初に登場したのが、BaaSの機能の一つとしてMobile Servicesの中でプッシュ通知を提供していました。その後に登場したのが、プッシュ通知に特化した通知ハブ(Notification Hubs)と言うサービスが提供されました。
Mobile Servicesの通知も改良されています。
管理ポータルでMobile Servicesのプッシュタブを見ると、上記画像のように表示されます。今は、通知ハブのAPIを使うように改良されているのです。
今後、通知の機能を使う場合には、通知ハブを意識していただければOKです。
通知ハブになると、いろいろな課題が改良されました。Mobile ServicesはBaaSの一部だったので、通知だけ欲しい顧客には大きすぎたり、あまり課題が改良されていなかったのです。
通知ハブのプッシュ通信
通知ハブはREST APIで操作します。
.NET、Node.jsのSDKが提供されており、直接REST通信をしなくても良いようになっています。
通知ハブは、プッシュ通知のハブとなるサービスです。
バックエンドとPNSの間にあって、様々な処理を受け持ちます。
バックエンドから通知ハブにリクエストを送り、通知ハブにデータベースがありハンドル情報を保持しているので、通知ハブから並列にPNSにリクエストを送信します。
通知ハブにリクエストを送信すると、ゲートウェイノードが受信しキューに登録します。通知ノードがキューを取得し、データストアからハンドルを取得します。ハンドルを取得して、数万とかある大量の通知だと判明すると、自動的に通知ノードがスケールします。通知ノードが自動的に何台も立ち上がって、並列に通知してくれます。
通知が失敗すると、PNSからエラーを受け取って、データストアに格納してくれます。また、ハンドルがどんどん新しいものに変わっていきますので、それも管理してくれます。期限切れしたハンドルは勝手に削除してくれます。
プッシュ通知の課題をしっかりと解決してくれています。
50万通で2040円ぐらいです。
これを自前で実装するには相当の開発と運用工数がかかるため、自前で用意するのが割にあわなくなっています。
どれぐらいスケールするのか。
Bingニュースの事例では、300万台以上の端末に2分以内で通知できています。
通知サービスの実装とテスト
提供されているSDKは、サーバーサイドは.NETとJavaScript、クライアントサイドはだいたい通常使われる端末は用意されています。
重要なクラスが2つあります。
NotificationHubClientクラスは、管理用のクラスです。通知ハブのデータべースの読み書きや通知の送信ができたり、なんでもできるサーバサイドのクラスです。
NotificationHubクラスは、PNSからハンドルをとってきて、通知ハブにハンドルを登録する、フロントのクラスです。
NotificationHubClientクラスは、Microsoft.ServiceBusの中に含まれているので、最初にNuGetで取得してきてください。
クライアントのほうは、Microsot.WindowsAzure.Messaging.Managedに、NotificationHubクラスが含まれているのでインストールしておいてください。
PushNotificationChannelManager.CreatePushuNotificationChannelForApplicationAsyncを呼ぶとPNSからハンドルを取得してきます。
NotificationHubで、通知ハブの名前を設定し、通知ハブの接続情報を指定します。
RegisterNativeAsyncで、ハンドルの情報を渡すと通知ハブのデータベースにハンドルを登録します。
Andoroidの場合も、同様の流れで操作できます。これはSDKが提供されているからです。
NotificationHubは同じで、Androidの場合はm、gcmからハンドルを取得してきて、通知ハブのデータベースにハンドル情報を登録します。
Microsoft Azureの管理ポータル上から、サーバーサイドの実装をしてなくてもプッシュ通知のテストをしたりすることができます。
サーバーサイドの実装です。
NotificationHubClient.CreateClientFromConnectionStringで、管理者用の接続情報を設定します。
メッセージ本文を設定し、送信します。メッセージ本文は、それぞれの端末の通知の従って記述します。そして、送信メソッドで送信します。
Androidは、SendGcmNativeNotificationAsync
iOSは、SendAppleNativeNotificationAsync
windowsは、SendWindowsNativeNotificationAsync
タグを使用して、特定のユーザーやグループだけに通知を送ることができます。通知ハブにタグを登録しておいて、タグでフィルタリングして送信できます。
タグは文字列です。
タグの登録には、RegisterNativeAsyncで、ハンドルとタグを指定します。
送信には、送信メソッドSendGcmNativeNotificationAsyncに、タグを渡してあげるだけでOKです。
タグのほかの使い方としては、アクセスログから長期間アクセスしていないユーザー全員にプッシュ通知をするというような使い方もできます。
テンプレート機能で一斉に複数プラットフォームにメッセージを変更して、データ送信することもできます。
大量配信のテストをしたいという要望があります。
その場合に裏技として、通知ハブに同じハンドルを大量に登録しておく方法があります。
同じハンドルを100件登録しておけば、100件の送信テストができます。
(同じ端末に100個通知されます…。)