Firebase クラウド メッセージングによるリモート通知

このチュートリアルでは、Firebase Cloud Messaging を使用して Xamarin.Android アプリケーションにリモート通知 (プッシュ通知とも呼ばれます) を実装する方法について詳しく説明します。 Firebase Cloud Messaging (FCM) との通信に必要なさまざまなクラスを実装する方法を示し、FCM にアクセスするために Android マニフェストを構成する方法の例を示し、Firebase コンソールを使用したダウンストリーム メッセージングを示します。

FCM 通知の概要

このチュートリアルでは、FCMClient という基本的なアプリを作成して、FCM メッセージングの要点を説明します。 FCMClient は、Google Play 開発者サービスの存在を確認し、FCM から登録トークンを受け取り、Firebase コンソールから送信したリモート通知を表示し、トピック メッセージを登録します。

アプリのスクリーンショットの例

次のトピック領域について説明します。

  1. バックグラウンド通知

  2. トピック メッセージ

  3. フォアグラウンド通知

このチュートリアルでは、FCMClient に機能を段階的に追加し、デバイスまたはエミュレーターで実行して、FCM との対話方法について理解します。 ログを使用して FCM サーバーでライブ アプリ トランザクションを監視し、Firebase コンソール通知 GUI に入力した FCM メッセージから通知がどのように生成されるかを確認します。

要件

Firebase Cloud Messaging で送信できるさまざまな種類のメッセージについて理解しておくと役立ちます。 メッセージのペイロードによって、クライアント アプリがメッセージを受信して処理する方法が決まります。

このチュートリアルを進める前に、Google の FCM サーバーを使用するために必要な資格情報を取得する必要があります。このプロセスについては、「Firebase Cloud Messaging」を参照してください。 特に、このチュートリアルで示すコード例で使用する google-services.json ファイルをダウンロードする必要があります。 Firebase コンソールでプロジェクトをまだ作成していない場合は (または google-services.json ファイルをまだダウンロードしていない場合)、「Firebase Cloud Messaging」を参照してください。

サンプル アプリを実行するには、Firebase と互換性のある Android テスト デバイスまたはエミュレーターが必要です。 Firebase Cloud Messaging では、Android 4.0 以降で実行されているクライアントがサポートされており、これらのデバイスには Google Play ストア アプリもインストールされている必要があります (Google Play 開発者サービス 9.2.1 以降が必要です)。 Google Play ストア アプリがまだデバイスにインストールされていない場合は、Google Play Web サイトにアクセスしてダウンロードし、インストールしてください。 または、テスト デバイスではなく、Google Play 開発者サービスがインストールされた Android SDK エミュレーターを使用することもできます (Android SDK エミュレーターを使用している場合は、Google Play ストアをインストールする必要はありません)。

アプリ プロジェクトを開始する

まず、FCMClient という名前の新しい空の Xamarin.Android プロジェクトを作成します。 Xamarin.Android プロジェクトの作成に慣れていない場合は、「Hello, Android」を参照してください。 新しいアプリが作成されたら、次の手順で、パッケージ名を設定し、FCM との通信に使用される NuGet パッケージをいくつかインストールします。

パッケージ名を設定する

Firebase Cloud Messaging で、FCM 対応アプリのパッケージ名を指定しました。 このパッケージ名は、API キーに関連付けられているアプリケーション ID としても機能します。 このパッケージ名を使用するようにアプリを構成します。

  1. FCMClient プロジェクトのプロパティを開きます。

  2. [Android マニフェスト] ページで、パッケージ名を設定します。

次の例では、パッケージ名は com.xamarin.fcmexample に設定されています。

パッケージ名を設定する

Android マニフェストの更新中に、Internet アクセス許可が有効になっていることも確認します。

重要

このパッケージ名が Firebase コンソールに入力されたパッケージ名と "正確に" 一致しない場合、クライアント アプリは FCM から登録トークンを受け取ることができません。

Xamarin Google Play 開発者サービス Base パッケージを追加する

Firebase Cloud Messaging は Google Play 開発者サービスに依存するため、Xamarin Google Play 開発者サービス - Base NuGet パッケージを Xamarin.Android プロジェクトに追加する必要があります。 バージョン 29.0.0.2 以降が必要です。

  1. Visual Studio で、[参照] > [NuGet パッケージの管理...] の順に右クリックを使用して選択します。

  2. [参照] タブをクリックし、Xamarin.GooglePlayServices.Base を検索します。

  3. このパッケージを FCMClient プロジェクトにインストールします。

    Google Play 開発者サービス ベースをインストールする

