タイトルが長いw
シナリオ
- Xamarin.Forms 製のアプリのとある画面(Page)から、Androidの通知領域(ステータスバー)に通知を表示させる
- その通知がタップされたら、新しい画面(Page)を開く(など、任意の Xamarin.Forms 依存の処理を行う)
方法
だらだら説明しようと思ったけど、面倒になったので Github にサンプルを上げました。
ポイント
通知はネイティブ固有の機能です
Android の通知は Intent などネイティブの概念と深く結びついており、Forms 側で共通化することは不可能(うまく隠蔽したライブラリはあるかも、ご存じの方教えてください)、つまりネイティブ側に処理をさせる必要がある。
その為に、このサンプルでは MessagingCenter
を使っている。ここは DI でやってもよい。
通知を表示するには?
この辺。
を参考にさせてもらったけど、通知関連は Android OS のバージョンアップで仕様/APIが変わりやすいので要注意。
通知がタップされた時の処理は?
通知がタップされた時に送信される Intent
を設定しておく。
ここでは、 このアプリのエントリポイントである MainActivity
を再度呼び出させるようにしている。
この時、 SetFlags(ActivityFlags.SingleTop)
を忘れないこと。
これを付けないと、通知をタップした時に、画面(MainAcitivity
) がもう一つ起動してしまう。
このあたりで戦うには、次のようなネイティブの知識が必要になる。
- タスクとバックスタック / Android Developers
- Y.A.M の 雑記帳: Android launchMode の違い
- launchModeをsingleTopにしておくと何が起こるか - woshidan's blog
- IntentのCategoryとExtraとFlagの一覧表を作ってみたよ - hyoromoのブログ
通知から呼び出された事をどうやって判別する?
まず、通知がタップされた時、アプリ(正確にはAcitivity)が 必ずしも起動しているとは限らない事 を理解しなければならない。
表題の答えは、SingleTop
を使っている場合、
- アプリが起動中の場合、タップが通知された事は
MainActivity.OnNewIntent
が呼び出されることで判る - アプリが起動してない場合、タップされるとアプリが起動し、通知からの起動かどうかは
MainActivity.OnCreate
でIntent.Data
にデータが入っていることで判る ※if (Intent?.Data != null) {
とか。
の2つとなる。こちらも例えば次のようなネイティブの知識が必要。
通知をネイティブ側で検知できたら、次はどうすれば?
アプリ起動中に OnNewIntent
で検知した場合は、OnCreate
で生成された Xamarin.Forms 側の App
クラスにアクセスできるはず なので、さらに App
クラスに「現在のPageが取得できるような細工」をしておくことで、現在のページから PushAsync
などが使える。
通知タップでアプリが起動された場合は、前述の App
クラスに何らかのフラグを持たせ、それを用いて、Xamarin.Forms 側の起動時の挙動を変える。
起動時にナビゲーションの奥の方の画面を開くような要件は実装が面倒だが、 Prism.Forms の DeepLinking を使うと楽になれるかもしれない。
実際の動き
github のサンプルを動かすと、下図のようになります。
アプリ起動中に通知をタップした場合
アプリが起動してない状態で、通知をタップした場合
まとめ
結果的にだらだら説明してしまった気がするけどまとめ。
- 通知はネイティブ固有機能だから Xamarin.Forms "だけ" ではムリー
- 通知のタップで自アプリを反応させるには
ActivityFlags.SingleTop
を使うとよいぞ - アプリが起動してない時に通知をタップされた時の仕様を考える必要があるぞ
次は iOS・・・。