Широковещательные рассылки

Приложения для Android отправляют и получают широковещательные сообщения от системы Android и других приложений для Android, используя шаблон проектирования издатель-подписчик. Система и приложения обычно отправляют широковещательные сообщения при определенных событиях. Например, система Android отправляет широковещательные сообщения при возникновении различных системных событий, таких как загрузка системы или зарядка устройства. Приложения также отправляют специальные широковещательные сообщения, например чтобы уведомить другие приложения о чем-то, что может быть им интересно (например, о скачивании новых данных).

Приложения могут регистрироваться для получения определенных трансляций. Когда отправляется широковещательное сообщение, система автоматически пересылает его приложениям, которые подписаны на получение сообщений этого типа.

В целом трансляции можно использовать как систему обмена сообщениями между приложениями и вне обычного пользовательского процесса. Однако следует помнить, что злоупотребление возможностью отвечать на широковещательные сообщения и запускать фоновые задачи может привести к снижению производительности системы.

Системные широковещательные рассылки

Система автоматически отправляет широковещательные сообщения при возникновении различных системных событий, например при включении и выключении режима полета. Все приложения, подписанные на эти трансляции, получают их.

Объект Intent содержит сообщение трансляции. Строка action определяет произошедшее событие, например android.intent.action.AIRPLANE_MODE. Намерение также может содержать дополнительную информацию, объединенную в поле extra. Например, намерение Airplane Mode включает логическое дополнительное значение, которое указывает, включен или выключен режим полета.

Подробнее о том, как читать намерения и получать строку действия из намерения, рассказывается в разделе Намерения и фильтры намерений.

Действия с системной широковещательной рассылкой

Полный список системных действий трансляции можно найти в файле BROADCAST_ACTIONS.TXT в Android SDK. Каждому действию трансляции соответствует постоянное поле. Например, значение константы 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) или более поздней версии, система не включает SSID, BSSID, информацию о подключении или результаты сканирования в широковещательные передачи Wi-Fi. Чтобы получить эту информацию, вместо этого вызовите метод getConnectionInfo().

Android 8.0

Начиная с Android 8.0 (уровень API 26) система накладывает дополнительные ограничения на приемники, объявленные в манифесте.

Если ваше приложение предназначено для Android 8.0 или более поздней версии, вы не можете использовать манифест, чтобы объявить приемник для большинства неявных широковещательных передач (передач, которые не предназначены специально для вашего приложения). Вы по-прежнему можете использовать приемник, зарегистрированный в контексте, когда пользователь активно использует ваше приложение.

Android 7.0

В Android 7.0 (уровень API 24) и более поздних версиях не отправляются следующие системные широковещательные сообщения:

Кроме того, приложения, предназначенные для Android 7.0 и более поздних версий, должны регистрировать трансляцию CONNECTIVITY_ACTION с помощью registerReceiver(BroadcastReceiver, IntentFilter). Объявление получателя в манифесте не работает.

Получать трансляции

Приложения могут получать широковещательные передачи двумя способами: через приемники, зарегистрированные в контексте, и приемники, объявленные в манифесте.

Приемники, зарегистрированные в контексте

Приемники, зарегистрированные в контексте, получают широковещательные передачи, пока действителен контекст, в котором они зарегистрированы. Обычно это происходит между вызовами registerReceiver и unregisterReceiver. Контекст регистрации также становится недействительным, когда система уничтожает соответствующий контекст. Например, если вы зарегистрируетесь в контексте Activity, то будете получать широковещательные передачи, пока активность остается активной. Если вы зарегистрируетесь с контекстом приложения, то будете получать широковещательные сообщения, пока приложение запущено.

Чтобы зарегистрировать получатель с контекстом, выполните следующие действия:

  1. В файл сборки на уровне модуля приложения добавьте библиотеку AndroidX Core версии 1.9.0 или более поздней:

    Классный

    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"
    }

    Котлин

    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). Обязательно отмените регистрацию получателя, когда он больше не нужен или контекст становится недействительным.

Отмените регистрацию широковещательного приемника

