Android5.0 LollipopではiOSさながらにロックスクリーンに通知を表示することができるようになりました。
しかし、Notificationに入れるContentIntentでChromeを呼び出すようなIntentを渡したところ、ロック解除中は通知タップで普通にChromeを起動しIntentに含んだURLのサイトを表示できたものの、ロック画面の通知をタップした時は何も起こらず、困ったのでメモしておきます。
実現したいこと
普通に通知を送って自分のアプリ内のWebViewではなく好きなブラウザでURLのページを表示して欲しいです。
NexusだとChromeしか入ってないので、Chromeを想定してました。
追加するIntentはこんな感じです。
// httpなスキーマのACTION_VIEWの暗黙intentを渡してます。
Uri uri = Uri.parse("http://example.co.jp");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
PendingIntent pi = PendingIntent.getActivity(context, NOTIFICATION_ID, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 普通にbuilderで渡したり。。
new NotificationCompat.Builder(context).setIcon(
...
).setContentIntent(pi).build();
困ったこと
ロック解除中、というかステータスバーの通知をタップすると普通にChromeが呼ばれました。
しかし、ロックスクリーンの通知をタップする時は、挙動が違います。
ユーザ視点では何もおきません。
logcatを見ると
E/ChromeLauncherActivity(): Ignoring intent: Intent { act=android.intent.action.VIEW dat=http://www.google.com/ flg=0x10000000 cmp=com.android.chrome/com.google.android.apps.chrome.Main }
のように表示されていました。
明示的Intentに変更してもダメです。
調べると何やらNFC関連のissueとして上がっているようです。
Issue 455126: ChromeLauncherActivity ignores intent as lock screen status (by NFC beam enabled)
LockScreen(画面はついてる)でNFC beamでintentをchromeに対して呼ぶとignoring intent
とか言われてしまいます。悲しいですね。
しかも仕様として特に対応はしてくれないようです。
まあ、ロック中なのにChrome経由で変なコードが実行されないように、ということなのでしょう。しょうがないですね。
回避策
上記のissueスレッドにも書かれていますが、ロックが解除されたら実行されればいいのです。
スレッドでは10秒後とかならlockが解除されたと判断できる、など書いてありますが別にもっと短くてもいいようです。
ということで自分はBroadcastReceiverを使っていたので、それを一回経由してからintentを送るようにしてみました。
もちろん、Serviceとかでも可能だと思います。
// 中身はそのまま、自分のアプリへの明示的intentにします。
Uri uri = Uri.parse("http://example.co.jp");
Intent intent = new Intent(con, MyReceiver.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setData(uri);
受け取るBroadcastReceiverでは、UIスレッドじゃない気がするので、今回はAlarmManagerで遅延させたintentを発行してもらいます。
ServiceとかならThreadを遅延実行させればいいかもしれません。
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Context con = context.getApplicationContext();
if ("myaction".equals(action)) {
...
} else if (Intent.ACTION_VIEW.equals(action)) {
// 今回はとりあえず、ここでintentを作っていますが、中に入れたりしたほうがいいと思います。
Intent i = new Intent(Intent.ACTION_VIEW, intent.getData());
AlarmManager am = (AlarmManager) con.getSystemService(Context.ALARM_SERVICE);
// 500msの遅延を入れてintentを飛ばしてもらいます。これは何秒でもいいと思います
am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 500,
PendingIntent.getActivity(con, 0, i, 0));
}
}
}
こうすることで、きちんとchromeを起動することができました。
面倒ですが、しょうがないですね。。
ちなみに遅延は端末の処理速度に依存するかと思いますが、5-10msとかでも全然大丈夫でした。(手元の機種では1msはさすがにダメでした)
というか、ロックスクリーンの通知はタップした直後にintentが発行されず、ロック解除時に発行されるので、結局それをロック中かロック解除後か判別してハンドリングできていないChrome or Androidのバグな気がします。。