2016年2月28日日曜日

conent_available を true にすると foreground のときしか onMessageReceived() が呼ばれない

GcmListenerService では、特定の条件の場合 onMessageReceived() を呼ばずに自分で Notification を出すような処理になっています。

この条件が Google Play Services のバージョンによって異なり、7.8.0 から 8.4.0 に変更したときにはまったので調べた結果をまとめておきます。
(調べたのは 7.8.0 と 8.4.0 で、この間の他のバージョンは調べていません。)

7.8.0



7.8.0 では、送信する JSON に "notification" payload があり、その中の "icon" の値が null じゃない場合は onMessageReceived() が呼ばれずに GcmListenerService が Notification を出します。このときの Notification には "notification" payload で指定された "title" や "body" が使われます。"title" の値が空のときはアプリ名が利用されます。

notification payload の形式については https://developers.google.com/cloud-messaging/http-server-ref#notification-payload-support 参照

つまり
"notification" の "icon" == null → onMessageReceived()
"notification" の "icon" != null → GcmListenerService が Notification 発行


8.4.0



8.4.0 では条件が大きく変わります。
"content_available" が false (指定がない場合も false)かつ "notification" の "icon" == null の場合 onMessageReceived() が呼ばれます。そうでない場合、アプリが foreground にあれば onMessageReceived() が呼ばれ、background なら GcmListenerService が Notification を出します。

つまり
"content_available" == false && "notification" の "icon" == null → onMessageReceived()
"content_available" == true || "notification" の "icon" != null →
  アプリが foreground → onMessageReceived()
  アプリが background → GcmListenerService が Notification 発行

"content_available" を true にしていると、7.8.0 から 8.4.0 に変更したときに今まで background でも onMessageReceived() が呼ばれていたのに呼ばれなくなります。全然ドキュメントにも書いてないしはまりました。。。


7.8.0 のコード

GcmListenerService private void zzt(Bundle var1) { var1.remove("message_type"); var1.remove("android.support.content.wakelockid"); if(zza.zzu(var1)) { zza.zzay(this).zzv(var1); // "notification" のデータを使って Notification を発行している } else { String var2 = var1.getString("from"); var1.remove("from"); this.onMessageReceived(var2, var1); } } zza static boolean zzu(Bundle var0) { return zzb(var0, "gcm.n.icon") != null; } "gcm.n.icon" は "notification" payload の "icon" に対応している。


8.4.0 のコード

GcmListenerService private void zzq(Intent var1) { Bundle var2 = var1.getExtras(); var2.remove("message_type"); var2.remove("android.support.content.wakelockid"); if(zzb.zzy(var2)) { if(!zzb.zzaI(this)) { // 同じプロセスの Activity が foreground かチェック、foreground じゃない場合 if の中に入る zzb.zzc(this, this.getClass()).zzA(var2); // "notification" のデータを使って Notification を発行している return; } if(zzx(var1.getExtras())) { zza.zzh(this, var1); } zzb.zzz(var2); } String var3 = var2.getString("from"); var2.remove("from"); zzw(var2); this.onMessageReceived(var3, var2); } zzb static boolean zzy(Bundle var0) { return "1".equals(zze(var0, "gcm.n.e")) || zze(var0, "gcm.n.icon") != null; } "gcm.n.e" は "content_available" に対応している。 "gcm.n.icon" は "notification" payload の "icon" に対応している。

zzb static boolean zzaI(Context var0) { KeyguardManager var1 = (KeyguardManager)var0.getSystemService("keyguard"); if(var1.inKeyguardRestrictedInputMode()) { return false; } else { int var2 = Process.myPid(); ActivityManager var3 = (ActivityManager)var0.getSystemService("activity"); List var4 = var3.getRunningAppProcesses(); if(var4 != null) { Iterator var5 = var4.iterator(); while(var5.hasNext()) { RunningAppProcessInfo var6 = (RunningAppProcessInfo)var5.next(); if(var6.pid == var2) { return var6.importance == 100; } } } return false; } }


0 件のコメント:

コメントを投稿