次の方法で共有


Google Cloud Messaging を使用したリモート通知

警告

Google は、2018 年 4 月 10 日の時点で GCM を非推奨としました。 次のドキュメントとサンプル プロジェクトはメンテナンスされなくなる可能性があります。 Google の GCM サーバーとクライアント API は、2019 年 5 月 29 日にすぐに削除されます。 Google では、GCM アプリを Firebase Cloud Messaging (FCM) に移行することを推奨しています。 GCM の非推奨と移行の詳細については、非推奨の Google Cloud Messaging の説明を参照してください。

Xamarin で Firebase Cloud Messaging を使用してリモート通知を開始するには、FCM を使用したリモート通知のページを参照してください。

このチュートリアルでは、Google Cloud Messaging を使用して Xamarin.Android アプリケーションにリモート通知 (プッシュ通知とも呼ばれます) を実装する方法について詳しく説明します。 ここでは、Google Cloud Messaging (GCM) と通信するために実装する必要があるさまざまなクラスについて説明し、GCM にアクセスするために Android マニフェストでアクセス許可を設定する方法について説明し、サンプル テスト プログラムを使用したエンド ツー エンドメッセージングの方法を具体的に示します。

GCM 通知の概要

このチュートリアルでは、Google Cloud Messaging (GCM) を使用してリモート通知 (プッシュ通知とも呼ばれます) を実装する Xamarin.Android アプリケーションを作成します。 リモート メッセージングに GCM を使用するさまざまな意図サービスとリスナー サービスを実装し、アプリケーション サーバーをシミュレートするコマンド ライン プログラムを使用して実装をテストします。

このチュートリアルを進める前に、Google の GCM サーバーを使用するために必要な資格情報を取得する必要があります。このプロセスについては、「Google Cloud Messaging」で説明されています。 特に、このチュートリアルで説明するコード例に挿入するには、API キーと送信者 ID が必要です。

次の手順を使用して、GCM 対応 Xamarin.Android クライアント アプリを作成します。

  1. GCM サーバーとの通信に必要な追加のパッケージをインストールします。
  2. GCM サーバーにアクセスするためのアプリのアクセス許可を構成します。
  3. Google Play 開発者サービスの存在を確認するためのコードを実装します。
  4. 登録トークンについて GCM とネゴシエートする登録意図サービスを実装します。
  5. GCM からの登録トークンの更新をリッスンするインスタンス ID リスナー サービスを実装します。
  6. GCM 経由でアプリ サーバーからリモート メッセージを受信する GCM リスナー サービスを実装します。

このアプリでは、トピック メッセージングと呼ばれる新しい GCM 機能を使用します。 トピック メッセージングでは、アプリ サーバーは個々のデバイスの一覧ではなく、トピックにメッセージを送信します。 そのトピックをサブスクライブするデバイスは、プッシュ通知としてトピック メッセージを受信できます。

クライアント アプリの準備ができたら、GCM 経由でクライアント アプリにプッシュ通知を送信するコマンド ライン C# アプリケーションを実装します。

チュートリアル

まず、RemoteNotifications という名前の新しい空のソリューションを作成しましょう。 次に、Android アプリ テンプレートに基づく新しい Android プロジェクトをこのソリューションに追加しましょう。 このプロジェクトの名前を ClientApp としましょう。 (Xamarin.Android プロジェクトの作成に慣れていない場合は、「Hello, Android」を参照してください)。ClientApp プロジェクトには、GCM 経由でリモート通知を受信する Xamarin.Android クライアント アプリケーションのコードが含まれます。

必要なパッケージを追加する

クライアント アプリ コードを実装する前に、GCM との通信に使用するいくつかのパッケージをインストールする必要があります。 また、Google Play ストア アプリケーションがまだインストールされていない場合は、デバイスに追加する必要があります。

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

Google Cloud Messaging からメッセージを受信するには、Google Play 開発者サービス フレームワークがデバイスに存在する必要があります。 このフレームワークがないと、Android アプリケーションは GCM サーバーからメッセージを受信できません。 Google Play 開発者サービスは、Android デバイスの電源がオンになっている間にバックグラウンドで実行され、GCM からのメッセージを静かにリッスンします。 これらのメッセージが届くと、Google Play 開発者サービスはメッセージを意図に変換し、これらの意図を登録されたアプリケーションにブロードキャストします。

