プッシュ通知ってめんどいですよね。 ということで Visual Studio Mobile Center の Push を試してみようと思います。Android, iOS, UWP あたりに対応してるらしいですが、とりあえず私の好きな Xamarin.Forms を使って Android に対して対応してみようと思います。
VSMS にプロジェクトを作成
これがないと始まらないのでさくっと作りましょう。
Android で Xamarin でさくっとね。
設定とか
Push の項目を見てみると Firebase Console でアプリ作ってねっていう感じの説明があるので Firebase Console に移動します。
https://console.firebase.google.com/?hl=ja
とりあえずプロジェクトがないと始まらないみたいなので Firebase Console でプロジェクトを作成しましょう。
作成後、左側のメニューから 成長 のところにある Notifications を選びます。そこから Android のアプリを作るボタンがあるのでさくっと作っちゃいましょう。
Android パッケージ名は、これから作るアプリのパッケージと合わせておきます。ここでは jp.okazuki.pushlab.android
にしました。
次の画面で google-services.json をダウンロードするように言われるので、これをダウンロードしておきます。あとで使うので。
そして、Mobile Center と Firebase の間をつなぐ設定をします。これは、Firebase Console の左のメニューの上の方にある歯車マークを押してプロジェクトの設定を選択します。そして、画面上部のタブにあるクラウドメッセージングを選択して、そこにあるサーバーキーというものを使います。
サーバーキーをゲットしたら、Mobile Center の画面に戻って Next を選択します。するとサーバーキーを入れる画面になるので、先ほど Firebase Console でゲットしたサーバーキーを入力します。Done を押すと完了です。
プッシュ通知が送れそうな雰囲気の画面になります。
アプリの作成
では、サーバー側の構成が終わったのでクライアント側を作っていきます。 Xamarin.Forms のアプリケーションをサクッと作りましょう。
ここでは、PushLabApp という名前で作りました。
作ったら、ソリューションのNuGetパッケージの管理で Microsoft.Azure.Mobile.Push パッケージを PCL, Android, iOS, UWP のプロジェクトに追加しましょう。
次に、先ほどダウンロードした google-services.json を Android プロジェクトに追加します。そしてビルドアクションを GoogleServicesJson にします。
Tips
GoogleServicesJson のビルドアクションが出ない場合は Visual Studio を再起動してみましょう。こういうの多いですよね。
アプリの作成続き
Android プロジェクトのプロパティで Android マニフェストで、パッケージ名に先ほど作成した Firebase Console のアプリで指定したパッケージ名と同じものを設定しましょう。
App.xaml.cs の OnStart メソッドに Push を有効化させるコードを書きます。
protected override void OnStart() { MobileCenter.Start("android=a58a4c6f-1093-4bfd-a47b-2b3d877a56c6;" + "uwp={Your UWP App secret here};" + "ios={Your iOS App secret here}", typeof(Push)); }
uwp や ios は今後有効化させるとして置いときましょう。
AndroidManifest.xml の application タグの下に2つほど receiver タグを追加します。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-sdk android:minSdkVersion="15" /> <application android:label="PushLabApp.Android"> <!-- ここから --> <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" /> <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> <category android:name="${applicationId}" /> </intent-filter> </receiver> <!-- ここまで --> </application> </manifest>
${applicationId} あたりは何か固定値入れるのかなと思わせつつそのままでいいみたいですね。
ビルドして動作確認
では、ビルドしましょう!ちなみにビルドエラー(java.exeが2を返すみたいな雰囲気のメッセージ)が出たら Android プロジェクトのプロパティの Android オプションにある Multi-Dex を有効にするをチェック入れましょう。
んで、実行してホームボタンを押してアプリをバックグラウンドに回します。
Send notification を押します。
あとは、適当に項目を埋めて
送信対象者を選びます。
最後にプレビューが出るので Send notification を押しましょう。
送信するとこんな感じでリスト形式で表示されます。
アプリ側には、このような感じで通知がきます。(フォアグランドにアプリがあると来ないので気を付けてね)
フォアグランドにあるときはどうするの?
Push きても通知が出るのがバックグラウンドだけだったらフォアグランドにあるときはどうしよう?って感じですよね。 その時は、Push.PushNotificationReceived イベントが発火します。ということなので、こんな感じにすればいいじゃん?ってことになりますよね。
protected override void OnStart() { Debug.WriteLine("App.OnStart() called"); MobileCenter.Start("android=a58a4c6f-1093-4bfd-a47b-2b3d877a56c6;" + "uwp={Your UWP App secret here};" + "ios={Your iOS App secret here}", typeof(Push)); Push.PushNotificationReceived += this.Push_PushNotificationReceived; } private async void Push_PushNotificationReceived(object sender, PushNotificationReceivedEventArgs e) { Debug.WriteLine( string.Join("\n", e.CustomData?.Select(x => $"{x.Key}, {x.Value}") ?? new[] { "" })); if (string.IsNullOrEmpty(e.Message)) { return; } await this.MainPage.DisplayAlert(e.Title, e.Message, "OK"); } protected override void OnSleep() { Push.PushNotificationReceived -= this.Push_PushNotificationReceived; }
ちなみに、Send notification の時に Custom data が設定できる画面がありましたが、これはイベント引数の CustomData プロパティにディクショナリで格納されています。とりあえずあったら適当にデバッグコンソールに出しておきましょう。
あと、これは個人的に解せぬ動きなんですが、この PushNotificationReceived イベントはバックグラウンドにアプリがあるときに通知がきて、それをタップしたときにも呼ばれるんですよね。その時は、何故か CustomData は値が入っていて Title, Message が null みたいになってます。ちょっとびっくりした。
よくわからないんだけどこれも必要みたい
なんか、Android アプリ開発にそんなに明るくないせいか不勉強のせいかはじめて OnNewIntent なるメソッドを見ました。 なんだか Activity の launchMode が singleTop, singleInstance, singleTask の時は OnNewIntent メソッドを以下のようにしないといけないみたいです。ふーん。
protected override void OnNewIntent(Android.Content.Intent intent) { base.OnNewIntent(intent); Push.CheckLaunchedFromNotification(this, intent); }
あとは試してないんだけど
有効無効を切り替えれるらしい。
Push.SetEnabledAsync(false); // 無効 Push.SetEnabledAsync(true); // 有効
配信先の制御
今まで無差別に全員に対して Push 通知を送り込んできました。
ここらへんは、ある程度絞ることができるようになっています。まずは、MobileCenter.getInstallId();
でとってこれるインストールID指定で送る方法です。20人まで一気に遅れるみたいですね。当選者発表みたいなのとかに使うんだろうか?
あとは Push の下にある Audiences でオーディエンスというものを作っておくとユーザーを条件つけて絞り込めるという機能もあります。
ドキュメント上は Custom Properties を使ってきめ細やかな設定ができるということも書いてありますが UI 上設定の仕方がわかりませんでした。REST API を使ってやってる人がいたので、もしかしたらまだ UI が出来てないんですかね?
まとめ
ということで、割と簡単にプッシュ通知できるみたいですね。 そして興味を持った人はドキュメントを見てみましょう!
あと、Mobile Center 自体に興味を持った人で、がんがん使いこなしてみたいって人は、私はまだ見てないけど REST API も公開されてるようなので、それを使うと楽しいことが出来そうな気がしてます。
https://docs.mobile.azure.com/api/
ちなみに、こういう便利系サービス割と好きです。今回 Push をやるにあたって Firebase Console を見たけどこいつも色々出来そうですね。というか Push だけに限ると Firebase そのまま使ってもいいんじゃ?って思ったんですがどうでしょう。Firebase についてはこの資料好きです。