Пока широковещательный приемник зарегистрирован, он хранит ссылку на контекст, в котором он был зарегистрирован. Это может привести к утечкам, если зарегистрированная область получателя превышает область действия жизненного цикла контекста. Например, это может произойти, если вы зарегистрируете приемник в области действия Activity, но забудете отменить его регистрацию, когда система уничтожит Activity. Поэтому всегда отменяйте регистрацию широковещательного приемника.

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: широковещательный приемник получает обновления, только когда composable-функция находится в дереве композиции. Эта область действия не связана с областью действия жизненного цикла объекта activity. Рекомендуем зарегистрировать получателя в контексте приложения. Это связано с тем, что composable-функция может теоретически пережить область действия жизненного цикла объекта activity и привести к утечке Activity.
  • Activity onCreate/onDestroy: широковещательный приемник получает обновления, пока Activity находится в созданном состоянии. Отмените регистрацию в onDestroy(), а не в onSaveInstanceState(Bundle), поскольку последний метод может не вызываться.
  • Специальная область действия. Например, вы можете зарегистрировать приемник в области действия ViewModel, чтобы он пережил воссоздание активности. При регистрации получателя используйте контекст приложения, поскольку получатель может существовать дольше, чем жизненный цикл действия, и привести к утечке памяти.

Как создавать компоненты с состоянием и без него

В Compose есть composable-функции с состоянием и без него. Регистрация или отмена регистрации широковещательного приемника внутри composable-функции делает его с отслеживанием состояния. Composable-функция не является детерминированной функцией, которая при передаче одинаковых параметров отрисовывает один и тот же контент. Внутреннее состояние может меняться в зависимости от вызовов зарегистрированного приемника широковещательных сообщений.

В 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>
    

    Фильтры intent указывают, на какие широковещательные действия подписан приемник.

  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() получателя. Система выполняет процесс, за исключением случаев, когда памяти критически не хватает.

Система деактивирует BroadcastReceiver через onReceive(). Значимость хост-процесса получателя зависит от компонентов приложения. Если в этом процессе размещен только приемник, объявленный в манифесте, система может завершить его через onReceive(), чтобы освободить ресурсы для других более важных процессов. Это часто происходит с приложениями, которыми пользователь никогда не пользовался или не пользовался в последнее время.

Поэтому приемники широковещательных передач не должны запускать длительные фоновые потоки. Система может остановить процесс в любой момент после onReceive(), чтобы освободить память, завершив созданный поток. Чтобы процесс не завершился, запланируйте JobService от получателя с помощью JobScheduler, чтобы система знала, что процесс ещё выполняется. Подробнее о фоновых задачах…

Отправка трансляций

В Android есть два способа отправки широковещательных сообщений:

  • Метод sendOrderedBroadcast(Intent, String) отправляет широковещательные сообщения одному получателю за раз. Поскольку каждый получатель выполняется по очереди, он может передать результат следующему получателю. Также можно полностью прервать трансляцию, чтобы она не дошла до других приемников. Вы можете управлять порядком выполнения получателей в рамках одного процесса приложения. Для этого используйте атрибут android:priority соответствующего фильтра intent. Приемники с одинаковым приоритетом запускаются в произвольном порядке.
  • Метод 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) и позволяют отправлять сообщения между разными приложениями или между системой и приложениями. Отправка широковещательной рассылки, в которой все получатели работают в том же процессе, что и отправитель, очень неэффективна, создает ненужную системную нагрузку и настоятельно не рекомендуется.

Приложения отправляют трансляции самим себе в двух распространенных случаях:

  • Обмен данными между компонентами в одном процессе. Например, передача событий или данных между действиями, фрагментами, сервисами или фоновыми потоками. Вместо отправки широковещательных сообщений используйте стандартные механизмы связи в процессе, такие как шаблон наблюдателя или реактивные потоки:

    • Потоки Kotlin (SharedFlow и StateFlow). Современное и идиоматичное решение на Kotlin для передачи и отслеживания потоков событий или обновлений состояния между сопрограммами и компонентами в приложении.
    • Общий ViewModel позволяет обмениваться данными и событиями между разными компонентами интерфейса (например, фрагментами или композициями) в рамках одного действия.
    • Обратные вызовы и прослушиватели. Стандартные обратные вызовы интерфейса или ссылки на функции, передаваемые непосредственно между компонентами или зарегистрированные в центральном хранилище или контроллере.
  • Обработка системных событий, заданий или запланированных операций. Например, получение запланированного задания, запланированной операции или системного обратного вызова и отправка широковещательной рассылки для запуска фактической работы. Вместо отправки широковещательного сообщения выполните работу непосредственно в задаче (например, в JobService или WorkManager), обработчике оповещений или системном компоненте обратного вызова или делегируйте ее классам бизнес-логики приложения.