Visual Studio で、[参照] を右クリック > [NuGet パッケージの管理...] の順に選択します。Visual Studio for Mac では、[パッケージ] を右クリック.>.[パッケージを追加...] の順に選択します。Xamarin Google Play 開発者サービス- GCM を検索し、このパッケージを ClientApp プロジェクトにインストールします。

Installing Google Play Services

Xamarin Google Play 開発者サービス- GCM をインストールすると、Xamarin Google Play 開発者サービス- Base が自動的にインストールされます。 エラーが発生した場合は、プロジェクトの [Minimum Android to target]\(ターゲットとなる最小 Android\) 設定を [Compile using SDK version]\(SDK バージョンを使用したコンパイル\) 以外の値に変更し、NuGet のインストールをもう一度試してください。

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

using Android.Gms.Common;
using Android.Util;

これにより、Google Play 開発者サービス GMS パッケージの型がコードで使用できるようになり、GMS とのトランザクションを追跡するために使用するログ機能が追加されます。

Google Play ストア

GCM からメッセージを受信するには、Google Play ストア アプリケーションをデバイスにインストールする必要があります。 (Google Play アプリケーションがデバイスにインストールされるたびに、Google Play ストアもインストールされるため、テスト デバイスに既にインストールされている可能性があります)。Google Play がないと、Android アプリケーションは GCM からメッセージを受信できません。 Google Play ストア アプリがまだデバイスにインストールされていない場合は、Google Play Web サイトにアクセスして Google Play をダウンロードしてインストールしてください。

または、テスト デバイスの代わりに Android 2.2 以降を実行している Android エミュレーターを使用できます (Android エミュレーターに Google Play ストアをインストールする必要はありません)。 ただし、エミュレーターを使用する場合は、Wi-Fi を使用して GCM に接続する必要があります。また、このチュートリアルで後述するように、Wi-Fi のファイアウォールで複数のポートを開く必要があります。

パッケージ名を設定する

Google Cloud Messaging では、GCM 対応アプリのパッケージ名を指定しました (このパッケージ名は、API キーと送信者 ID に関連付けられているアプリケーション ID としても機能します)。 ClientApp プロジェクトのプロパティを開き、パッケージ名をこの文字列に設定しましょう。 この例では、パッケージ名を com.xamarin.gcmexample に設定します。

Setting the package name

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

Android マニフェストにアクセス許可を追加する

Android アプリケーションは、Google Cloud Messaging から通知を受信する前に、次のアクセス許可を構成する必要があります。

  • com.google.android.c2dm.permission.RECEIVE – Google Cloud Messaging からメッセージを登録および受信するためのアクセス許可をアプリに付与します。 (c2dm は何を意味するでしょうか。これは、GCM の現在非推奨の先行タスクである cloud-to-device メッセージングを意味します。GCM は、多くのアクセス許可文字列で引き続き c2dm を使用します)。

  • android.permission.WAKE_LOCK – (省略可能) メッセージのリッスン中にデバイスの CPU がスリープ状態にならないようにします。

  • android.permission.INTERNET – クライアント アプリが GCM と通信できるように、インターネット アクセスを許可します。

  • package_name.permission.C2D_MESSAGE – アプリケーションを Android に登録し、すべての C2D (cloud-to-device) メッセージを排他的に受信するためのアクセス許可を要求します。 package_name プレフィックスは、アプリケーション ID と同じです。

これらのアクセス許可は、Android マニフェストで設定します。 AndroidManifest.xml を編集し、内容を次の XML に置き換えてみましょう。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="YOUR_PACKAGE_NAME"
    android:versionCode="1"
    android:versionName="1.0"
    android:installLocation="auto">
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
    <permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
                android:protectionLevel="signature" />
    <application android:label="ClientApp" android:icon="@drawable/Icon">
    </application>
</manifest>

上記の XML で、YOUR_PACKAGE_NAME をクライアント アプリ プロジェクトのパッケージ名に変更します。 たとえば、com.xamarin.gcmexample のようにします。