NuGet のインストール中にエラーが発生した場合は、FCMClient プロジェクトを閉じてからもう一度開き、NuGet のインストールを再試行してください。

Xamarin.GooglePlayServices.Base をインストールすると、必要な依存関係もすべてインストールされます。 MainActivity.cs を編集し、次の using ステートメントを追加します。

using Android.Gms.Common;

このステートメントにより、Xamarin.GooglePlayServices.BaseGoogleApiAvailability クラスを FCMClient コードで使用できるようになります。 GoogleApiAvailability は、Google Play 開発者サービスの存在を確認するために使用されます。

Xamarin Firebase メッセージング パッケージを追加する

FCM からメッセージを受信するには、Xamarin Firebase - Messaging NuGet パッケージをアプリ プロジェクトに追加する必要があります。 このパッケージがないと、Android アプリケーションは FCM サーバーからメッセージを受信できません。

  1. Visual Studio で、[参照] > [NuGet パッケージの管理...] の順に右クリックを使用して選択します。

  2. Xamarin.Firebase.Messaging を検索します。

  3. このパッケージを FCMClient プロジェクトにインストールします。

    Xamarin Firebase メッセージングをインストールする

Xamarin.Firebase.Messaging をインストールすると、必要な依存関係もすべてインストールされます。

次に、MainActivity.cs を編集し、次の using ステートメントを追加します。

using Firebase.Messaging;
using Firebase.Iid;
using Android.Util;

最初の 2 つのステートメントでは、Xamarin.Firebase.Messaging NuGet パッケージの型を FCMClient コードで使用できるようにします。 Android.Util により、FMS でトランザクションを監視するために使用されるログ機能が追加されます。

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

次の手順では、google-services.json ファイルをプロジェクトのルート ディレクトリに追加します。

  1. google-services.json をプロジェクト フォルダーにコピーします。

  2. google-services.json をアプリ プロジェクトに追加します (ソリューション エクスプローラー[すべてのファイルを表示] をクリックし、google-services.json を右クリックして、[プロジェクトに含める] を選択します)。

  3. ソリューション エクスプローラー ウィンドウで、[google-services.json] を選択します。

  4. [プロパティ] ペインで、[ビルド アクション][GoogleServicesJson] に設定します。

    ビルド アクションを GoogleServicesJson に設定する

    Note

    GoogleServicesJson ビルド アクションが表示されない場合は、ソリューションを保存して閉じてから、もう一度開きます。

google-services.json がプロジェクトに追加され、GoogleServicesJson ビルド アクションが設定されている場合、ビルド プロセスによって、クライアント ID と API キーが抽出され、これらの資格情報が、obj/Debug/android/AndroidManifest.xml に存在する、マージ/生成された AndroidManifest.xml に追加されます。 このマージ プロセスでは、FCM サーバーへの接続に必要なアクセス許可とその他の FCM 要素が自動的に追加されます。

Google Play 開発者サービスを確認し、通知チャネルを作成する

Google では、Android アプリが Google Play 開発者サービス機能にアクセスする前に、Google Play 開発者サービス APK の存在を確認することを推奨しています (詳細については、「Google Play 開発者サービスをチェックする」を参照してください)。

アプリの UI の初期レイアウトが最初に作成されます。 Resources.layout.Main.axml を編集し、そのコンテンツを次の XML に置き換えます。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp">
    <TextView
        android:text=" "
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/msgText"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:padding="10dp" />
</LinearLayout>

この TextView は、Google Play 開発者サービスがインストールされているかどうかを示すメッセージを表示するために使用されます。 変更を Main.axml に保存します。

MainActivity.cs を編集し、次のインスタンス変数を MainActivity クラスに追加します。

public class MainActivity : AppCompatActivity
{
    static readonly string TAG = "MainActivity";

    internal static readonly string CHANNEL_ID = "my_notification_channel";
    internal static readonly int NOTIFICATION_ID = 100;

