Skip to content

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
// 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
// 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
// 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 に実装を追加:

kotlin
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を修正:

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)

csharp
RegisterReceiver(broadcastReceiver, intentFilter, ReceiverFlags.Exported);

ライブラリ固有の問題解決(Tuya例)

方法1: ライブラリのバージョンアップ

build.gradleの依存関係を更新:

gradle
implementation 'com.thingclips.smart:thingclips-smart:6.1.0' // 最新版確認必須

更新後プロジェクトをクリーン:

bash
./gradlew clean build

方法2: ローカルブロードキャストの使用

アプリ内通信用であればLocalBroadcastManagerを代替利用:

kotlin
LocalBroadcastManager.getInstance(this)
    .registerReceiver(broadcastReceiver, intentFilter)

ライブラリ利用時の注意点

  1. AndroidManifest.xml内の<receiver>要素にandroid:exported属性を明記
  2. サードパーティライブラリの更新ノートを必ず確認
  3. 最新版で問題が解決しない場合はライブラリ側のIssueトラッカーを調査

根本原因と背景

Android 14ではブロードキャストレシーバの意図しない外部公開を防ぐため、新たな要件が追加されました:

  1. 動的登録レシーバ: コードで登録される全レシーバにフラグ必須
  2. 静的登録レシーバ: AndroidManifest.xml<receiver>android:exported属性必須
  3. システムブロードキャスト専用レシーバ以外は全て対象

この変更はマルウェアによる悪意あるインテント傍受を防止するセキュリティ向上策です。公式ドキュメント:Android 14 行動変化

ベストプラクティス

  1. アプリ内通信にはRECEIVER_NOT_EXPORTEDを優先使用
  2. 他アプリとの連携時は必要なパーミッションを明記
  3. ブロードキャストの代替手段を検討(LocalBroadcastManagerWorkManager
  4. BroadcastReceiverの登録解除を忘れずに実装
  5. ターゲットSDKバージョンごとに対応方法をテスト

これらの解決策を適用することで、Android 14環境でのブロードキャストレシーバ関連のクラッシュを効果的に防止できます。ライブラリ利用時は提供元の最新情報を常に確認し、セキュリティ要件を満たした実装を行いましょう。