Google Play 開発者サービスを確認する

このチュートリアルでは、UI に 1 つの TextView が含まれる最小限のアプリを作成します。 このアプリは、GCM との対話を直接示すわけではありません。 代わりに、出力ウィンドウを見て、アプリが GCM とどのようにハンドシェイクするかを確認し、通知トレイで新しい通知の到着を確認します。

まず、メッセージ領域のレイアウトを作成しましょう。 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>

Main.axml を保存して閉じます。

クライアント アプリが起動したら、GCM への接続を試みる前に Google Play 開発者サービスが利用可能であることを確認する必要があります。 MainActivity.cs を編集し、count インスタンス変数宣言を次のインスタンス変数宣言に置き換えます。

TextView msgText;

次に、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 = "Sorry, this device is not supported";
            Finish ();
        }
        return false;
    }
    else
    {
        msgText.Text = "Google Play Services is available.";
        return true;
    }
}

このコードは、Google Play 開発者サービス APK がインストールされているかどうかをデバイスで確認します。 インストールされていない場合は、Google Play ストアから APK をダウンロードするようにユーザーに指示するメッセージがメッセージ領域に表示されます (または、デバイスのシステム設定で有効にします)。 クライアント アプリの起動時にこのチェックを実行するため、OnCreate の最後にこのメソッドへの呼び出しを追加します。

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

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);

    SetContentView (Resource.Layout.Main);
    msgText = FindViewById<TextView> (Resource.Id.msgText);

    IsPlayServicesAvailable ();
}

このコードは、Google Play 開発者サービス APK の存在を確認し、結果をメッセージ領域に書き込みます。

アプリを完全にリビルドして実行しましょう。 次のスクリーンショットのような画面が表示されます。

Google Play Services is available

この結果が得られない場合は、前に説明したように、Google Play 開発者サービス APK がデバイスにインストールされていること、および Xamarin Google Play 開発者サービス- GCM パッケージが ClientApp プロジェクトに追加されていることを確認します。 ビルド エラーが発生した場合は、ソリューションをクリーニングし、プロジェクトをもう一度ビルドしてみてください。

次に、GCM に接続して登録トークンを取得するコードを記述します。

GCM に登録する

アプリがアプリ サーバーからリモート通知を受信できるようにするには、事前に GCM に登録し、登録トークンを取得する必要があります。 アプリケーションを GCM に登録する作業は、作成した IntentService によって処理されます。 IntentService では次の手順が実行されます。

  1. InstanceID API を使用して、クライアント アプリがアプリ サーバーにアクセスすることを承認するセキュリティ トークンを生成します。 それと引き換えに、GCM から登録トークンを取得します。

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

  3. 1 つ以上の通知トピック チャネルをサブスクライブします。

この IntentService を実装したらテストを実行して、GCM から登録トークンを取得するかどうかを確認します。

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

using System;
using Android.App;
using Android.Content;
using Android.Util;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;

namespace ClientApp
{
    [Service(Exported = false)]
    class RegistrationIntentService : IntentService
    {
        static object locker = new object();

        public RegistrationIntentService() : base("RegistrationIntentService") { }

        protected override void OnHandleIntent (Intent intent)
        {
            try
            {
                Log.Info ("RegistrationIntentService", "Calling InstanceID.GetToken");
                lock (locker)
                {
                    var instanceID = InstanceID.GetInstance (this);
                    var token = instanceID.GetToken (
                        "YOUR_SENDER_ID", GoogleCloudMessaging.InstanceIdScope, null);

                    Log.Info ("RegistrationIntentService", "GCM Registration Token: " + token);
                    SendRegistrationToAppServer (token);
                    Subscribe (token);
                }
            }
            catch (Exception e)
            {
                Log.Debug("RegistrationIntentService", "Failed to get a registration token");
                return;
            }
        }

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

        void Subscribe (string token)
        {
            var pubSub = GcmPubSub.GetInstance(this);
            pubSub.Subscribe(token, "/topics/global", null);
        }
    }
}

