ブロードキャストの概要

Android アプリは、パブリッシュ / サブスクライブ設計パターンと同様に、Android システムや他の Android アプリとの間でブロードキャスト メッセージを送受信します。通常、システムとアプリは特定のイベントが発生したときにブロードキャストを送信します。たとえば、Android システムは、システムの起動やデバイスの充電など、さまざまなシステム イベントが発生したときにブロードキャストを送信します。アプリは、他のアプリに関係がありそうなこと(新しいデータのダウンロードなど)を通知するために、カスタム ブロードキャストを送信することもあります。

アプリは特定のブロードキャストを受信するように登録できます。ブロードキャストが送信されると、システムは、その特定のタイプのブロードキャストを受信するために登録したアプリにブロードキャストを自動的にルーティングします。

一般的に、ブロードキャストはアプリ間や通常のユーザーフロー外のメッセージング システムとして使用できます。ただし、ブロードキャストに応答してバックグラウンドでジョブを実行する機会を濫用し、システム パフォーマンスの低下を招かないように注意する必要があります。

システム ブロードキャストについて

システムは、システムが機内モードに切り替わるなど、さまざまなシステム イベントが発生したときにブロードキャストを自動的に送信します。登録されているすべてのアプリがこれらのブロードキャストを受信します。

Intent オブジェクトはブロードキャスト メッセージをラップします。action 文字列は、発生したイベント(android.intent.action.AIRPLANE_MODE など)を識別します。インテントには、追加情報がバンドルされた追加フィールドが含まれることもあります。たとえば、機内モードのインテントには、機内モードがオンかどうかを示すブール値のエクストラが含まれています。

インテントの読み取り方法やインテントからアクション文字列を取得する方法について詳しくは、インテントとインテント フィルタをご覧ください。

システム ブロードキャスト アクション

システム ブロードキャスト アクションの完全なリストについては、Android SDK の BROADCAST_ACTIONS.TXT ファイルをご覧ください。各ブロードキャスト アクションには、関連付けられた定数フィールドがあります。たとえば、定数 ACTION_AIRPLANE_MODE_CHANGED の値は android.intent.action.AIRPLANE_MODE です。各ブロードキャスト アクションのドキュメントは、関連付けられた定数フィールドにあります。

システム ブロードキャストの変更

Android プラットフォームの進化に伴い、システム ブロードキャストの動作は定期的に変更されます。Android のすべてのバージョンをサポートするには、次の変更に注意してください。

Android 16

Android 16 では、android:priority 属性または IntentFilter.setPriority() を使用したブロードキャスト配信の順序が、異なるプロセス間で保証されなくなります。ブロードキャストの優先度は、すべてのプロセスではなく、同じアプリケーション プロセス内でのみ尊重されます。

また、ブロードキャストの優先度は自動的に範囲(SYSTEM_LOW_PRIORITY + 1、SYSTEM_HIGH_PRIORITY - 1)に制限されます。システム コンポーネントのみが、ブロードキャストの優先度として SYSTEM_LOW_PRIORITY、SYSTEM_HIGH_PRIORITY を設定できます。

Android 14

アプリがキャッシュに保存された状態にある間、システムはシステム ヘルスを維持するためにブロードキャスト配信を最適化します。たとえば、アプリがキャッシュに保存された状態にある間、システムは ACTION_SCREEN_ON などの重要度の低いシステム ブロードキャストを遅延させます。アプリがキャッシュに保存された状態からアクティブなプロセス ライフサイクルに移行すると、延期されたブロードキャストがすべて配信されます。

マニフェストで宣言された重要なブロードキャストは、配信のためにキャッシュに保存された状態からアプリを一時的に削除します。

Android 9

Android 9(API レベル 28)以降、NETWORK_STATE_CHANGED_ACTION ブロードキャストはユーザーの位置情報や個人を特定できるデータを受け取りません。

Android 9.0(API レベル 28)以上を搭載したデバイスにアプリがインストールされている場合、システムは Wi-Fi ブロードキャストに SSID、BSSID、接続情報、スキャン結果を含めません。この情報を取得するには、代わりに getConnectionInfo() を呼び出します。

Android 8.0

