おでんはじめました。

required ちくわぶ and 巾着,optional はんぺん.

.NET MAUI でプッシュ通知を実装する(Android 編)

表題の通り .NET MAUI でプッシュ通知を実装してみます。

(案の定というか).NET MAUI でのプッシュ通知に関するドキュメントが見つからないということもあり、Xamarin.Forms のドキュメントを参考にしながらやってみます。

learn.microsoft.com

やるべきこととしては以下のようになります。

1. Firebase プロジェクトを作成し、Firebase Cloud Messaging を有効にする

Firebase プロジェクトを作成します。ここでのプロジェクト名は任意で構いません。

Android パッケージ名を入力してアプリ登録をおこないます。

ここで入力した Android パッケージ名は .NET MAUI でも使用しますのでメモしておきます(後述)。

google-services.json をダウンロードします。このファイルは .NET MAUI で使用します(後述)。

以降は Java での実装なのでここでの作業はこれで終わりです。

プロジェクトの先頭に戻り、「プロジェクトの設定」(「プロジェクトの概要」の隣にあるタイヤアイコン)→「Cloud Messageing」と進みます。

「Cloud Messaging(レガシー)」の右側にある三点ボタンをクリックして、Cloud Messaging を有効にします。

(リロードすると Cloud Messaging が有効になるので)「サーバーキーを追加」をクリックします。ここでのサーバーキーは Notification Hubs の設定で使用しますのでメモしておきます。

2. 通知ハブ(Notification Hubs)を作成する

Azure ポータルから Notification Hub を検索して作成します。

ハブ名は .NET MAUI で使用しますのでメモしておきます。

Notification Hub の「Access Policies」から「DefaultListenSharedAccessSignature」(Permission=Listen)の値をメモしておきます。この後 .NET MAUI のプロジェクトで使用します。

3. FCM の設定を通知ハブ用に構成する

Notification Hubs で「Google (GCM/FCM)」 を選択します。

先ほど Firebase Console でメモしておいた API キーをペーストして保存します。

4. Visual Studio プロジェクトを作成し、NuGet パッケージを追加する

Visual Studio 2022 を起動して「新しいプロジェクトの作成」を選択します。

"maui" で検索するなどして、「.NET MAUI アプリ」を作成します。

プロジェクトのプロパティを選択して、「Andoird >マニフェスト」を選択します。

Firebase Console でメモしておいた「アプリケーションパッケージ名」をペーストします。アプリケーション名は任意です。

ここで設定した「アプリケーションパッケージ名」は Platforms/Android/AndroidManifest.xml へ反映されますが、このファイルも同時にプロジェクトで開いていると反映されないケースがあるようです。

パッケージを二つインストールします。バージョンは 2022年10月28日時点のものです。

<PackageReference Include="Xamarin.Azure.NotificationHubs.Android" Version="1.1.4.1" />
<PackageReference Include="Xamarin.Firebase.Messaging" Version="123.0.8" />

Android の Framework のバージョンを 30 にしておきます。

5. Google Services JSON ファイルを追加する

Google Firebase Console からダウンロードした google-services.json ファイルをプロジェクト フォルダーにコピーします。

ソリューション エクスプローラーで google-services.json を選択して、プロパティでビルド アクションを GoogleServicesJson に設定します。

パッケージが正常にインストールされていないと GoogleServicesJson が選択できない場合があります。Visual Studio を再起動してプロジェクトを再度開くと表示されることもあります。

6. プロジェクトで Notification Hubs を設定する

<application> 要素の後ろに(前でも良いですが)、以下のステートメントを追加します。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>

プロジェクトで下記の Constants.cs クラスを作成します。プレースホルダーの値を実際の値に置き換えます。

ListenConnectionString は「Access Policies」の「DefaultListenSharedAccessSignature」で取得した値、NotificationHubName は Notification Hubs で作成したハブ名になります。