上記のサンプル コードでは、YOUR_SENDER_ID をクライアント アプリ プロジェクトの送信者 ID 番号に変更します。 プロジェクトの送信者 ID を取得するには、次の手順を実行します。

  1. Google Cloud Console にログインし、プルダウン メニューからプロジェクト名を選択します。 プロジェクトに表示される [Project info]\(プロジェクト情報\) ウィンドウで、[Go to project settings]\(プロジェクト設定に移動\) をクリックします。

    Selecting XamarinGCM project

  2. [Settings]\(設定\) ページで、プロジェクト番号を見つけます。これはプロジェクトの送信者 ID です。

    Project number displayed

アプリの実行が開始されたときに RegistrationIntentService を開始します。 Google Play 開発者サービスの存在を確認した後に RegistrationIntentService が開始されるように、MainActivity.cs を編集し、OnCreate メソッドを変更します。

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);

    SetContentView(Resource.Layout.Main);
    msgText = FindViewById<TextView> (Resource.Id.msgText);

    if (IsPlayServicesAvailable ())
    {
        var intent = new Intent (this, typeof (RegistrationIntentService));
        StartService (intent);
    }
}

ここで、RegistrationIntentService の各セクションを確認して、そのしくみを理解しましょう。

まず、サービスがシステムによってインスタンス化されないことを示すために、次の属性で RegistrationIntentService に注釈を付けます。

[Service (Exported = false)]

RegistrationIntentService コンストラクターは、デバッグを容易にするために、ワーカー スレッド RegistrationIntentService に名前を付けます。

public RegistrationIntentService() : base ("RegistrationIntentService") { }

RegistrationIntentService のコア機能は、OnHandleIntent メソッドに存在します。 このコードを見て、アプリを GCM に登録する方法を見てみましょう。

登録トークンを要求する

OnHandleIntent は、最初に Google の InstanceID.GetToken メソッドを呼び出して、GCM に登録トークンを要求します。 複数の登録意図が同時に発生する可能性を防ぐために、このコードを lock にラップします。lock により、これらの意図が順番に処理されます。 登録トークンを取得できない場合は、例外がスローされ、エラーがログに記録されます。 登録が成功した場合、token は GCM から取得した登録トークンに設定されます。