    TextView msgText;

変数 CHANNEL_IDNOTIFICATION_ID は、このチュートリアルの後半で MainActivity に追加される メソッド CreateNotificationChannel で使用されます。

次の例で OnCreate メソッドは、アプリが FCM サービスの使用を試みる前に、Google Play 開発者サービスが使用可能であることを確認します。 次のメソッドを MainActivity クラスに追加します:

public bool IsPlayServicesAvailable ()
{
    int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable (this);
    if (resultCode != ConnectionResult.Success)
    {
        if (GoogleApiAvailability.Instance.IsUserResolvableError (resultCode))
            msgText.Text = GoogleApiAvailability.Instance.GetErrorString (resultCode);
        else
        {
            msgText.Text = "This device is not supported";
            Finish ();
        }
        return false;
    }
    else
    {
        msgText.Text = "Google Play Services is available.";
        return true;
    }
}

このコードでは、Google Play 開発者サービス APK がインストールされているかどうかをデバイスで確認します。 インストールされていない場合は、Google Play ストアから APK をダウンロードするように (または、それをデバイスのシステム設定で有効にするように) ユーザーに指示するメッセージが TextBox に表示されます。

Android 8.0 (API レベル 26) 以降で実行されているアプリでは、通知を発行するための "通知チャネル" を作成する必要があります。 通知チャネルを作成する MainActivity クラスに次のメソッドを追加します (必要な場合)。

void CreateNotificationChannel()
{
    if (Build.VERSION.SdkInt < BuildVersionCodes.O)
    {
        // Notification channels are new in API 26 (and not a part of the
        // support library). There is no need to create a notification
        // channel on older versions of Android.
        return;
    }

    var channel = new NotificationChannel(CHANNEL_ID,
                                          "FCM Notifications",
                                          NotificationImportance.Default)
                  {

                      Description = "Firebase Cloud Messages appear in this channel"
                  };

    var notificationManager = (NotificationManager)GetSystemService(Android.Content.Context.NotificationService);
    notificationManager.CreateNotificationChannel(channel);
}

OnCreate メソッドを次のコードで置き換えます。

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);
    SetContentView (Resource.Layout.Main);
    msgText = FindViewById<TextView> (Resource.Id.msgText);

    IsPlayServicesAvailable ();

    CreateNotificationChannel();
}

IsPlayServicesAvailableOnCreate の終了時に呼び出されることで、アプリが起動するたびに Google Play 開発者サービス チェックが実行されます。 メソッド CreateNotificationChannel は、Android 8 以降を実行しているデバイスに通知チャネルが存在することを確認するために呼び出されます。 アプリに OnResume メソッドがある場合、そのアプリは、OnResume からも IsPlayServicesAvailable を呼び出す必要があります。 アプリを完全にリビルドして実行してください。 すべてが正しく構成されている場合は、次のスクリーンショットのような画面が表示されます。

アプリは、Google Play 開発者サービスが利用可能であることを示します

この結果が得られない場合は、Google Play 開発者サービス APK がデバイスにインストールされていることを確認します (詳細については、「Google Play 開発者サービスをセットアップする」を参照してください)。 また、前に説明したように、Xamarin.Google.Play.Services.Base パッケージが FCMClient プロジェクトに追加されていることを確認します。

インスタンス ID 受信者を追加する

次の手順では、Firebase 登録トークンの作成、ローテーション、更新を処理するために FirebaseInstanceIdService を拡張するサービスを追加します。 FCM がデバイスにメッセージを送信できるようにするには、FirebaseInstanceIdService サービスが必要です。 FirebaseInstanceIdService サービスがクライアント アプリに追加されると、そのアプリは FCM メッセージを自動的に受信し、アプリがバックグラウンドにある場合は必ず、それを通知として表示します。

Android マニフェストで受信者を宣言する

AndroidManifest.xml を編集し、次の <receiver> 要素を <application> セクションに挿入します。

<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>

この XML では、次の処理が行われます。

  • 各アプリ インスタンスの一意識別子を提供する FirebaseInstanceIdReceiver 実装を宣言します。 この受信者は、アクションの認証と承認も行います。

  • サービスを安全に開始するために使用される内部 FirebaseInstanceIdInternalReceiver 実装を宣言します。

  • アプリ ID は、プロジェクトに追加された google-services.json ファイルに格納されます。 Xamarin.Android Firebase バインドは、トークン ${applicationId} をアプリ ID に置き換えます。クライアント アプリでは、アプリ ID を提供するための追加コードは必要ありません。

FirebaseInstanceIdReceiver は、FirebaseInstanceId イベントと FirebaseMessaging イベントを受け取る WakefulBroadcastReceiver であり、それらを FirebaseInstanceIdService から派生したクラスに配信します。

Firebase インスタンス ID サービスを実装する