public static class Constants
{
    public const string ListenConnectionString = "<Listen connection string>";
    public const string NotificationHubName = "<hub name>";
}

下記の FirebaseService クラスを Platforms/Android フォルダに追加します。

OnNewToken メソッドはアプリの初回起動時に呼ばれます。ここで取得できるトークンをつかって Notification Hubs への登録をおこないます。

プッシュ通知を受信すると OnMessageReceived メソッドが呼ばれます。ここではアプリがバックグラウンドの状態の時のローカル通知用の設定(SendLocalNotification)と、アプリが起動している場合は MainPage へメッセージを追加する処理(SendMessageToMainPage)をおこなっています。

using Android.App;
using Android.Content;
using Android.Util;
using AndroidX.Core.App;
using Firebase.Messaging;
using WindowsAzure.Messaging;

namespace MauiPush.Platforms.Android;

[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
    public override void OnNewToken(string token)
    {
        SendRegistrationToServer(token);
    }

    public override void OnMessageReceived(RemoteMessage message)
    {
        base.OnMessageReceived(message);
        string messageBody = string.Empty;

        if (message.GetNotification() != null)
        {
            messageBody = message.GetNotification().Body;
        }
        else
        {
            messageBody = message.Data.Values.First();
        }

        // convert the incoming message to a local notification
        SendLocalNotification(messageBody);

        // send the incoming message directly to the MainPage
        SendMessageToMainPage(messageBody);
    }

    private void SendLocalNotification(string body)
    {
        try
        {
            var intent = new Intent(this, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.ClearTop);
            intent.PutExtra("message", body);

            var requestCode = new Random().Next();
            var pendingIntent = PendingIntent.GetActivity(this, requestCode, intent, PendingIntentFlags.OneShot);

            var notificationBuilder = new NotificationCompat.Builder(this, Constants.NotificationChannelId)
                .SetContentTitle("IDEQ Alert")
                .SetSmallIcon(Resource.Drawable.ic_launcher)
                .SetContentText(body)
                .SetAutoCancel(true)
                .SetShowWhen(false)
                .SetContentIntent(pendingIntent);

            var notificationManager = NotificationManagerCompat.From(this);
            notificationManager.Notify(0, notificationBuilder.Build());
        }
        catch (Exception e)
        {
            Log.Error("firebase", e.ToString());
        }
    }

    void SendMessageToMainPage(string body)
    {
        var appShell = App.Current.MainPage as AppShell;
        var mainPage = appShell.CurrentPage as MainPage;

        mainPage.AddMessage(body);

        Log.Debug("firebase", $"Message:{body}");
    }

    void SendRegistrationToServer(string token)
    {
        try
        {
            NotificationHub hub = new NotificationHub(Constants.NotificationHubName, Constants.ListenConnectionString, this);

            // register device with Azure Notification Hub using the token from FCM
            Registration registration = hub.Register(token, Constants.SubscriptionTags);

        }
        catch (Exception e)
        {
            Log.Error("firebase", $"Error registering device: {e.Message}");
        }
    }
}

プッシュ通知を受信した時に表示するコントロールMainPage.xaml に追加します。今回は <Button> の下に追加しました。

<StackLayout x:Name="messageDisplay"
             HorizontalOptions="Center"
             VerticalOptions="Start">
</StackLayout>

これで実装ができたので実機を使ってデバッグします。

7. Azure Portal からテスト通知を送信する

アプリの通知の受信をテストするには、Azure Portal の「テスト送信(Test Send)」オプションを使用します。 プラットフォームで「Android」を選択して「Send」をクリックします。

Androidバイスが正常に登録されていれば、送信結果に登録された Registration Id が出力されます。

アプリが起動されていればプッシュ通知を受信する都度メッセージが追加されます。

アプリがバックグラウンドにいる場合はローカル通知で受信します。

次回は .NET MAUI の iOS でのプッシュ通知をやってみます。