static object locker = new object ();
...
try
{
    lock (locker)
    {
        var instanceID = InstanceID.GetInstance (this);
        var token = instanceID.GetToken (
            "YOUR_SENDER_ID", GoogleCloudMessaging.InstanceIdScope, null);
        ...
    }
}
catch (Exception e)
{
    Log.Debug ...

登録トークンをアプリ サーバーに転送する

登録トークンを取得した場合 (つまり、例外がスローされなかった場合)、SendRegistrationToAppServer を呼び出して、アプリケーションによって管理されているサーバー側アカウント (存在する場合) にユーザーの登録トークンを関連付けます。 この実装はアプリ サーバーの設計に依存するため、ここでは空のメソッドを提供します。

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

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

通知トピックをサブスクライブする

次に、通知トピックをサブスクライブすることを GCM に示す Subscribe メソッドを呼び出します。 Subscribe では、GcmPubSub.Subscribe API を呼び出して、クライアント アプリを /topics/global にあるすべてのメッセージにサブスクライブします。

void Subscribe (string token)
{
    var pubSub = GcmPubSub.GetInstance(this);
    pubSub.Subscribe(token, "/topics/global", null);
}

通知メッセージを受信する場合は、アプリ サーバーが /topics/global に通知メッセージを送信する必要があります。 /topics にあるトピック名は、アプリ サーバーとクライアント アプリの両方がこれらの名前に同意している限り、任意の名前にすることができます。 (ここでは、アプリ サーバーでサポートされているすべてのトピックでメッセージを受信することを示すために、global という名前を選択しました)。

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

登録トークンは一意で安全です。ただし、アプリの再インストールまたはセキュリティの問題が発生した場合は、クライアント アプリ (または GCM) で登録トークンの更新が必要になる場合があります。 このため、GCM からのトークン更新要求に応答する InstanceIdListenerService を実装する必要があります。

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

using Android.App;
using Android.Content;
using Android.Gms.Gcm.Iid;

namespace ClientApp
{
    [Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]
    class MyInstanceIDListenerService : InstanceIDListenerService
    {
        public override void OnTokenRefresh()
        {
            var intent = new Intent (this, typeof (RegistrationIntentService));
            StartService (intent);
        }
    }
}

サービスがシステムによってインスタンス化されないこと、および GCM 登録トークン (インスタンス ID とも呼ばれます) の更新要求を受け取ることができることを示すために、InstanceIdListenerService に次の属性で注釈を付けます。

[Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]

サービス内の OnTokenRefresh メソッドは、新しい登録トークンをインターセプトできるように、RegistrationIntentService を開始します。

GCM との登録をテストする

アプリを完全にリビルドして実行しましょう。 GCM から登録トークンを正常に受信した場合は、登録トークンが出力ウィンドウに表示されます。 次に例を示します。

D/Mono    ( 1934): Assembly Ref addref ClientApp[0xb4ac2400] -> Xamarin.GooglePlayServices.Gcm[0xb4ac2640]: 2
I/RegistrationIntentService( 1934): Calling InstanceID.GetToken
I/RegistrationIntentService( 1934): GCM Registration Token: f8LdveCvXig:APA91bFIsjUAbP-V8TPQdLR89qQbEJh1SYG38AcCbBUf34z5gSdUc5OsXrgs93YFiGcRSRafPfzkz23lf3-LvYV1CwrFheMjHgwPeFSh12MywnRIhz

ダウンストリーム メッセージを処理する

これまでに実装したコードは、"セットアップ" コードにすぎません。Google Play 開発者サービスがインストールされているかどうかを確認し、GCM とアプリ サーバーとネゴシエートして、リモート通知を受信するためにクライアント アプリを準備します。 ただし、ダウンストリームの通知メッセージを実際に受信して処理するコードはまだ実装されていません。 これを行うには、GCM リスナー サービスを実装する必要があります。 このサービスは、アプリ サーバーからトピック メッセージを受信し、それらを通知としてローカルでブロードキャストします。 このサービスを実装したら、GCM にメッセージを送信するテスト プログラムを作成して、実装が正しく動作するかどうかを確認します。

通知アイコンを追加する

まず、通知が起動されたときに通知領域に表示される小さなアイコンを追加しましょう。 このアイコンをプロジェクトにコピーするか、独自のカスタム アイコンを作成できます。 アイコン ファイルに ic_stat_button_click.png という名前を付け、Resources/drawable フォルダーにコピーします。 このアイコン ファイルをプロジェクトに含めるには、必ず [追加] > [既存アイテム...] を使用してください。

GCM リスナー サービスを実装する

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

using Android.App;
using Android.Content;
using Android.OS;
using Android.Gms.Gcm;
using Android.Util;

namespace ClientApp
{
    [Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]
    public class MyGcmListenerService : GcmListenerService
    {
        public override void OnMessageReceived (string from, Bundle data)
        {
            var message = data.GetString ("message");
            Log.Debug ("MyGcmListenerService", "From:    " + from);
            Log.Debug ("MyGcmListenerService", "Message: " + message);
            SendNotification (message);
        }

        void SendNotification (string message)
        {
            var intent = new Intent (this, typeof(MainActivity));
            intent.AddFlags (ActivityFlags.ClearTop);
            var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);

            var notificationBuilder = new Notification.Builder(this)
                .SetSmallIcon (Resource.Drawable.ic_stat_ic_notification)
                .SetContentTitle ("GCM Message")
                .SetContentText (message)
                .SetAutoCancel (true)
                .SetContentIntent (pendingIntent);

            var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
            notificationManager.Notify (0, notificationBuilder.Build());
        }
    }
}

GcmListenerService の各セクションを確認して、そのしくみを理解しましょう。

まず、このサービスがシステムによってインスタンス化されないことを示すために GcmListenerService に属性で注釈を付け、GCM メッセージを受信することを示す意図フィルターを含めます。

[Service (Exported = false), IntentFilter (new [] { "com.google.android.c2dm.intent.RECEIVE" })]