FCM にアプリケーションを登録する作業は、指定したカスタム FirebaseInstanceIdService サービスによって処理されます。 FirebaseInstanceIdService では次の手順が実行されます。

  1. インスタンス ID API を使用して、クライアント アプリが FCM とアプリ サーバーにアクセスすることを承認するセキュリティ トークンを生成します。 その代わりに、アプリは FCM から登録トークンを取得します。

  2. 登録トークンをアプリ サーバーに転送します (アプリ サーバーで必要な場合)。

MyFirebaseIIDService.cs という名前の新しいファイルを追加し、そのテンプレート コードを次のように置き換えます。

using System;
using Android.App;
using Firebase.Iid;
using Android.Util;

namespace FCMClient
{
    [Service]
    [IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
    public class MyFirebaseIIDService : FirebaseInstanceIdService
    {
        const string TAG = "MyFirebaseIIDService";
        public override void OnTokenRefresh()
        {
            var refreshedToken = FirebaseInstanceId.Instance.Token;
            Log.Debug(TAG, "Refreshed token: " + refreshedToken);
            SendRegistrationToServer(refreshedToken);
        }
        void SendRegistrationToServer(string token)
        {
            // Add custom implementation, as needed.
        }
    }
}

このサービスは、登録トークンが最初に作成または変更されたときに呼び出される OnTokenRefresh メソッドを実装します。 OnTokenRefresh が実行されると、それは FirebaseInstanceId.Instance.Token プロパティから最新のトークンを取得します (これは FCM によって非同期的に更新されます)。 この例では、更新されたトークンがログされ、出力ウィンドウに表示されます。

var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "Refreshed token: " + refreshedToken);

OnTokenRefresh は呼び出される頻度が低く、次の状況でトークンを更新するときに使用されます。

  • アプリがインストールまたはアンインストールされたとき。

  • ユーザーがアプリ データを削除したとき。

  • アプリがインスタンス ID を消去したとき。

  • トークンのセキュリティが侵害されたとき。

Google のインスタンス ID ドキュメントによると、FCM インスタンス ID サービスは、アプリにトークンを定期的 (通常は 6 か月ごと) に更新するよう要求します。

また、OnTokenRefreshSendRegistrationToAppServer を呼び出して、ユーザーの登録トークンと、アプリケーションによって管理されているサーバー側アカウント (存在する場合) を関連付けます。

void SendRegistrationToAppServer (string token)
{
    // Add custom implementation here as needed.
}

この実装はアプリ サーバーの設計に依存するため、この例では空のメソッド本体が提供されます。 アプリ サーバーで FCM 登録情報が必要な場合は、SendRegistrationToAppServer を変更して、ユーザーの FCM インスタンス ID トークンを、アプリによって管理されている任意のサーバー側アカウントに関連付けます (トークンはクライアント アプリに対して不透明であることに注意してください)。

トークンがアプリ サーバーに送信されるときは、そのトークンがサーバーに送信されたかどうかを示すブール値を SendRegistrationToAppServer で保持する必要があります。 このブール値が false の場合、SendRegistrationToAppServer は、トークンをアプリ サーバーに送信します。それ以外の場合、トークンは、以前の呼び出しで既にアプリ サーバーに送信されています。 場合によっては (この FCMClient 例など)、アプリ サーバーはトークンを必要としません。したがって、この例ではこのメソッドは必要ありません。

クライアント アプリ コードを実装する

受信側サービスが整ったので、これらのサービスを利用するためにクライアント アプリ コードを記述できます。 次のセクションでは、登録トークン (インスタンス ID トークンとも呼ばれます) をログするためのボタンが UI に追加され、通知からアプリが起動されたときに Intent 情報を表示するために MainActivity にさらにコードが追加されます。

アプリ画面に追加された [Log Token] (ログ トークン) ボタン

ログ トークン

この手順で追加されたコードは、デモンストレーションのみを目的としています。運用クライアント アプリでは、登録トークンをログする必要はありません。 Resources/layout/Main.axml を編集し、TextView 要素の直後に次の Button 宣言を追加します。

<Button
  android:id="@+id/logTokenButton"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:text="Log Token" />

`MakeConstAsync` メソッドの末尾に次のコードを追加します。

var logTokenButton = FindViewById<Button>(Resource.Id.logTokenButton);
logTokenButton.Click += delegate {
    Log.Debug(TAG, "InstanceID token: " + FirebaseInstanceId.Instance.Token);
};

このコードは、[ログ トークン] ボタンがタップされたときに、現在のトークンを出力ウィンドウにログします。

通知の意図を処理する

