Firebase クラウド メッセージングによるリモート通知
このチュートリアルでは、Firebase Cloud Messaging を使用して Xamarin.Android アプリケーションにリモート通知 (プッシュ通知とも呼ばれます) を実装する方法について詳しく説明します。 Firebase Cloud Messaging (FCM) との通信に必要なさまざまなクラスを実装する方法を示し、FCM にアクセスするために Android マニフェストを構成する方法の例を示し、Firebase コンソールを使用したダウンストリーム メッセージングを示します。
FCM 通知の概要
このチュートリアルでは、FCMClient という基本的なアプリを作成して、FCM メッセージングの要点を説明します。 FCMClient は、Google Play 開発者サービスの存在を確認し、FCM から登録トークンを受け取り、Firebase コンソールから送信したリモート通知を表示し、トピック メッセージを登録します。
次のトピック領域について説明します。
バックグラウンド通知
トピック メッセージ
フォアグラウンド通知
このチュートリアルでは、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 としても機能します。 このパッケージ名を使用するようにアプリを構成します。
FCMClient プロジェクトのプロパティを開きます。
[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 以降が必要です。
NuGet のインストール中にエラーが発生した場合は、FCMClient プロジェクトを閉じてからもう一度開き、NuGet のインストールを再試行してください。
Xamarin.GooglePlayServices.Base をインストールすると、必要な依存関係もすべてインストールされます。 MainActivity.cs を編集し、次の using
ステートメントを追加します。
using Android.Gms.Common;
このステートメントにより、Xamarin.GooglePlayServices.Base の GoogleApiAvailability
クラスを FCMClient コードで使用できるようになります。
GoogleApiAvailability
は、Google Play 開発者サービスの存在を確認するために使用されます。
Xamarin Firebase メッセージング パッケージを追加する
FCM からメッセージを受信するには、Xamarin Firebase - Messaging NuGet パッケージをアプリ プロジェクトに追加する必要があります。 このパッケージがないと、Android アプリケーションは FCM サーバーからメッセージを受信できません。
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 ファイルをプロジェクトのルート ディレクトリに追加します。
google-services.json をプロジェクト フォルダーにコピーします。
google-services.json をアプリ プロジェクトに追加します (ソリューション エクスプローラーで [すべてのファイルを表示] をクリックし、google-services.json を右クリックして、[プロジェクトに含める] を選択します)。
ソリューション エクスプローラー ウィンドウで、[google-services.json] を選択します。
[プロパティ] ペインで、[ビルド アクション] を [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_ID
と NOTIFICATION_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();
}
IsPlayServicesAvailable
が OnCreate
の終了時に呼び出されることで、アプリが起動するたびに Google Play 開発者サービス チェックが実行されます。 メソッド CreateNotificationChannel
は、Android 8 以降を実行しているデバイスに通知チャネルが存在することを確認するために呼び出されます。 アプリに OnResume
メソッドがある場合、そのアプリは、OnResume
からも IsPlayServicesAvailable
を呼び出す必要があります。 アプリを完全にリビルドして実行してください。 すべてが正しく構成されている場合は、次のスクリーンショットのような画面が表示されます。
この結果が得られない場合は、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
では次の手順が実行されます。
インスタンス ID API を使用して、クライアント アプリが FCM とアプリ サーバーにアクセスすることを承認するセキュリティ トークンを生成します。 その代わりに、アプリは FCM から登録トークンを取得します。
登録トークンをアプリ サーバーに転送します (アプリ サーバーで必要な場合)。
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 か月ごと) に更新するよう要求します。
また、OnTokenRefresh
は SendRegistrationToAppServer
を呼び出して、ユーザーの登録トークンと、アプリケーションによって管理されているサーバー側アカウント (存在する場合) を関連付けます。
void SendRegistrationToAppServer (string token)
{
// Add custom implementation here as needed.
}
この実装はアプリ サーバーの設計に依存するため、この例では空のメソッド本体が提供されます。 アプリ サーバーで FCM 登録情報が必要な場合は、SendRegistrationToAppServer
を変更して、ユーザーの FCM インスタンス ID トークンを、アプリによって管理されている任意のサーバー側アカウントに関連付けます (トークンはクライアント アプリに対して不透明であることに注意してください)。
トークンがアプリ サーバーに送信されるときは、そのトークンがサーバーに送信されたかどうかを示すブール値を SendRegistrationToAppServer
で保持する必要があります。 このブール値が false の場合、SendRegistrationToAppServer
は、トークンをアプリ サーバーに送信します。それ以外の場合、トークンは、以前の呼び出しで既にアプリ サーバーに送信されています。 場合によっては (この FCMClient
例など)、アプリ サーバーはトークンを必要としません。したがって、この例ではこのメソッドは必要ありません。
クライアント アプリ コードを実装する
受信側サービスが整ったので、これらのサービスを利用するためにクライアント アプリ コードを記述できます。 次のセクションでは、登録トークン (インスタンス ID トークンとも呼ばれます) をログするためのボタンが UI に追加され、通知からアプリが起動されたときに Intent
情報を表示するために MainActivity
にさらにコードが追加されます。
ログ トークン
この手順で追加されたコードは、デモンストレーションのみを目的としています。運用クライアント アプリでは、登録トークンをログする必要はありません。 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" />
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 アプリをビルドして実行します。 [ログ トークン] ボタンが表示されます。
[ログ トークン] ボタンをタップします。 次のようなメッセージが IDE 出力ウィンドウに表示されます。
トークンでラベル付けされた長い文字列は、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 コンソールにサインインし、プロジェクトを選択し、[通知] をクリックして、[最初のメッセージの送信] をクリックします。
[メッセージの作成] ページで、メッセージ テキストを入力し、[単一デバイス] を選択します。 IDE 出力ウィンドウからインスタンス ID トークンをコピーし、Firebase コンソールの [FCM 登録トークン] フィールドに貼り付けます。
Android デバイス (またはエミュレーター) で、Android の [概要] ボタンをタップし、ホーム画面にタッチして、アプリをバックグラウンドにします。 デバイスの準備ができたら、Firebase コンソールで [メッセージの送信] をクリックします。
[メッセージの確認] ダイアログが表示されたら、[送信] をクリックします。 通知アイコンは、デバイス (またはエミュレーター) の通知領域に表示されます。
通知アイコンを開いてメッセージを表示します。 通知メッセージは、Firebase コンソールの[メッセージ テキスト] フィールドに入力されたものと完全に同じである必要があります。
通知アイコンをタップして FCMClient アプリを起動します。 FCMClient に送信される Intent
エクストラは、IDE 出力ウィンドウに一覧表示されます。
この例では、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 出力ウィンドウにトピックの同期が成功したことが表示されます。
トピック メッセージを送信するには、次の手順に従います。
Firebase コンソールで、[新しいメッセージ] をクリックします。
[メッセージの作成] ページで、メッセージ テキストを入力し、[トピック] を選択します。
[トピック] プルダウン メニューで、組み込みのトピック "ニュース" を選択します。
Android デバイス (またはエミュレーター) で、Android の [概要] ボタンをタップし、ホーム画面にタッチして、アプリをバックグラウンドにします。
デバイスの準備ができたら、Firebase コンソールで [メッセージの送信] をクリックします。
IDE 出力ウィンドウを確認して、ログ出力に /topics/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 がメッセージを配信する方法が原因で、デバッグ セッションでこれらのブレークポイントにヒットする場合とヒットしない場合があります。
別のメッセージを送信する
アプリをアンインストールし、リビルドして、もう一度実行し、次の手順に従って別のメッセージを送信します。
Firebase コンソールで、[新しいメッセージ] をクリックします。
[メッセージの作成] ページで、メッセージ テキストを入力し、[単一デバイス] を選択します。
IDE 出力ウィンドウからトークン文字列をコピーし、以前と同様に Firebase コンソールの [FCM 登録トークン] フィールドに貼り付けます。
アプリがフォアグラウンドで実行されていることを確認し、Firebase コンソールで [メッセージの送信] をクリックします。
[メッセージの確認] ダイアログが表示されたら、[送信] をクリックします。
受信メッセージは 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.png を Resources/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
によってメッセージが処理されます。 - 両方 – システム トレイに、通知とデータ ペイロードの両方を持つメッセージが配信されます。 アプリが起動すると、データ ペイロードは、アプリの起動に使用された
Intent
のExtras
に表示されます。
この例では、アプリがバックグラウンドにある場合、メッセージにデータ ペイロードがあるときに、SendNotification
が実行されます。 それ以外の場合は、バックグラウンド通知 (このチュートリアルで前述) が起動されます。
最後のメッセージを送信する
アプリをアンインストールし、リビルドして、もう一度実行し、次の手順を使用して最後のメッセージを送信します。
Firebase コンソールで、[新しいメッセージ] をクリックします。
[メッセージの作成] ページで、メッセージ テキストを入力し、[単一デバイス] を選択します。
IDE 出力ウィンドウからトークン文字列をコピーし、以前と同様に Firebase コンソールの [FCM 登録トークン] フィールドに貼り付けます。
アプリがフォアグラウンドで実行されていることを確認し、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 リスナー サービスを実装する方法を示し、アプリがバックグラウンドにあるときに、このコードでバックグラウンド通知を作成する方法について説明しました。 トピック メッセージを登録する方法について説明し、アプリがフォアグラウンドで実行されている間に、リモート通知を受信して表示するときに使用されるメッセージ リスナー サービスの実装例を示しました。