次の方法で共有


Xamarin.Android でのブロードキャスト レシーバー

このセクションでは、ブロードキャスト レシーバーの使用方法について説明します。

ブロードキャスト レシーバーの概要

"ブロードキャスト レシーバー" は、Android オペレーティング システムまたはアプリケーションによってブロードキャストされたメッセージ (Android Intent) にアプリケーションで応答できるようにする Android コンポーネントです。 ブロードキャストは、イベントが契機となってブロードキャストがパブリッシュされ、イベントに関心のあるコンポーネントがそれを受信する、"パブリッシュ-サブスクライブ" モデルに従います。

Android では、2 種類のブロードキャストが識別されます。

  • 明示的ブロードキャスト: この種類のブロードキャストでは、特定のアプリケーションがターゲットになります。 明示的ブロードキャストの最も一般的な用途は、アクティビティを開始することです。 アプリで電話番号をダイヤルする必要がある場合の、明示的ブロードキャストの例。Android 上の電話アプリをターゲットとするインテントをディスパッチし、ダイヤルする電話番号を渡します。 その後、Android はインテントを電話アプリにルーティングします。
  • 暗黙的ブロードキャスト: このブロードキャストは、デバイス上のすべてのアプリにディスパッチされます。 暗黙的ブロードキャストの例は、ACTION_POWER_CONNECTED インテントです。 このインテントは、デバイスのバッテリーが充電中であることを Android が検出するたびにパブリッシュされます。 Android は、このイベントに登録されているすべてのアプリにこのインテントをルーティングします。

ブロードキャスト レシーバーは BroadcastReceiver 型のサブクラスであり、OnReceive メソッドをオーバーライドする必要があります。 Android はメイン スレッドで OnReceive を実行するため、このメソッドはすばやく実行するように設計する必要があります。 Android はメソッドが終了するとプロセスを終了する可能性があるため、OnReceive でスレッドを生成するときは注意が必要です。 ブロードキャスト レシーバーが時間のかかる処理を実行する必要がある場合は、JobScheduler または "Firebase ジョブ ディスパッチャー" を使って、"ジョブ" をスケジュールすることをお勧めします。 ジョブでの処理のスケジュールについては、別のガイドで説明します。

"インテント フィルター" は、Android がメッセージを適切にルーティングできるようにブロードキャスト レシーバーを登録するために使われます。 インテント フィルターは、実行時に指定する (これは、"コンテキスト登録レシーバー" または "動的登録" と呼ばれることもあります) ことも、または Android マニフェストで静的に定義する ("マニフェスト登録レシーバー") こともできます。 Xamarin.Android で提供されている C# 属性 IntentFilterAttribute は、インテント フィルターを静的に登録します (これについては、このガイドで後ほど詳しく説明します)。 Android 8.0 以降では、アプリケーションで暗黙的ブロードキャスト用に静的に登録することはできません。

マニフェスト登録レシーバーとコンテキスト登録レシーバーの主な違いは、コンテキスト登録レシーバーはアプリケーションの実行中にのみブロードキャストに応答しますが、マニフェスト登録レシーバーはアプリが実行されていない可能性がある場合でもブロードキャストに応答できることです。

ブロードキャスト レシーバーの管理用と、ブロードキャストの送信用に、2 セットの API があります。

  1. Context: Android.Content.Context クラスを使うと、システム全体のイベントに応答するブロードキャスト レシーバーを登録できます。 Context は、システム全体のブロードキャストをパブリッシュするためにも使われます。
  2. LocalBroadcastManager: これは、Xamarin Support Library v4 NuGet パッケージで使用できる API です。 このクラスは、ブロードキャストとブロードキャスト レシーバーを、それらを使っているアプリケーションのコンテキスト内で分離しておくために使われます。 このクラスは、アプリケーション専用ブロードキャストに他のアプリケーションが応答したり、プライベート レシーバーにメッセージを送信したりするのを防ぐのに役立ちます。

ブロードキャスト レシーバーはダイアログを表示できないので、ブロードキャスト レシーバー内からはアクティビティを開始しないことを強くお勧めします。 ブロードキャスト レシーバーがユーザーに通知する必要がある場合は、通知をパブリッシュする必要があります。