ユーザーが FCMClient から発行された通知をタップすると、その通知メッセージに付随するすべてのデータが Intent エクストラで使用できるようになります。 MainActivity.cs を編集し、次のコードを OnCreate メソッドの先頭に追加します (IsPlayServicesAvailable への呼び出しの前)。

if (Intent.Extras != null)
{
    foreach (var key in Intent.Extras.KeySet())
    {
        var value = Intent.Extras.GetString(key);
        Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
    }
}

ユーザーが通知メッセージをタップすると、アプリのランチャー Intent が起動されるため、このコードでは、Intent 内の付随するデータが出力ウィンドウにログされます。 別 の Intent を起動する必要がある場合は、通知メッセージの click_action フィールドをその Intent に設定する必要があります (ランチャー Intent は、click_action が指定されていない場合に使用されます)。

バックグラウンド通知

FCMClient アプリをビルドして実行します。 [ログ トークン] ボタンが表示されます。

[Log Token] (ログ トークン) ボタンが表示されます

[ログ トークン] ボタンをタップします。 次のようなメッセージが IDE 出力ウィンドウに表示されます。

出力ウィンドウに表示されるインスタンス ID トークン

トークンでラベル付けされた長い文字列は、Firebase コンソールに貼り付けるインスタンス ID トークンです。この文字列を選択してクリップボードにコピーします。 インスタンス ID トークンが表示されない場合は、次の行を OnCreate メソッドの上部に追加して、google-services.json が正しく解析されたことを確認します。

Log.Debug(TAG, "google app id: " + GetString(Resource.String.google_app_id));

出力ウィンドウにログされる google_app_id 値は、google-services.json に記録されている mobilesdk_app_id 値と一致する必要があります。 Resource.String.google_app_id は、google-services.json を処理するときに msbuild によって生成されます。

メッセージの送信

Firebase コンソールにサインインし、プロジェクトを選択し、[通知] をクリックして、[最初のメッセージの送信] をクリックします。

[Send Your First Message] (最初のメッセージの送信) ボタン

[メッセージの作成] ページで、メッセージ テキストを入力し、[単一デバイス] を選択します。 IDE 出力ウィンドウからインスタンス ID トークンをコピーし、Firebase コンソールの [FCM 登録トークン] フィールドに貼り付けます。

メッセージの作成ダイアログ

Android デバイス (またはエミュレーター) で、Android の [概要] ボタンをタップし、ホーム画面にタッチして、アプリをバックグラウンドにします。 デバイスの準備ができたら、Firebase コンソールで [メッセージの送信] をクリックします。

[Send message] (メッセージの送信) ボタン

[メッセージの確認] ダイアログが表示されたら、[送信] をクリックします。 通知アイコンは、デバイス (またはエミュレーター) の通知領域に表示されます。

通知アイコンが表示されます

通知アイコンを開いてメッセージを表示します。 通知メッセージは、Firebase コンソールの[メッセージ テキスト] フィールドに入力されたものと完全に同じである必要があります。

通知メッセージがデバイスに表示されます

通知アイコンをタップして FCMClient アプリを起動します。 FCMClient に送信される Intent エクストラは、IDE 出力ウィンドウに一覧表示されます。

キー、メッセージ ID、および折りたたみキーからの意図の追加リスト

この例では、from キーは、アプリの Firebase プロジェクト番号 (この例では 41590732) に設定され、collapse_key は、そのパッケージ名 (com.xamarin.fcmexample) に設定されます。 メッセージが表示されない場合は、デバイス (またはエミュレーター) で FCMClient アプリを削除して、上記の手順を繰り返してください。

Note

アプリを強制的に閉じると、FCM は通知の配信を停止します。 Android では、停止したアプリケーションのコンポーネントが、バックグラウンド サービス ブロードキャストによって誤って、または不必要に起動されないようになっています (この動作の詳細については、「停止したアプリでの起動コントロール」を参照してください)。このため、アプリを実行するたびに手動でアンインストールし、デバッグ セッションから停止する必要があります。これにより、FCM では、メッセージを受信し続けるために新しいトークンが生成されます。

カスタムの既定の通知アイコンを追加する

前の例では、通知アイコンがアプリケーション アイコンに設定されています。 次の XML により、通知用のカスタムの既定のアイコンが構成されます。 Android では、通知アイコンが明示的に設定されていないすべての通知メッセージに対して、このカスタムの既定のアイコンが表示されます。

カスタムの既定の通知アイコンを追加するには、Resources/drawable ディレクトリにアイコンを追加し、AndroidManifest.xml を編集して、<application> セクションに次の <meta-data> 要素を挿入します。