Android 8.0(API レベル 26)以降では、マニフェストで宣言されたレシーバにシステムが追加の制限を課します。

アプリが Android 8.0 以降をターゲットとしている場合、マニフェストを使用して、ほとんどの暗黙的ブロードキャスト(アプリを特にターゲットとしていないブロードキャスト)のレシーバを宣言することはできません。ユーザーがアプリをアクティブに使用している場合は、コンテキスト登録済みレシーバを使用できます。

Android 7.0

Android 7.0(API レベル 24)以降では、次のシステム ブロードキャストは送信されません。

また、Android 7.0 以降をターゲットとするアプリは、registerReceiver(BroadcastReceiver, IntentFilter) を使用して CONNECTIVITY_ACTION ブロードキャストを登録する必要があります。マニフェストでレシーバを宣言しても機能しません。

ブロードキャストを受信する

アプリは、コンテキスト登録レシーバとマニフェスト宣言レシーバの 2 つの方法でブロードキャストを受信できます。

コンテキスト登録されたレシーバー

コンテキスト登録されたレシーバは、登録コンテキストが有効である限りブロードキャストを受信します。通常、これは registerReceiver と unregisterReceiver の呼び出しの間で行われます。システムが対応するコンテキストを破棄すると、登録コンテキストも無効になります。たとえば、Activity コンテキスト内で登録した場合、アクティビティがアクティブな状態である限り、ブロードキャストを受信します。Application コンテキストで登録すると、アプリが実行されている限りブロードキャストを受信します。

コンテキストを使用してレシーバーを登録する手順は、次のとおりです。

  1. アプリのモジュール レベルのビルドファイルに、バージョン 1.9.0 以降の AndroidX Core ライブラリを追加します。

    Groovy

    dependencies {
        def core_version = "1.19.1"
    
        // Java language implementation
        implementation "androidx.core:core:$core_version"
        // Kotlin
        implementation "androidx.core:core-ktx:$core_version"
    
        // To use RoleManagerCompat
        implementation "androidx.core:core-role:1.1.0"
    
        // To use the Animator APIs
        implementation "androidx.core:core-animation:1.0.0"
        // To test the Animator APIs
        androidTestImplementation "androidx.core:core-animation-testing:1.0.0"
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation "androidx.core:core-performance:1.0.0"
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation "androidx.core:core-google-shortcuts:1.1.0"
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation "androidx.core:core-remoteviews:1.1.0"
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation "androidx.core:core-splashscreen:1.2.0"
    }

    Kotlin

    dependencies {
        val core_version = "1.19.1"
    
        // Java language implementation
        implementation("androidx.core:core:$core_version")
        // Kotlin
        implementation("androidx.core:core-ktx:$core_version")
    
        // To use RoleManagerCompat
        implementation("androidx.core:core-role:1.1.0")
    
        // To use the Animator APIs
        implementation("androidx.core:core-animation:1.0.0")
        // To test the Animator APIs
        androidTestImplementation("androidx.core:core-animation-testing:1.0.0")
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation("androidx.core:core-performance:1.0.0")
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation("androidx.core:core-google-shortcuts:1.1.0")
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation("androidx.core:core-remoteviews:1.1.0")
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation("androidx.core:core-splashscreen:1.2.0")
    }
  2. BroadcastReceiver のインスタンスを作成します。

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    Java

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. IntentFilter のインスタンスを作成します。

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    Java

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. ブロードキャスト レシーバをエクスポートしてデバイス上の他のアプリから参照可能にするかどうかを選択します。このレシーバがシステムまたは他のアプリ(所有している他のアプリも含む)から送信されたブロードキャストをリッスンしている場合は、RECEIVER_EXPORTED フラグを使用します。このレシーバがアプリから送信されたブロードキャストのみをリッスンする場合は、代わりに RECEIVER_NOT_EXPORTED フラグを使用します。

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    Java

    boolean listenToBroadcastsFromOtherApps = false;
    int receiverFlags = listenToBroadcastsFromOtherApps
            ? ContextCompat.RECEIVER_EXPORTED
            : ContextCompat.RECEIVER_NOT_EXPORTED;
    
  5. registerReceiver() を呼び出してレシーバを登録します。

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. ブロードキャストの受信を停止するには、unregisterReceiver(android.content.BroadcastReceiver) を呼び出します。不要になった場合やコンテキストが無効になった場合は、必ずレシーバの登録を解除してください。