На устройствах с Android 17 QPR2 или более поздней версии система более эффективно обрабатывает внутренние трансляции, возвращая их в процесс отправки, который передает их собственным получателям в основном потоке. Отправка собственного широковещательного сообщения не повышает важность процесса и не предотвращает заморозку кешированного процесса, поэтому не полагайтесь на собственные широковещательные сообщения, чтобы поддерживать работу приложения или выполнять задачи в фоновом режиме. Даже с этой оптимизацией саморассылки менее эффективны, чем механизмы связи в процессе, поэтому используйте эти альтернативы.

Подробнее о том, как организовать взаимодействие между компонентами приложения, рассказывается в руководстве по архитектуре приложений.

Безопасность

Вот несколько советов по обеспечению безопасности при отправке и получении трансляций:

  • Если в манифесте многих приложений указано, что они должны получать одну и ту же широковещательную передачу, система может запустить большое количество приложений, что существенно повлияет на производительность устройства и удобство работы с ним. Чтобы избежать этого, лучше использовать регистрацию контекста, а не объявление в манифесте. Иногда система Android сама требует использовать приемники, зарегистрированные в контексте. Например, широковещательная передача CONNECTIVITY_ACTION доставляется только зарегистрированным в контексте получателям.

  • Не передавайте конфиденциальную информацию с помощью неявного намерения. Любое приложение может прочитать информацию, если зарегистрируется для получения трансляции. Вы можете настроить доступ к трансляциям тремя способами:

    • При отправке трансляции можно указать разрешение.
    • В Android 4.0 (уровень API 14) и более поздних версиях при отправке широковещательного сообщения можно указать пакет с setPackage(String). Система ограничивает трансляцию набором приложений, которые соответствуют пакету.
  • При регистрации получателя любое приложение может отправлять ему потенциально вредоносные широковещательные сообщения. Ограничить количество трансляций, получаемых приложением, можно несколькими способами:

    • При регистрации широковещательного приемника можно указать разрешение.
    • Для приемников, объявленных в манифесте, можно задать атрибуту android:exported значение "false" в манифесте. Получатель не получает трансляции из источников, не связанных с приложением.
  • Пространство имен для действий трансляции является глобальным. Убедитесь, что названия действий и другие строки написаны в принадлежащем вам пространстве имен. В противном случае вы можете случайно вызвать конфликт с другими приложениями.

  • Поскольку метод onReceive(Context, Intent) получателя выполняется в основном потоке, он должен быстро выполняться и возвращать результат. Если вам нужно выполнить длительную работу, будьте осторожны при создании потоков или запуске фоновых служб, поскольку система может завершить весь процесс после возврата onReceive(). Подробная информация приведена в разделе Влияние на состояние процесса. Чтобы выполнять длительные операции, мы рекомендуем:

    • Вызов метода goAsync() в методе onReceive() получателя и передача объекта BroadcastReceiver.PendingResult в фоновый поток. Это позволит сохранить трансляцию активной после возвращения из onReceive(). Однако даже в этом случае система ожидает, что вы завершите трансляцию очень быстро (менее чем за 10 секунд). Она позволяет перенести работу в другой поток, чтобы избежать сбоев в основном потоке.
    • Планирование задания с помощью JobScheduler. Подробнее об интеллектуальном планировании заданий…
  • Не запускайте действия из приемников широковещательных сообщений, поскольку это может негативно сказаться на удобстве использования, особенно если приемников несколько. Вместо этого можно показывать уведомление.