Help us understand the problem. What is going on with this article?

複数端末を所持している人を考慮してプッシュ通知を送る

More than 3 years have passed since last update.

Gmailとかハングアウトとかって、複数端末で通知を受けても、1つの端末で消せばちゃんと全部の端末で通知消えるんですよね。

これがやりたい。

あれ、どうやるの? という話です。

ざっくり

プッシュを受け取った端末が「受け取ったよ!」って空プッシュを送って send-to-sync する、みたいなことをやらないといけないようです。
Slice.png

以下のリファレンスを見ると、Device Group Messagingというのをつかうだけで、GCMがいい感じにやってくれるようにも見えますが、実際に動かしてみると、プッシュ消去は同期されませんでした・・・・・・。

http://www.androiddocs.com/google/gcm/notifications.html
https://firebase.google.com/docs/cloud-messaging/android/device-group

Device Group Messaging

Slice.png

FCMには、メッセージ送信の to パラメータにグループを指定することで、そのグループに属する端末たちの通知が同期される仕組みがあります。
グループがあれば、個々のデバイストークンを指定せずにメッセージが送れるので、ユーザ単位でプッシュを送りたいケースでは、1デバイスであっても使う価値はありそうです。

グループ?

https://android.googleapis.com/gcm/notification というエンドポイントにPOSTリクエストを出すことで、グループのメンバー管理ができるようです。

初めてグループを作るとき

{
   "operation": "create",
   "notification_key_name": "HogeAppUser0003",
   "registration_ids": ["xxxxx", "yyyyy"]
}

みたいなのをPOSTすると、グループのID文字列(notification_key)が返ってくるので、
それをどこかに覚えておいて送信時に使います。

registration_id は、Androidアプリ側で FirebaseInstanceId.getInstance().getToken(); で取得できるやつを指定。(これ、リファレンスには曖昧な書き方されてて、ちょっとハマるとこw)

グループにメンバーを追加・削除するとき

{
   "operation": "add",
   "notification_key": "作成時にもらったグループのID文字列",
   "registration_ids": ["zzzzz"]
}

とか

{
   "operation": "remove",
   "notification_key": "作成時にもらったグループのID文字列",
   "registration_ids": ["xxxxx"]
}

とかをPOSTすると、グループのID文字列(notification_key)が返ってきて成功! となります。

非常にくせのある仕様・・・

https://android.googleapis.com/gcm/notification のAPIは、
グループが0人か1人以上かによって挙動が変わります。これがすごくめんどくさい。

おそらく

  • 0人の時→createのみ可能。新規notification_keyが発行される。
  • 1人の時→add/removeのみ可能。notification_keyが引き継がれる

のような仕様なんだと思うんですが、

  • create したあと create →400エラー
  • create したあと同じ人を add →200 OK (notification_keyが返る)
  • add したあと同じ人を add →200 OK (notification_keyが返る)

あたりはわかるんですが、

  • createもしくはaddした人を remove →200 OK  ・・・ notification_keyが返るが、グループの残りが0人だったら、もうこのnotification_keyは使えない
  • remove した人を removeグループメンバーがのこり0人であれば 400エラー 、1人以上いたら 200 OK
  • remove した人を addグループメンバーがのこり0人であれば 400エラー 、1人以上いたら 200 OK
  • remove した人を create →グループメンバーが0人であれば 200 OK、 1人以上いたら 400エラー

あたりは、かなりくせっぽいなー (≒ こんな管理をやりたくないなー) と・・・w

ちなみに、Androidアプリから登録する際には、notification_key の指定無しで add/removeができるので、このようなめんどくさい考慮はいりません。(が、別のめんどくさい考慮が必要です・・・後述)
 
 

誰がメンバー管理をするべきか?

基本的に、「サーバーサイドで端末グループ管理なんて自前でやりたくないよー」っていう場合のことを書きます。

パターン1 グループ登録までAndroid側でやる

Android側で

  • ユーザIDから、一意で推測されにくい文字列を生成する ・・・これをグループ名としてつかう
  • アプリにログイン完了後、FCMトークンを取得し、グループを作成 or メンバー追加する
  • グループIDをサーバに送る

みたいなことをやる流れになります。

サーバーサイドでは

User has_one fcm_group_key

みたいな関連を持っておくだけでプッシュが送れるので、シンプルな構成になります。

ただ、AndroidのAPIは、 id_token が必要で、こいつは Googleログインを組み込んであげないと取得できない シロモノでして・・・
まぁ頑張って実装しましょう・・・。

 

とはいかないこともあるので・・・

パターン2 サーバー側でグループ登録処理だけはやる

Android側

  • アプリにログイン完了後、FCMトークンを取得後、それをサーバーに送る

サーバー側

  • もらったFCMトークンをもとに、グループを作成 or メンバー追加する
  • グループIDを登録する

という流れになります。

この場合は

User
 has_many fcm_tokens
 has_one fcm_group_key

のように2つの関連をもつことになるでしょう。

誰がどのグループに属しているかは知らなくてもよいですが、先に述べたような「くせのある仕様」を攻略する必要があります。

とはいえ、端末個別にもプッシュはおくりたいし、端末グループ単位(ユーザごと)にもプッシュはおくりたい、 という場合は必然的にこちらのパターンを採用することになるでしょう・・・。

  
  

で、どっちがいいの? といわれると、

  • サーバー側でFCMトークンを持つということ自体が何かと不便
  • そもそも端末単位で送りたいプッシュなんて、そんなにないでしょ?

という独断と偏見で、私はパターン1をおすすめします。 が、システムによって要件はまちまちなので、そこは適宜考えて下さい。

まとめ

まず、プッシュ通知をおくる、となったときには

  • 重要じゃない(≒ アプリの機能と関係のない)通知を送ろうとしてないか?
  • プッシュ通知頻度は適正か?

だけでなく、

  • 複数端末にプッシュした際に、プッシュの消去が同期されるべきか、否か?

という観点を持ちましょう。

プッシュの消去を同期したかったら Device Group Messaging を使いましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away