ブロードキャスト レシーバー内からサービスにバインドしたり、サービスを開始したりすることはできません。

このガイドでは、ブロードキャスト レシーバーを作成する方法と、ブロードキャストを受信できるようにそれを登録する方法について説明します。

ブロードキャスト レシーバーの作成

Xamarin.Android でブロードキャスト レシーバーを作成するには、アプリケーションで BroadcastReceiver クラスをサブクラス化し、BroadcastReceiverAttribute で修飾して、OnReceive メソッドをオーバーライドする必要があります。

[BroadcastReceiver(Enabled = true, Exported = false)]
public class SampleReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // Do stuff here.

        String value = intent.GetStringExtra("key");
    }
}

Xamarin.Android は、クラスをコンパイルするときに、レシーバーの登録に必要なメタデータで AndroidManifest も更新します。 静的登録ブロードキャスト レシーバーの場合、Enabled プロパティを true に設定する必要があります。そうしないと、Android はレシーバーのインスタンスを作成できません。

Exported プロパティは、ブロードキャスト レシーバーがアプリケーションの外部からのメッセージを受信できるかどうかを制御します。 このプロパティが明示的に設定されていない場合、プロパティの既定値は、ブロードキャスト レシーバーに関連付けられているインテント フィルターがあるかどうかに基づいて、Android により決定されます。 ブロードキャスト レシーバーにインテント フィルターが 1 つでもある場合、Android は Exported プロパティが true であると見なします。 ブロードキャスト レシーバーにインテント フィルターが関連付けられていない場合、Android は値が false であると見なします。

OnReceive メソッドは、ブロードキャスト レシーバーにディスパッチされた Intent への参照を受け取ります。 これにより、インテントの送信者はブロードキャスト レシーバーに値を渡すことができます。

インテント フィルター内でのブロードキャスト レシーバーの静的登録

BroadcastReceiverIntentFilterAttribute で修飾されていると、Xamarin.Android はコンパイル時に必要な <intent-filter> 要素を Android マニフェストに追加します。 次のスニペットは、デバイスの起動が完了すると実行されるブロードキャスト レシーバーの例です (適切な Android アクセス許可がユーザーによって付与されている場合)。

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class MyBootReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // Work that should be done when the device boots.     
    }
}

Note

Android 8.0 (API 26 以上) では、ユーザーが直接操作していない間にアプリでできることについて Google が制限を設けました。 これらの制限は、バックグラウンド サービスと暗黙的ブロードキャスト レシーバー (Android.Content.Intent.ActionBootCompleted など) に影響します。 これらの制限により、新しいバージョンの Android でブロードキャスト レシーバーを Boot Completed 登録するのが難しい場合があります。 そのような場合は、これらの制限は、ブロードキャスト レシーバーから呼び出すことができるフォアグラウンド サービスには適用されないことに注意してください。

また、カスタム インテントに応答するインテント フィルターを作成することもできます。 次の例を考えてみましょう。

[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "com.xamarin.example.TEST" })]
public class MySampleBroadcastReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // Do stuff here
    }
}

Android 8.0 (API レベル 26) 以降を対象とするアプリでは、暗黙的ブロードキャスト用に静的に登録できません。 その場合でも、アプリは明示的ブロードキャスト用には静的に登録できます。 この制限から除外される暗黙的ブロードキャストの小さなリストがあります。 これらの例外については、Android ドキュメントの「暗黙的ブロードキャストの例外」ガイドで説明されています。 暗黙的ブロードキャストに関心があるアプリは、RegisterReceiver メソッドを使って動的にそれを行う必要があります。 これについては次に説明します。

ブロードキャスト レシーバーのコンテキスト登録

レシーバーのコンテキスト登録 (動的登録とも呼ばれます) は、RegisterReceiver メソッドを呼び出して実行されます。ブロードキャスト レシーバーは、UnregisterReceiver メソッドを呼び出して登録解除する必要があります。 リソースのリークを防ぐには、コンテキスト (アクティビティまたはサービス) に関連しなくなったレシーバーの登録を解除することが重要です。 たとえば、サービスでは、インテントをブロードキャストして、更新プログラムをユーザーに表示できるようになったことをアクティビティに通知できます。 アクティビティは、開始したらそれらのインテントに登録します。 アクティビティがバックグラウンドに移動されて、ユーザーに表示されなくなったら、更新プログラムを表示するための UI が見えなくなるため、レシーバーの登録を解除する必要があります。 次のコード スニペットは、アクティビティのコンテキストでブロードキャスト レシーバーを登録および登録解除する方法の例です。