<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />

この例では、Resources/drawable/ic_stat_ic_notification.png にある通知アイコンが、カスタムの既定の通知アイコンとして使用されます。 カスタムの既定のアイコンが AndroidManifest.xml で構成されておらず、通知ペイロードにアイコンが設定されていない場合、Android ではアプリケーション アイコンが通知アイコンとして使用されます (上記の通知アイコンのスクリーンショットを参照)。

トピック メッセージを処理する

これまでに記述されたコードは、登録トークンを処理し、リモート通知機能をアプリに追加します。 次の例では、トピック メッセージをリッスンし、それをリモート通知としてユーザーに転送するコードを追加します。 トピック メッセージは、特定のトピックを登録する 1 つ以上のデバイスに送信される FCM メッセージです。 トピック メッセージの詳細については、トピック メッセージングに関するページを参照してください。

トピックのサブスクライブ

Resources/layout/Main.axml を編集し、前の Button 要素の直後に次の Button 宣言を追加します。

<Button
  android:id="@+id/subscribeButton"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:layout_marginTop="20dp"
  android:text="Subscribe to Notifications" />

この XML は、[通知を登録] ボタンをレイアウトに追加します。 MainActivity.cs を編集し、次のコードを OnCreate メソッドの末尾に追加します。

var subscribeButton = FindViewById<Button>(Resource.Id.subscribeButton);
subscribeButton.Click += delegate {
    FirebaseMessaging.Instance.SubscribeToTopic("news");
    Log.Debug(TAG, "Subscribed to remote notifications");
};

このコードは、レイアウト内の [通知を登録] ボタンを見つけ、FirebaseMessaging.Instance.SubscribeToTopic を呼び出すコードにそのクリック ハンドラーを割り当て、登録されたトピックである "ニュース" を渡します。 ユーザーが [登録] ボタンをタップすると、アプリによって "ニュース" トピックが登録されます。 次のセクションでは、Firebase コンソール通知 GUI から "ニュース" トピック メッセージが送信されます。

トピック メッセージを送信する

アプリをアンインストールし、リビルドして、もう一度実行します。 [通知を登録] ボタンをクリックします。

[通知] ボタンに登録する

アプリによって正常に登録されている場合は、IDE 出力ウィンドウにトピックの同期が成功したことが表示されます。

トピックの同期に成功したメッセージが出力ウィンドウに表示される

トピック メッセージを送信するには、次の手順に従います。

  1. Firebase コンソールで、[新しいメッセージ] をクリックします。

  2. [メッセージの作成] ページで、メッセージ テキストを入力し、[トピック] を選択します。

  3. [トピック] プルダウン メニューで、組み込みのトピック "ニュース" を選択します。

    ニュース トピックを選択する

  4. Android デバイス (またはエミュレーター) で、Android の [概要] ボタンをタップし、ホーム画面にタッチして、アプリをバックグラウンドにします。

  5. デバイスの準備ができたら、Firebase コンソールで [メッセージの送信] をクリックします。

  6. IDE 出力ウィンドウを確認して、ログ出力に /topics/news を表示します。

    /topic/news からのメッセージが表示されます

このメッセージが出力ウィンドウに表示されると、Android デバイスの通知領域にも通知アイコンが表示されます。 通知アイコンを開いて、トピック メッセージを表示します。

トピック メッセージが通知として表示されます

メッセージが表示されない場合は、デバイス (またはエミュレーター) で FCMClient アプリを削除して、上記の手順を繰り返してください。

フォアグラウンド通知

フォアグラウンド アプリで通知を受信するには、FirebaseMessagingService を実装する必要があります。 このサービスは、データ ペイロードを受信したり、アップストリーム メッセージを送信したりする際にも必要です。 次の例は、FirebaseMessagingService を拡張するサービスを実装する方法を示しています。結果として得られるアプリは、フォアグラウンドで実行されている間にリモート通知を処理できます。

FirebaseMessagingService を実装する

FirebaseMessagingService サービスは、Firebase からのメッセージの受信と処理を担当します。 各アプリがこの型をサブクラス化し、OnMessageReceived をオーバーライドして、受信メッセージを処理する必要があります。 アプリがフォアグラウンドにある場合、OnMessageReceived コールバックは常にメッセージを処理します。

Note

アプリには、受信した Firebase Cloud メッセージを処理する時間が 10 秒しかありません。 これよりも時間がかかる作業は、Android ジョブ スケジューラFirebase ジョブ ディスパッチャーなどのライブラリを使用して、バックグラウンドで実行されるようにスケジュールする必要があります。

