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

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

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

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

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

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

Объект Intent содержит сообщение. Строка action определяет произошедшее событие, например android.intent.action.AIRPLANE_MODE. Намерение также может содержать дополнительную информацию, включенную в его дополнительное поле. Например, намерение 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. В файле сборки на уровне модуля приложения укажите версию 1.9.0 или более позднюю библиотеки AndroidX Core:

    Классный

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

Создание composable-функций с отслеживанием и без отслеживания состояния

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

Рекомендуется разделять composable-функции на версии с сохранением состояния и без него. Поэтому мы рекомендуем вынести создание широковещательного приемника из 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>
    

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

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

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

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

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

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

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

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

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

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

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

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