[Activity(Label = "MainActivity", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity: Activity
{
    MySampleBroadcastReceiver receiver;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        receiver = new MySampleBroadcastReceiver();

        // Code omitted for clarity
    }

    protected override void OnResume()
    {
        base.OnResume();
        RegisterReceiver(receiver, new IntentFilter("com.xamarin.example.TEST"));
        // Code omitted for clarity
    }

    protected override void OnPause()
    {
        UnregisterReceiver(receiver);
        // Code omitted for clarity
        base.OnPause();
    }
}

前の例では、アクティビティは、フォアグラウンドになると、OnResume ライフサイクル メソッドを使ってカスタム インテントをリッスンするブロードキャスト レシーバーを登録します。 アクティビティがバックグラウンドに移ると、OnPause() メソッドはレシーバーの登録を解除します。

ブロードキャストのパブリッシュ

インテント オブジェクトを作成し、SendBroadcast または SendOrderedBroadcast メソッドを使ってそれをディスパッチして、デバイスにインストールされているすべてのアプリにブロードキャストをパブリッシュできます。

  1. Context.SendBroadcast メソッド: このメソッドには複数の実装があります。 これらのメソッドは、インテントをシステム全体にブロードキャストします。 インテントを不定の順序で受信するブロードキャスト レシーバー。 これにより、柔軟性は大幅に向上しますが、他のアプリケーションがインテントを登録して受信できることを意味します。 これにより、潜在的なセキュリティ リスクが発生する可能性があります。 アプリケーションでは、承認されていないアクセスを防ぐため、追加のセキュリティの実装が必要になる場合があります。 考えられる解決策の 1 つは、アプリのプライベート空間内でのみメッセージをディスパッチする LocalBroadcastManager を使うことです。 次のコード スニペットは、SendBroadcast メソッドの 1 つを使ってインテントをディスパッチする方法の一例です。

    Intent message = new Intent("com.xamarin.example.TEST");
    // If desired, pass some values to the broadcast receiver.
    message.PutExtra("key", "value");
    SendBroadcast(message);
    

    次のスニペットは、Intent.SetAction メソッドを使ってアクションを識別してブロードキャストを送信する、もう 1 つの例です。

    Intent intent = new Intent();
    intent.SetAction("com.xamarin.example.TEST");
    intent.PutExtra("key", "value");
    SendBroadcast(intent);
    
  2. Context.SendOrderedBroadcast: このメソッドは Context.SendBroadcast とよく似ていますが、レシーバーが登録された順序で、一度に 1 つずつ、インテントがレシーバーにパブリッシュされる点が異なります。

LocalBroadcastManager

Xamarin Support Library v4 では、LocalBroadcastManager と呼ばれるヘルパー クラスが提供されています。 LocalBroadcastManager は、デバイス上の他のアプリとの間でブロードキャストを送受信したくないアプリを対象としています。 LocalBroadcastManager は、アプリケーションのコンテキスト内でのみ、LocalBroadcastManager に登録されているブロードキャスト レシーバーにだけ、メッセージをパブリッシュします。 次のコード スニペットは、ブロードキャスト レシーバーを LocalBroadcastManager に登録する例です。

Android.Support.V4.Content.LocalBroadcastManager.GetInstance(this). RegisterReceiver(receiver, new IntentFilter("com.xamarin.example.TEST"));

デバイス上の他のアプリは、LocalBroadcastManager でパブリッシュされたメッセージを受信できません。 次のコード スニペットは、LocalBroadcastManager を使ってインテントをディスパッチする方法を示しています。

Intent message = new Intent("com.xamarin.example.TEST");
// If desired, pass some values to the broadcast receiver.
message.PutExtra("key", "value");
Android.Support.V4.Content.LocalBroadcastManager.GetInstance(this).SendBroadcast(message);