← Назад к вопросам

Как можно создать Broadcast Receiver который будет слушать внутри приложения?

2.0 Middle🔥 72 комментариев
#Android компоненты

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Создание Broadcast Receiver для внутреннего использования в приложении

Для создания Broadcast Receiver, который будет работать только внутри вашего приложения (без доступа извне), существует несколько подходов. Это важный аспект безопасности и архитектуры приложения, предотвращающий несанкционированный доступ к вашим широковещательным сообщениям.

Основные подходы

1. Локальная широковещательная рассылка через LocalBroadcastManager (устаревший, но все еще встречается)

LocalBroadcastManager был стандартным способом до Android 8.0 (API 26), но сейчас считается устаревшим в пользу более современных методов.

// Регистрация Receiver
val localBroadcastManager = LocalBroadcastManager.getInstance(context)
localBroadcastManager.registerReceiver(myReceiver, IntentFilter("MY_ACTION"))

// Отправка локального broadcast
val intent = Intent("MY_ACTION").apply {
    putExtra("DATA_KEY", "some_data")
}
localBroadcastManager.sendBroadcast(intent)

// Не забыть отписать в onDestroy()
localBroadcastManager.unregisterReceiver(myReceiver)

2. Использование системного BroadcastReceiver с явным указанием пакета (рекомендуемый способ)

Начиная с Android 8.0, для защиты от злоупотреблений, неявные широковещательные сообщения были ограничены. Лучший подход - использовать явные интенты с указанием компонента или ограничение broadcast пакетом.

// В AndroidManifest.xml
<receiver 
    android:name=".MyInternalReceiver"
    android:exported="false"> <!-- Ключевой параметр! -->
    <intent-filter>
        <action android:name="com.example.app.INTERNAL_ACTION" />
    </intent-filter>
</receiver>

// Отправка broadcast с указанием пакета
val intent = Intent("com.example.app.INTERNAL_ACTION").apply {
    `package` = context.packageName // Ограничиваем только нашим приложением
    putExtra("INTERNAL_DATA", "secret_info")
}
context.sendBroadcast(intent)

3. Динамическая регистрация с явным IntentFilter (самый гибкий способ)

class MainActivity : AppCompatActivity() {
    private val internalReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                "INTERNAL_EVENT_1" -> {
                    val data = intent.getStringExtra("DATA")
                    // Обработка события
                }
                "INTERNAL_EVENT_2" -> {
                    // Другая обработка
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Регистрируем receiver для конкретных действий
        val filter = IntentFilter().apply {
            addAction("INTERNAL_EVENT_1")
            addAction("INTERNAL_EVENT_2")
        }
        
        // Регистрируем с контекстом активности
        registerReceiver(internalReceiver, filter)
    }

    override fun onDestroy() {
        super.onDestroy()
        // Важно: всегда отписываться!
        unregisterReceiver(internalReceiver)
    }

    // Метод для отправки внутреннего события
    private fun sendInternalEvent() {
        val intent = Intent("INTERNAL_EVENT_1").apply {
            putExtra("DATA", "Internal data")
        }
        sendBroadcast(intent)
    }
}

4. Использование LiveData или Flow + ViewModel для коммуникации внутри приложения

Для полностью внутренней коммуникации в современных Android-приложениях часто используют архитектурные компоненты вместо BroadcastReceiver:

class EventBusViewModel : ViewModel() {
    private val _internalEvents = MutableSharedFlow<String>()
    val internalEvents = _internalEvents.asSharedFlow()

    suspend fun sendEvent(event: String) {
        _internalEvents.emit(event)
    }
}

// В Activity/Fragment
lifecycleScope.launch {
    viewModel.internalEvents.collect { event ->
        when (event) {
            "USER_LOGGED_IN" -> updateUI()
            "DATA_LOADED" -> showData()
        }
    }
}

Ключевые рекомендации

  1. Всегда устанавливайте android:exported="false" для ресиверов в манифесте, если они не предназначены для внешнего использования
  2. Используйте явные интенты с указанием конкретного класса-получателя или пакета приложения
  3. Не забывайте отписываться от динамически зарегистрированных ресиверов в соответствующих методах жизненного цикла
  4. Рассмотрите альтернативы BroadcastReceiver для внутренней коммуникации:
    • SharedFlow/MutableSharedFlow из Kotlin Coroutines
    • LiveData и ViewModel для UI-слоя
    • Событийные шины на основе RxJava или Kotlin Flow
  5. Будьте внимательны к версии Android - политики безопасности меняются, особенно после Android 8.0

Пример безопасного внутреннего Receiver

class SecureInternalReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Проверяем, что broadcast пришел из нашего приложения
        if (intent.`package` != context.packageName) {
            return // Игнорируем внешние вызовы
        }
        
        // Проверяем подпись (для дополнительной безопасности)
        val callingUid = Binder.getCallingUid()
        if (callingUid != Process.myUid()) {
            return // Не наш процесс
        }
        
        // Безопасная обработка
        handleInternalEvent(intent)
    }
    
    private fun handleInternalEvent(intent: Intent) {
        // Ваша логика обработки
    }
}

Выбор конкретного подхода зависит от требований вашего приложения, но для чисто внутренней коммуникации в современных приложениях часто предпочтительнее использовать архитектурные компоненты или Kotlin Flow вместо классических BroadcastReceiver.

Как можно создать Broadcast Receiver который будет слушать внутри приложения? | PrepBro