ブロードキャスト レシーバを登録解除する

ブロードキャスト レシーバが登録されている間、登録に使用した Context への参照を保持します。レシーバの登録済みスコープが Context ライフサイクル スコープを超えている場合、リークが発生する可能性があります。たとえば、アクティビティのスコープでレシーバを登録したものの、システムがアクティビティを破棄したときに登録解除を忘れた場合などに発生します。そのため、ブロードキャスト レシーバは常に登録解除してください。

Kotlin

class MyActivity : ComponentActivity() {
    private val myBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
        setContent { MyApp() }
    }

    override fun onDestroy() {
        super.onDestroy()
        // When you forget to unregister your receiver here, you're causing a leak!
        this.unregisterReceiver(myBroadcastReceiver)
    }
}

Java

class MyActivity extends ComponentActivity {
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
        // Set content
    }
}

最小スコープでレシーバを登録する

ブロードキャスト レシーバは、結果に実際に興味がある場合にのみ登録する必要があります。可能な限り小さい受信側のスコープを選択します。

  • LifecycleResumeEffect またはアクティビティの onResume/onPause ライフサイクル メソッド: ブロードキャスト レシーバは、アプリが再開状態にある間のみ更新を受け取ります。
  • LifecycleStartEffect またはアクティビティの onStart/onStop ライフサイクル メソッド: ブロードキャスト レシーバは、アプリが再開状態にある間のみ更新を受け取ります。
  • DisposableEffect: コンポーザブルがコンポジション ツリーにある間のみ、ブロードキャスト レシーバは更新を受け取ります。このスコープは、アクティビティのライフサイクル スコープに関連付けられていません。アプリケーション コンテキストにレシーバを登録することを検討してください。これは、コンポーザブルがアクティビティのライフサイクル スコープよりも長く存続し、アクティビティがリークする可能性があるためです。
  • アクティビティ onCreate/onDestroy: アクティビティが作成状態の間、ブロードキャスト レシーバは更新を受け取ります。onSaveInstanceState(Bundle) は呼び出されない可能性があるため、onDestroy() で登録解除してください。
  • カスタム スコープ: たとえば、ViewModel スコープにレシーバを登録して、アクティビティの再作成後も存続させることができます。レシーバはアクティビティ ライフサイクル スコープよりも長く存続し、アクティビティをリークする可能性があるため、アプリケーション コンテキストを使用してレシーバを登録してください。

ステートフルとステートレスのコンポーザブルを作成する

Compose には、ステートフルとステートレスのコンポーザブルがあります。コンポーザブル内でブロードキャスト レシーバを登録または登録解除すると、ステートフルになります。コンポーザブルは、同じパラメータが渡されたときに同じコンテンツをレンダリングする決定論的関数ではありません。内部状態は、登録されたブロードキャスト レシーバへの呼び出しに基づいて変更できます。

Compose のベスト プラクティスとして、コンポーザブルをステートフル バージョンとステートレス バージョンに分割することをおすすめします。そのため、ブロードキャスト レシーバの作成を Composable からホイスティングして、ステートレスにすることをおすすめします。

@Composable
fun MyStatefulScreen() {
    val myBroadcastReceiver = remember { MyBroadcastReceiver() }
    val context = LocalContext.current
    LifecycleStartEffect(true) {
        // ...
        ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
        onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
    }
    MyStatelessScreen()
}

@Composable
fun MyStatelessScreen() {
    // Implement your screen
}

マニフェストで宣言されたレシーバー

マニフェストでブロードキャスト レシーバを宣言すると、ブロードキャストが送信されたときにシステムがアプリを起動します。アプリがまだ実行されていない場合は、システムがアプリを起動します。