GcmListenerService が GCM からメッセージを受信すると、OnMessageReceived メソッドが呼び出されます。 このメソッドは、渡された Bundle からメッセージの内容を抽出し、メッセージの内容をログに記録し (出力ウィンドウで表示できるように)、受信したメッセージの内容を含むローカル通知を起動するために SendNotification を呼び出します。

var message = data.GetString ("message");
Log.Debug ("MyGcmListenerService", "From:    " + from);
Log.Debug ("MyGcmListenerService", "Message: " + message);
SendNotification (message);

SendNotification メソッドは Notification.Builder を使用して通知を作成し、NotificationManager を使用して通知を起動します。 実質的に、これにより、リモート通知メッセージがローカル通知に変換され、ユーザーに表示されます。 Notification.BuilderNotificationManager の使用の詳細については、ローカル通知の説明を参照してください。

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

GCM からメッセージを受信するには、Android マニフェストで GCM リスナーを宣言する必要があります。 AndroidManifest.xml を編集し、<application> セクションを次の XML に置き換えてみましょう。

<application android:label="RemoteNotifications" android:icon="@drawable/Icon">
    <receiver android:name="com.google.android.gms.gcm.GcmReceiver"
              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="YOUR_PACKAGE_NAME" />
        </intent-filter>
    </receiver>
</application>

上記の XML で、YOUR_PACKAGE_NAME をクライアント アプリ プロジェクトのパッケージ名に変更します。 このチュートリアルの例では、パッケージ名は com.xamarin.gcmexample です。

この XML の各設定で実行される内容を見てみましょう。

設定 説明
com.google.android.gms.gcm.GcmReceiver アプリが、受信プッシュ通知メッセージをキャプチャして処理する GCM レシーバーを実装することを宣言します。
com.google.android.c2dm.permission.SEND GCM サーバーのみがアプリに直接メッセージを送信できることを宣言します。
com.google.android.c2dm.intent.RECEIVE アプリが GCM からのブロードキャスト メッセージを処理することをアドバタイズする意図フィルター。
com.google.android.c2dm.intent.REGISTRATION アプリが新しい登録意図を処理することをアドバタイズする意図フィルター (つまり、インスタンス ID リスナー サービスを実装しました)。

または、XML で指定するのではなく、これらの属性で GcmListenerService を装飾することもできます。ここでは、コード サンプルを簡単にフォローできるように、AndroidManifest.xml で指定します。

アプリをテストするメッセージ送信者を作成する

C# デスクトップ コンソール アプリケーション プロジェクトをソリューションに追加し、MessageSender と呼びます。 このコンソール アプリケーションを使用してアプリケーション サーバーをシミュレートします。これにより、GCM 経由で ClientApp に通知メッセージが送信されます。

Json.NET パッケージを追加する

このコンソール アプリでは、クライアント アプリに送信する通知メッセージを含む JSON ペイロードを構築しています。 MessageSenderJson.NET パッケージを使用して、GCM で必要な JSON オブジェクトを簡単に構築できるようにします。 Visual Studio で、[参照] を右クリック > [NuGet パッケージの管理...] の順に選択します。Visual Studio for Mac では、[パッケージ] を右クリック.>.[パッケージを追加...] の順に選択します。

Json.NET パッケージを検索し、プロジェクトにインストールしてみましょう。

Installing the Json.NET package

System.Net.Http に対する参照を追加する

テスト メッセージを GCM に送信するために HttpClient インスタンスを作成できるように、System.Net.Http への参照も追加する必要があります。 MessageSender プロジェクトで、[参照] を右クリック > [参照の追加] の順に移動して、System.Net.Http が表示されるまで下にスクロールします。 System.Net.Http の横にチェック マークを付け、[OK] をクリックします。

テスト メッセージを送信するコードを実装する

