ブロードキャストの概要

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

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

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

ブロードキャストの送受信に関するセキュリティ上の考慮事項を次に示します。

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

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

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

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

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

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