マニフェストでブロードキャストのレシーバーを宣言する手順は、次のとおりです。

  1. アプリのマニフェストで <receiver> 要素を指定します。

    <!-- If this receiver listens for broadcasts sent from the system or from
         other apps, even other apps that you own, set android:exported to "true". -->
    <receiver android:name=".MyBroadcastReceiver" android:exported="false">
        <intent-filter>
            <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
        </intent-filter>
    </receiver>
    

    インテント フィルタは、レシーバが登録するブロードキャスト アクションを指定します。

  2. BroadcastReceiver をサブクラス化し、onReceive(Context, Intent) を実装します。次の例のブロードキャスト レシーバは、ブロードキャストの内容をログに記録して表示します。

    Kotlin

    class MyBroadcastReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var dataRepository: DataRepository
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") {
                val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data"
                // Do something with the data, for example send it to a data repository:
                dataRepository.updateData(data)
            }
        }
    }
    

    Java

    public static class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Inject
        DataRepository dataRepository;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) {
                String data = intent.getStringExtra("com.example.snippets.DATA");
                // Do something with the data, for example send it to a data repository:
                if (data != null) { dataRepository.updateData(data); }
            }
        }
    }
    

システム パッケージ マネージャーは、アプリのインストール時にレシーバを登録します。レシーバはアプリへの個別のエントリ ポイントになるため、アプリが実行されていない場合、システムはアプリを起動してブロードキャストを配信できます。

システムは、受信した各ブロードキャストを処理するために、新しい BroadcastReceiver コンポーネント オブジェクトを作成します。このオブジェクトは、onReceive(Context, Intent) の呼び出し中にのみ有効です。コードがこのメソッドから戻ると、システムはコンポーネントがアクティブでなくなったと見なします。

プロセス状態への影響

BroadcastReceiver が動作しているかどうかは、そのプロセスに影響し、システムが終了する可能性を変更します。フォアグラウンド プロセスは、レシーバーの onReceive() メソッドを実行します。システムは、メモリ負荷が極端に高い場合を除き、プロセスを実行します。

システムは onReceive() の後に BroadcastReceiver を無効にします。レシーバのホスト プロセスの重要性は、アプリのコンポーネントによって異なります。そのプロセスがマニフェストで宣言されたレシーバのみをホストしている場合、システムは onReceive() の後にそのプロセスを強制終了して、他のより重要なプロセス用にリソースを解放する可能性があります。これは、ユーザーが一度も使用したことがないアプリや、最近使用していないアプリでよく見られます。

そのため、ブロードキャスト レシーバは長時間実行されるバックグラウンド スレッドを開始すべきではありません。システムは onReceive() の後、いつでもプロセスを停止してメモリを再利用し、作成されたスレッドを終了できます。プロセスを存続させるには、JobScheduler を使用してレシーバから JobService をスケジュール設定し、システムがプロセスがまだ動作していることを認識できるようにします。詳しくは、バックグラウンド処理の概要をご覧ください。

ブロードキャストを送信する

Android では、アプリがブロードキャストを送信する方法として、次の 2 つが用意されています。

  • sendOrderedBroadcast(Intent, String) メソッドは、一度に 1 つのレシーバにブロードキャストを送信します。各レシーバは順番に実行されるので、結果を次のレシーバに伝播できます。また、ブロードキャストを完全に中止して、他のレシーバに届かないようにすることもできます。同じアプリ プロセス内でレシーバが実行される順序を制御できます。これを行うには、一致するインテント フィルタの android:priority 属性を使用します。優先度が同じレシーバは、任意の順序で実行されます。
  • sendBroadcast(Intent) メソッドは、未定義の順序ですべてのレシーバにブロードキャストを送信します。これは通常のブロードキャストと呼ばれます。この方が効率的ですが、レシーバは他のレシーバの結果を読み取ったり、ブロードキャストから受信したデータを伝播したり、ブロードキャストを中止したりできません。

次のコード スニペットは、インテントを作成して sendBroadcast(Intent) を呼び出すことでブロードキャストを送信する方法を示しています。

Kotlin

val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
    putExtra("com.example.snippets.DATA", newData)
    setPackage("com.example.snippets")
}
context.sendBroadcast(intent)

Java

Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);

ブロードキャスト メッセージは Intent オブジェクトでラップされます。インテントの action 文字列は、アプリの Java パッケージ名の構文を提供し、ブロードキャスト イベントを一意に識別する必要があります。putExtra(String, Bundle) を使用して、インテントに追加情報を付加できます。インテントで setPackage(String) を呼び出すことで、ブロードキャストを同じ組織内のアプリのセットに制限することもできます。

