🐈

AndroidでBroadcastReceiverを使う際に引っかかった事

に公開

私が Android の BroadcastReceiver を使う際に引っかかった2つのポイントをまとめます。

結論

  • レシーバーをコンテキストから登録する際にflagにRECEIVER_NOT_EXPORTEDを指定する場合はsendBroadcastをする際にIntentにsetPackageを指定しないと受け取れない
  • AndroidManifestからReceiverを登録する際はintent-filterを指定しないと受け取れない

1. コンテキストからレシーバーを登録(プログラムから登録)する際に引っかかった点

こんな感じで BroadcastReceiver を作成して登録したとします。

val serviceReceiver =
object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Handle the broadcast message here
        println("onReceive")
        if(intent.action == SampleService.ACTION_RESULT) {
            val status = intent.getStringExtra(SampleService.PROCESS_STATUS)
            println("Received broadcast: $status")
        }
    }
}

/// 省略

override fun onResume() {
    super.onResume()
    val filter = IntentFilter(SampleService.ACTION_RESULT)
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        registerReceiver(serviceReceiver, filter, RECEIVER_NOT_EXPORTED)
    } else {
        registerReceiver(serviceReceiver, filter)
    }
}

// 渡すのユースケースではServiceの処理の結果を受け取るためにsendBroadcastを呼び出す
sendBroadcast(
    Intent().apply {
        action = ACTION_RESULT
        putExtra(PROCESS_STATUS, "success")
    }
)

そしてsendBroadcastで送信して受け取ろうとしたのですが、受け取れませんでした。
原因としてはsendBroadcastを送る際にsetPackageを呼び出していなかったことが原因でした。

sendBroadcast(
    Intent().apply {
        action = ACTION_RESULT
        putExtra(PROCESS_STATUS, "test")
        setPackage("com.example.hogehoge")
    }
)

また、registerReceiverを呼び出してレシーバーを登録する際の第3引数のフラグをRECEIVER_EXPORTEDを設定する事でも呼び出されるように修正する事もできる
おそらくこのあたりのドキュメントが関係していそう
https://developer.android.com/privacy-and-security/risks/sticky-broadcast?hl=ja

2.AndroidManifestからレシーバーを登録する際に引っかかった点

intent-filterをAndroidManifestから登録する際に指定しないとsendBroadcastを呼び出そうとしてonReceiveが呼ばれませんでした。
これは私の思い込みなのですが、filterという名前的に別に指定しなくても動くと思い込んでいたので詰まってしまいました。

そのため以下のようにintent-filterを指定する必要がありました。

<receiver android:name=".MyReceiver" android:exported="false">
    <intent-filter>
        <action android:name="com.example.backgroundservicewithbroadcast.SampleService.RESULT" />
    </intent-filter>
</receiver>

まとめ

思い込みはよくない

Discussion