MyFirebaseMessagingService.cs という名前の新しいファイルを追加し、そのテンプレート コードを次のように置き換えます。

using System;
using Android.App;
using Android.Content;
using Android.Media;
using Android.Util;
using Firebase.Messaging;

namespace FCMClient
{
    [Service]
    [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
    public class MyFirebaseMessagingService : FirebaseMessagingService
    {
        const string TAG = "MyFirebaseMsgService";
        public override void OnMessageReceived(RemoteMessage message)
        {
            Log.Debug(TAG, "From: " + message.From);
            Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
        }
    }
}

新しい FCM メッセージが MyFirebaseMessagingService に送信されるように、MESSAGING_EVENT 意図フィルターを宣言する必要があることに注意してください。

[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]

クライアント アプリは FCM からメッセージを受信すると、OnMessageReceived は、GetNotification メソッドを呼び出すことで、渡された RemoteMessage オブジェクトからメッセージ コンテンツを抽出します。 次に、IDE 出力ウィンドウで表示できるように、メッセージ コンテンツがログされます。

var body = message.GetNotification().Body;
Log.Debug(TAG, "Notification Message Body: " + body);

Note

FirebaseMessagingService でブレークポイントを設定すると、FCM がメッセージを配信する方法が原因で、デバッグ セッションでこれらのブレークポイントにヒットする場合とヒットしない場合があります。

別のメッセージを送信する

アプリをアンインストールし、リビルドして、もう一度実行し、次の手順に従って別のメッセージを送信します。

  1. Firebase コンソールで、[新しいメッセージ] をクリックします。

  2. [メッセージの作成] ページで、メッセージ テキストを入力し、[単一デバイス] を選択します。

  3. IDE 出力ウィンドウからトークン文字列をコピーし、以前と同様に Firebase コンソールの [FCM 登録トークン] フィールドに貼り付けます。

  4. アプリがフォアグラウンドで実行されていることを確認し、Firebase コンソールで [メッセージの送信] をクリックします。

    コンソールから別のメッセージを送信する

  5. [メッセージの確認] ダイアログが表示されたら、[送信] をクリックします。

  6. 受信メッセージは IDE 出力ウィンドウにログされます。

    出力ウィンドウに出力されるメッセージ本文

ローカル通知送信者を追加する

この残りの例では、受信 FCM メッセージは、アプリがフォアグラウンドで実行されている間に起動されるローカル通知に変換されます。 MyFirebaseMessageService.cs を編集し、次の using ステートメントを追加します。

using FCMClient;
using System.Collections.Generic;

次のメソッドを MyFirebaseMessagingService に追加します。

void SendNotification(string messageBody, IDictionary<string, string> data)
{
    var intent = new Intent(this, typeof(MainActivity));
    intent.AddFlags(ActivityFlags.ClearTop);
    foreach (var key in data.Keys)
    {
        intent.PutExtra(key, data[key]);
    }

    var pendingIntent = PendingIntent.GetActivity(this,
                                                  MainActivity.NOTIFICATION_ID,
                                                  intent,
                                                  PendingIntentFlags.OneShot);

    var notificationBuilder = new  NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
                              .SetSmallIcon(Resource.Drawable.ic_stat_ic_notification)
                              .SetContentTitle("FCM Message")
                              .SetContentText(messageBody)
                              .SetAutoCancel(true)
                              .SetContentIntent(pendingIntent);

    var notificationManager = NotificationManagerCompat.From(this);
    notificationManager.Notify(MainActivity.NOTIFICATION_ID, notificationBuilder.Build());
}

この通知をバックグラウンド通知と区別するために、このコードにより、アプリケーション アイコンと異なるアイコンで通知がマークされます。 ファイル ic_stat_ic_notification.pngResources/drawable に追加し、それを FCMClient プロジェクトに含めます。

SendNotification メソッドでは、NotificationCompat.Builder を使用して通知が作成され、NotificationManagerCompat を使用して通知が起動されます。 通知には、PendingIntent が保持されています。これにより、ユーザーはアプリを開き、messageBody に渡された文字列のコンテンツを表示できます。 NotificationCompat.Builder の詳細については、ローカル通知に関するページを参照してください。

OnMessageReceived メソッドの末尾で SendNotification メソッドを呼び出します。

public override void OnMessageReceived(RemoteMessage message)
{
    Log.Debug(TAG, "From: " + message.From);

    var body = message.GetNotification().Body;
    Log.Debug(TAG, "Notification Message Body: " + body);
    SendNotification(body, message.Data);
}

これらの変更の結果、アプリがフォアグラウンドにある間に通知が受信されるたびに SendNotification が実行され、通知が通知領域に表示されます。

アプリがバックグラウンドにある場合は、メッセージのペイロードによってメッセージの処理方法が決まります。