権限でブロードキャストを制限する

権限を使用すると、特定の権限を保持するアプリのセットにブロードキャストを制限できます。ブロードキャストの送信者または受信者のいずれかに制限を適用できます。

権限付きブロードキャストを送信する

sendBroadcast(Intent, String) または sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) を呼び出すときに、権限パラメータを指定できます。マニフェストで <uses-permission> タグを使用してその権限をリクエストしたレシーバーのみが、ブロードキャストを受信できます。権限が危険な場合は、レシーバがブロードキャストを受信できるように、権限を付与する必要があります。たとえば、次のコードは権限付きのブロードキャストを送信します。

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

Java

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

ブロードキャストを受信するには、受信側のアプリが次のように権限をリクエストする必要があります。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

BLUETOOTH_CONNECT などの既存のシステム権限を指定するか、<permission> 要素を使用してカスタム権限を定義できます。権限とセキュリティ全般については、システム権限をご覧ください。

権限付きブロードキャストを受信する

ブロードキャスト レシーバを登録する際に権限パラメータを指定した場合(registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) を使用するか、マニフェストの <receiver> タグを使用)、マニフェストの <uses-permission> タグで権限をリクエストしたブロードキャスタのみが、レシーバにインテントを送信できます。権限が危険な場合は、ブロードキャスト送信者にも権限が付与されている必要があります。

たとえば、受信側アプリに次のようにマニフェストで宣言されたレシーバがあるとします。

<!-- If this receiver listens for broadcasts sent from the system or from
     other apps, even other apps that you own, set android:exported to "true". -->
<receiver
    android:name=".MyBroadcastReceiverWithPermission"
    android:permission="android.permission.ACCESS_COARSE_LOCATION"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
    </intent-filter>
</receiver>

または、受信アプリに次のようなコンテキスト登録されたレシーバがあります。

Kotlin

ContextCompat.registerReceiver(
    context, myBroadcastReceiver, filter,
    android.Manifest.permission.ACCESS_COARSE_LOCATION,
    null, // scheduler that defines thread, null means run on main thread
    receiverFlags
)

Java

ContextCompat.registerReceiver(
        context, myBroadcastReceiver, filter,
        android.Manifest.permission.ACCESS_COARSE_LOCATION,
        null, // scheduler that defines thread, null means run on main thread
        receiverFlags
);

これらのレシーバにブロードキャストを送信できるようにするには、送信側アプリが次のように権限をリクエストする必要があります。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

同じプロセス内のブロードキャストを回避する

ブロードキャストは、異なるアプリ間、またはシステムとアプリ間でメッセージを送信するためのプロセス間通信(IPC)メカニズムとして設計されています。すべてのレシーバがブロードキャストを送信したのと同じプロセスで実行されるブロードキャストであるセルフ ブロードキャストを送信することは、非常に非効率的で、不要なシステム オーバーヘッドが発生するため、強く推奨されません。

アプリがブロードキャストを自分自身に送信する一般的なシナリオは次の 2 つです。

  • 同じプロセス内のコンポーネント間の通信: たとえば、アクティビティ、フラグメント、サービス、バックグラウンド スレッド間でイベントやデータを渡す場合。ブロードキャストを送信する代わりに、オブザーバー パターンやリアクティブ ストリームなどの標準のプロセス内通信メカニズムを使用します。

    • Kotlin Flow(SharedFlow と StateFlow): アプリのコルーチンとコンポーネント間でイベント ストリームや状態の更新を送信および監視するための、Kotlin の最新の慣用的なソリューション。
    • 共有 ViewModel: 同じアクティビティ内の異なる UI コンポーネント(フラグメントやコンポーザブルなど)間でデータとイベントの共有を容易にします。
    • コールバックとリスナー: コンポーネント間で直接渡されるか、中央リポジトリまたはコントローラに登録される標準インターフェース コールバックまたは関数参照。
  • システム イベント、ジョブ、アラームの処理: たとえば、スケジュールされたジョブ、アラーム、システム コールバックを受信し、ブロードキャストを送信して実際の作業をトリガーします。ブロードキャストを送信する代わりに、そのジョブ内で直接作業を完了します(JobService または WorkManager ワーカー、アラーム ハンドラ、システム コールバック コンポーネントなど)。または、アプリのビジネス ロジック クラスに直接委任します。