MessageSender で、Program.cs を編集し、内容を次のコードに置き換えます。

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace MessageSender
{
    class MessageSender
    {
        public const string API_KEY = "YOUR_API_KEY";
        public const string MESSAGE = "Hello, Xamarin!";

        static void Main (string[] args)
        {
            var jGcmData = new JObject();
            var jData = new JObject();

            jData.Add ("message", MESSAGE);
            jGcmData.Add ("to", "/topics/global");
            jGcmData.Add ("data", jData);

            var url = new Uri ("https://gcm-http.googleapis.com/gcm/send");
            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Add(
                        new MediaTypeWithQualityHeaderValue("application/json"));

                    client.DefaultRequestHeaders.TryAddWithoutValidation (
                        "Authorization", "key=" + API_KEY);

                    Task.WaitAll(client.PostAsync (url,
                        new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
                            .ContinueWith(response =>
                            {
                                Console.WriteLine(response);
                                Console.WriteLine("Message sent: check the client device notification tray.");
                            }));
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Unable to send GCM message:");
                Console.Error.WriteLine(e.StackTrace);
            }
        }
    }
}

上記のコードで、YOUR_API_KEY をクライアント アプリ プロジェクトの API キーに変更します。

このテスト アプリ サーバーは、次の JSON 形式のメッセージを GCM に送信します。

{
  "to": "/topics/global",
  "data": {
    "message": "Hello, Xamarin!"
  }
}

GCM は、このメッセージをクライアント アプリに転送します。 MessageSender をビルドし、コンソール ウィンドウを開いて、コマンド ラインから実行してみましょう。

手順を次に示します。

これで、クライアント アプリをテストする準備ができました。 エミュレーターを使用している場合、またはデバイスが Wi-Fi 経由で GCM と通信している場合、GCM メッセージが通過するには、ファイアウォールで 5228、5229、5230 の TCP ポートを開く必要があります。

クライアント アプリを起動し、出力ウィンドウを見ます。 RegistrationIntentService が GCM から登録トークンを正常に受信すると、出力ウィンドウに、次のようなログ出力を含むトークンが表示されます。

I/RegistrationIntentService(16103): GCM Registration Token: eX9ggabZV1Q:APA91bHjBnQXMUeBOT6JDiLpRt8m2YWtY ...

この時点で、クライアント アプリはリモート通知メッセージを受信する準備ができています。 コマンド ラインから、MessageSender.exe プログラムを実行して、クライアント アプリに "Hello, Xamarin" 通知メッセージを送信します。 MessageSender プロジェクトをまだビルドしていない場合は、ここで作成します。

Visual Studio で MessageSender.exe を実行するには、コマンド プロンプトを開き、MessageSender/bin/Debug ディレクトリに移動して、コマンドを直接実行します。

MessageSender.exe

Visual Studio for Mac で MessageSender.exe を実行するには、ターミナル セッションを開き、MessageSender/bin/Debug ディレクトリに移動し、mono を使用して MessageSender.exe を実行します

mono MessageSender.exe

メッセージが GCM 経由で伝達され、クライアント アプリに戻るまでに最大 1 分かかる場合があります。 メッセージが正常に受信されると、出力ウィンドウに次のような出力が表示されます。

D/MyGcmListenerService(16103): From:    /topics/global
D/MyGcmListenerService(16103): Message: Hello, Xamarin!

さらに、通知トレイに新しい通知アイコンが表示されていることがわかります。

Notification icon appears on device

通知トレイを開いて通知を表示すると、リモート通知が表示されます。

Notification message is displayed

これで、アプリは最初のリモート通知を受け取りました。

アプリが強制停止されている場合、GCM メッセージは受信されなくなります。 強制停止後に通知を再開するには、アプリを手動で再起動する必要があります。 この Android ポリシーの詳細については、停止したアプリケーションのコントロールの起動の説明と、このスタック オーバーフローの投稿を参照してください。

まとめ

このチュートリアルでは、Xamarin.Android アプリケーションでリモート通知を実装する手順について詳しく説明しました。 GCM 通信に必要な追加のパッケージをインストールする方法と、GCM サーバーにアクセスするためのアプリのアクセス許可を構成する方法について説明しました。 これには、Google Play 開発者サービスの存在を確認する方法、登録トークンについて GCM とネゴシエートする登録意図サービスとインスタンス ID リスナー サービスを実装する方法、リモート通知メッセージを受信して処理する GCM リスナー サービスを実装する方法を示すコード例が用意されています。 最後に、GCM を介してクライアント アプリにテスト通知を送信するコマンド ライン テスト プログラムを実装しました。