  • 通知システム トレイにメッセージが送信されます。 そこにローカル通知が表示されます。 ユーザーが通知をタップすると、アプリが起動します。
  • データOnMessageReceived によってメッセージが処理されます。
  • 両方 – システム トレイに、通知とデータ ペイロードの両方を持つメッセージが配信されます。 アプリが起動すると、データ ペイロードは、アプリの起動に使用された IntentExtras に表示されます。

この例では、アプリがバックグラウンドにある場合、メッセージにデータ ペイロードがあるときに、SendNotification が実行されます。 それ以外の場合は、バックグラウンド通知 (このチュートリアルで前述) が起動されます。

最後のメッセージを送信する

アプリをアンインストールし、リビルドして、もう一度実行し、次の手順を使用して最後のメッセージを送信します。

  1. Firebase コンソールで、[新しいメッセージ] をクリックします。

  2. [メッセージの作成] ページで、メッセージ テキストを入力し、[単一デバイス] を選択します。

  3. IDE 出力ウィンドウからトークン文字列をコピーし、以前と同様に Firebase コンソールの [FCM 登録トークン] フィールドに貼り付けます。

  4. アプリがフォアグラウンドで実行されていることを確認し、Firebase コンソールで [メッセージの送信] をクリックします。

    前景メッセージを送信する

今回は、出力ウィンドウにログされたメッセージも新しい通知にパッケージ化されます。アプリがフォアグラウンドで実行されている間、通知アイコンが通知トレイに表示されます。

前景メッセージの通知アイコン

通知を開くと、Firebase コンソール通知 GUI から最後に送信されたメッセージが表示されます。

前景アイコンが表示された前景の通知

FCM からの切断

トピックの登録を解除するには、FirebaseMessaging クラスで UnsubscribeFromTopic メソッドを呼び出します。 たとえば、前に登録した "ニュース" トピックの登録を解除するには、次のハンドラー コードを使用して [登録を解除] ボタンをレイアウトに追加できます。

var unSubscribeButton = FindViewById<Button>(Resource.Id.unsubscribeButton);
unSubscribeButton.Click += delegate {
    FirebaseMessaging.Instance.UnsubscribeFromTopic("news");
    Log.Debug(TAG, "Unsubscribed from remote notifications");
};

FCM からデバイスの登録を完全に解除するには、FirebaseInstanceId クラスで DeleteInstanceId メソッドを呼び出してインスタンス ID を削除します。 次に例を示します。

FirebaseInstanceId.Instance.DeleteInstanceId();

このメソッド呼び出しによって、インスタンス ID とそれに関連付けられているデータが削除されます。 その結果、デバイスへの FCM データの定期的な送信が停止します。

トラブルシューティング

次に、Xamarin.Android で Firebase Cloud Messaging を使用するときに発生する可能性がある問題と回避策について説明します。

FirebaseApp が初期化されていません

場合によっては、次のエラー メッセージが表示されることがあります。

Java.Lang.IllegalStateException: Default FirebaseApp is not initialized in this process
Make sure to call FirebaseApp.initializeApp(Context) first.

これは既知の問題であり、ソリューションをクリーンし、プロジェクトをリビルドすることで回避できます ([ビルド] > [ソリューションのクリーン][ビルド] > [ソリューションのリビルド])。

まとめ

このチュートリアルでは、Xamarin.Android アプリケーションで Firebase Cloud Messaging リモート通知を実装する手順について詳しく説明しました。 FCM 通信に必要なパッケージをインストールする方法と、FCM サーバーにアクセスするために Android マニフェストを構成する方法について説明しました。 Google Play 開発者サービスの存在をチェックする方法を示すコード例を提供しました。 登録トークンについて FCM とネゴシエートするインスタンス ID リスナー サービスを実装する方法を示し、アプリがバックグラウンドにあるときに、このコードでバックグラウンド通知を作成する方法について説明しました。 トピック メッセージを登録する方法について説明し、アプリがフォアグラウンドで実行されている間に、リモート通知を受信して表示するときに使用されるメッセージ リスナー サービスの実装例を示しました。