Android 17 QPR2 以降を搭載したデバイスでは、送信プロセスに返してメインスレッドで独自のレシーバに配信することで、システムがセルフ ブロードキャストをより効率的に配信します。セルフブロードキャストを送信しても、プロセスの重要度は上がらず、キャッシュに保存されたプロセスがフリーズするのを防ぐこともできません。そのため、アプリを動作させたり、バックグラウンドで作業を行ったりするためにセルフブロードキャストに依存しないでください。この最適化を行っても、セルフ ブロードキャストはプロセス内通信メカニズムよりも効率が低いため、代わりにこれらの代替手段を使用してください。

アプリ コンポーネント間の通信の設計について詳しくは、アプリ アーキテクチャ ガイドをご覧ください。

セキュリティ上の考慮事項

ブロードキャストの送信と受信に関するセキュリティ上の考慮事項は次のとおりです。

  • マニフェストで同じブロードキャストを受信するように登録しているアプリが多数ある場合、システムが多数のアプリを起動し、デバイスのパフォーマンスとユーザー エクスペリエンスの両方に大きな影響を与える可能性があります。これを回避するには、マニフェスト宣言よりもコンテキスト登録を使用することをおすすめします。Android システム自体が、コンテキスト登録済みレシーバの使用を強制する場合もあります。たとえば、CONNECTIVITY_ACTION ブロードキャストは、コンテキスト登録済みのレシーバにのみ配信されます。

  • 暗黙的インテントを使用して機密情報をブロードキャストしないでください。ブロードキャストを受信するように登録したアプリは、この情報を読み取ることができます。ブロードキャストを受信できるレシーバーを制御するには、次の 3 つの方法があります。

    • ブロードキャストの送信時に権限を指定できます。
    • Android 4.0(API レベル 14)以降では、ブロードキャストを送信するときに setPackage(String) でパッケージを指定できます。システムは、ブロードキャストをパッケージに一致するアプリのセットに制限します。
  • レシーバを登録すると、どのアプリでも悪意のあるブロードキャストをアプリのレシーバに送信できるようになります。アプリが受信するブロードキャストを制限する方法はいくつかあります。

    • ブロードキャストのレシーバーを登録する際に、権限を指定できます。
    • マニフェストで宣言されたレシーバの場合、マニフェストで android:exported 属性を「false」に設定できます。レシーバはアプリ外のソースからのブロードキャストを受信しません。
  • ブロードキャスト アクションの名前空間はグローバルです。アクション名などの文字列は、所有している Namespace に記述してください。そうしないと、他のアプリと意図せず競合する可能性があります。

  • レシーバの onReceive(Context, Intent) メソッドはメインスレッドで実行されるため、迅速に実行して返す必要があります。長時間実行される作業を行う必要がある場合は、onReceive() が戻った後にシステムがプロセス全体を強制終了する可能性があるため、スレッドの生成やバックグラウンド サービスの開始には注意してください。詳細については、プロセス状態への影響をご覧ください。長時間実行される作業を行うには、次のことをおすすめします。

    • 受信側の onReceive() メソッドで goAsync() を呼び出し、BroadcastReceiver.PendingResult をバックグラウンド スレッドに渡します。これにより、onReceive() から戻った後もブロードキャストがアクティブな状態を維持します。ただし、このアプローチでも、システムはブロードキャストを非常に迅速に(10 秒以内)終了することを想定しています。ただし、メインスレッドのグリッチを回避するために、処理を別のスレッドに移動することはできます。
    • JobScheduler を使用してジョブのスケジュールを設定します。詳細については、インテリジェント ジョブ スケジューリングをご覧ください。
  • ブロードキャスト レシーバからアクティビティを開始しないでください。ユーザー エクスペリエンスが損なわれます。特に、レシーバが複数ある場合は、その傾向が顕著になります。代わりに、通知を表示することを検討してください。