Android 14 BroadcastReceiverの登録エラー解決
問題説明
Android 14 (APIレベル34) 以降でBroadcastReceiver
を登録する際、次のランタイムエラーが発生します:
「One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified...」
このエラーは、Tuyaのcom.thingclips.smart
ライブラリ(バージョン5.1.0)等を使用するアプリケーションで発生します。根本原因はAndroid 14のセキュリティ強化により、動的に登録されるBroadcastReceiverにRECEIVER_EXPORTED
またはRECEIVER_NOT_EXPORTED
フラグの明示的な指定が必須となったことです。
解決方法
✅ 基本解決策:フラグの明示的な指定
Android 13(Tiramisu/API 33)以降を対象とする場合、registerReceiver()
呼び出し時にセキュリティフラグを指定します:
// Kotlin実装例
val intentFilter = IntentFilter("YOUR_ACTION_NAME")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// 他のアプリからのブロードキャストを受信する場合
registerReceiver(broadcastReceiver, intentFilter, RECEIVER_EXPORTED)
// アプリ内のみで完結する場合
// registerReceiver(broadcastReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
} else {
@Suppress("UnspecifiedRegisterReceiverFlag")
registerReceiver(broadcastReceiver, intentFilter)
}
// Java実装例
IntentFilter filter = new IntentFilter("YOUR_ACTION_NAME");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// 他のアプリからの受信許可
registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
} else {
registerReceiver(receiver, filter);
}
✅ バージョン分岐不要の実装
ContextCompat
を使うとAPIレベル分岐が不要になります:
// Kotlin
ContextCompat.registerReceiver(
context,
broadcastReceiver,
intentFilter,
ContextCompat.RECEIVER_EXPORTED // または RECEIVER_NOT_EXPORTED
)
❗ フラグ選択の基準
フラグ | 用途 | セキュリティリスク |
---|---|---|
RECEIVER_EXPORTED | 他アプリからのブロードキャストを受信 | 中(適切なパーミッション管理が必要) |
RECEIVER_NOT_EXPORTED | 自アプリ内のみの通信 | 低(推奨) |
重要
アプリの機能上必要な場合を除き、RECEIVER_NOT_EXPORTED
の使用が推奨されます。不要な外部公開はセキュリティ脆弱性の原因となります。
クロスプラットフォーム対応
React Native
MainApplication.kt
または MainActivity.kt
に実装を追加:
import android.content.BroadcastReceiver
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
class MainActivity : ReactActivity() {
override fun registerReceiver(
receiver: BroadcastReceiver?,
filter: IntentFilter?
): Intent? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
super.registerReceiver(receiver, filter, RECEIVER_EXPORTED)
} else {
super.registerReceiver(receiver, filter)
}
}
}
Ionic/Capacitor
MainActivity.java
を修正:
public class MainActivity extends BridgeActivity {
@Override
public Intent registerReceiver(
@Nullable BroadcastReceiver receiver,
IntentFilter filter
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
} else {
return super.registerReceiver(receiver, filter);
}
}
}
Android .NET (Xamarin)
RegisterReceiver(broadcastReceiver, intentFilter, ReceiverFlags.Exported);
ライブラリ固有の問題解決(Tuya例)
方法1: ライブラリのバージョンアップ
build.gradle
の依存関係を更新:
implementation 'com.thingclips.smart:thingclips-smart:6.1.0' // 最新版確認必須
更新後プロジェクトをクリーン:
./gradlew clean build
方法2: ローカルブロードキャストの使用
アプリ内通信用であればLocalBroadcastManager
を代替利用:
LocalBroadcastManager.getInstance(this)
.registerReceiver(broadcastReceiver, intentFilter)
ライブラリ利用時の注意点
AndroidManifest.xml
内の<receiver>
要素にandroid:exported
属性を明記- サードパーティライブラリの更新ノートを必ず確認
- 最新版で問題が解決しない場合はライブラリ側のIssueトラッカーを調査
根本原因と背景
Android 14ではブロードキャストレシーバの意図しない外部公開を防ぐため、新たな要件が追加されました:
- 動的登録レシーバ: コードで登録される全レシーバにフラグ必須
- 静的登録レシーバ:
AndroidManifest.xml
の<receiver>
にandroid:exported
属性必須 - システムブロードキャスト専用レシーバ以外は全て対象
この変更はマルウェアによる悪意あるインテント傍受を防止するセキュリティ向上策です。公式ドキュメント:Android 14 行動変化
ベストプラクティス
- アプリ内通信には
RECEIVER_NOT_EXPORTED
を優先使用 - 他アプリとの連携時は必要なパーミッションを明記
- ブロードキャストの代替手段を検討(
LocalBroadcastManager
やWorkManager
) BroadcastReceiver
の登録解除を忘れずに実装- ターゲットSDKバージョンごとに対応方法をテスト
これらの解決策を適用することで、Android 14環境でのブロードキャストレシーバ関連のクラッシュを効果的に防止できます。ライブラリ利用時は提供元の最新情報を常に確認し、セキュリティ要件を満たした実装を行いましょう。