Receive boot broadcast что это
Автозапуск приложения при загрузке
Тема получения сообщения ACTION_BOOT_COMPLETED остается актуальной и по сей день. Многие новички сталкиваются с проблемой: они не получают в своих приложениях данное сообщение.
Можно выделить следующие правила:
В манифесте указать разрешение:
В манифесте в блоке application зарегистрировать приёмник на приём сообщения ACTION_BOOT_COMPLETED:
В описании без необходимости не указывайте атрибуты «enabled», «exported» и т.д. Вполне достаточно настроек и атрибутов по умолчанию.
Код вашего широковещательного приёмника:
Если ваш приёмник используется только для сообщения ACTION_BOOT_COMPLETED, то проверка «if» не обязательна. Однако иногда разработчики используют один и тот же ресивер для разных сообщений. В этом случае фильтруйте сообщения, проверяя их внутри метода onReceive().
Приложение должно быть установлено на внутреннюю память. Android устроена таким образом, что сообщение ACTION_BOOT_COMPLETED отправляется приложениям перед монтированием внешний памяти. Поэтому приложения, установленные на внешней памяти, никогда не получат это сообщение. Чтобы указать системе не устанавливать приложение на внешнюю память, в манифесте НЕ нужно прописывать для атрибута «@android:installLocation» значения «auto» или «preferExternal». По умолчанию, т.е. если этот атрибут не указан, Android установит ваше приложение только на внутреннюю память. Однако согласно официальной документации лучше явно указать значение «internalOnly», чтобы у вас и других разработчиков не возникло искушение в будущем указать иное значение.
После установки или принудительной остановки (force stop) приложение должно быть запущено хотя бы один раз, чтобы система «запомнила» это приложение для отправки ему сообщения ACTION_BOOT_COMPLETED. Такое поведение было реализовано в версии Android 3.1 в целях безопасности. В чем суть? Все только что установленные приложения находятся в состоянии «stopped» (не путать с активити, т.к. система управляет этим состоянием у приложений и активностей по-разному). В это же состояние приложение «уходит», когда пользователь в настройках телефона принудительно его останавливает. Пока приложение находится в таком состоянии, оно не будет запущено системой ни по какой причине (например, через ACTION_BOOT_COMPLETED), исключая, конечно же, запуск самим пользователем. Благодаря такому нововведению немалая часть вирусов и троянцев» перестала работать, т.к. уже нет возможности запуститься автоматом после установки.
Исключение составляют системные приложения.
Особенности режима Fast boot в HTC-устройствах: Известно, что HTC-устройства не перезагружаются в классическом смысле, а используют так называемый режим Fast boot (это одна из форм гибернации), сохраняя состояние ОС на диск. Поэтому сообщение ACTION_BOOT_COMPLETED не отправляется системой, т.к. в действительности перезагрузка не происходит. Вместо ACTION_BOOT_COMPLETED система может отправить следующие сообщения:
В вашем приложении укажите в теге «receiver» кроме ACTION_BOOT_COMPLETED также вышеуказанные сообщения. Кроме этого необходимо прописать дополнительное разрешение:
Практика: ошибки и особенности эксплуатации
Разберём ошибки, которые совершают новички при настройке приложения и в коде.
Отладка ресивера в эмуляторе и на реальных устройствах
В терминале выполните:
Далее, чтобы отправить ACTION_BOOT_COMPLETED всем приложениям, наберите в терминале:
Или для отправки ACTION_BOOT_COMPLETED конкретному приложению наберите в терминале:
В эмуляторе: установите ваше ПО, запустив его из студии. При этом студия соберет ваш проект, установит приложение и запустит его. После этого закройте эмулятор (это аналогично выключению на реальном устройстве). Чтобы получить сообщение ACTION_BOOT_COMPLETED, запустите эмулятор из AVD-менеджера, а не с помощью кнопки «Run app» в студии.
После запуска эмулятора во вкладке Android Monitor укажите запущенный эмулятор и ваше приложение, чтобы просмотреть логи logcat.
Итоги
Чтобы ваше приложение запускалось при загрузке на всех устройствах, манифест как минимум должен выглядеть так:
Broadcast (Широковещательные сообщения)
Практическая часть показана в отдельной статье.
Широковещательные сообщения делают приложение более открытым; передавая события, использующие сообщения, вы открываете компоненты своего приложения для сторонних приложений, и сторонние разработчики реагируют на события без необходимости изменять ваше оригинальное приложение. В своём приложении вы можете прослушивать широковещательные сообщения других приложений, заменить или улучшить функциональность собственного (или стороннего) приложения или реагировать на системные изменения и события приложений.
Вы тоже можете организовать отправку широковещательных сообщений, а другие приложения могут обзавестись приёмниками для обработки ваших сообщений.
Приёмник широковещательных сообщений — это компонент для получения внешних событий и реакции на них. Инициализировать передачи могут:
Широковещательные сообщения можно разделить на две группы:
Класс BroadcastReceiver является базовым для класса, в котором должны происходить получение и обработка сообщений, посылаемых клиентским приложением с помощью вызова метода sendBroadcast().
Зарегистрировать экземпляр класса BroadcastReceiver можно динамически в коде или статически в манифесте.
Для статической регистрации в файле манифеста в секции application следует создать секцию receiver и указать класс приёмника. Атрибут android:exported=»true» сообщает получателю, что он может принимать широковещательные сообщения вне области приложения. Внутри секции указывается фильтр намерений в виде строки, чтобы определить, какие сообщения приёмник должен прослушивать.
Если регистрация была сделана через манифест, приложение не обязано работать, чтобы ваш приёмник среагировал на трансляцию намерения. Приложение запустится автоматически, когда подходящие намерение будет транслировано. Система сама сканирует содержимое манифеста всех приложений и делает за нас всю работу. Это хорошее решение, позволяющее экономить ресурсы. Такой подход позволяет создавать приложения, способные реагировать на события даже после завершения или принудительного завершения.
Динамическая регистрация происходит с помощью метода Context.registerReceiver().
Перед этим создаётся класс, расширяющий базовый класс BroadcastReceiver и реализуется метод обратного вызова onReceive() обработчика событий.
Метод onReceive() будет выполнен при получении широковещательного намерения, если полученное намерение соответствует фильтру. Приложения с зарегистрированными приёмниками широковещательных намерений будут запущены автоматически при получении соответствующего намерения. Метод должен быть завершён в течение пяти секунд, иначе появится диалоговое окно о принудительном закрытии.
Когда широковещательное сообщение прибывает для получателя сообщения, Android вызывает его методом onReceive() и передаёт в него объект Intent, содержащий сообщение. Приёмник широковещательных сообщений является активным только во время выполнения этого метода. Процесс, который в настоящее время выполняет BroadcastReceiver, т. е. выполняющийся в настоящее время код в методе обратного вызова onReceive(), как полагает система, является приоритетным процессом и будет сохранён, кроме случаев критического недостатка памяти в системе.
Когда программа возвращается из метода onReceive(), приёмник становится неактивным и система полагает, что работа объекта BroadcastReceiver закончена. Процесс с активным широковещательным получателем защищён от уничтожения системой. Однако процесс, содержащий неактивные компоненты, может быть уничтожен системой в любое время, когда память, которую он потребляет, будет необходима другим процессам.
Это представляет проблему, когда ответ на широковещательное сообщение занимает длительное время. Если метод onReceive() порождает отдельный поток, а затем возвращает управление, то полный процесс, включая и порождённый поток, система Android считает неактивным (если другие компоненты приложения не активны в процессе), и считает этот процесс кандидатом на уничтожение.
В частности, вы не можете отобразить диалог или осуществить связывание со службой внутри экземпляра BroadcastReceiver. Для первого случая необходимо вместо этого использовать методы класса NotificationManager. Во втором случае можно использовать вызов метода Context.startService(), чтобы послать команду для запуска службы.
Решение этой проблемы возможно, если запустить в методе onReceive() отдельную службу вместе с BroadcastReceiver и позволить службе выполнять задание, чтобы сохранить содержание процесса активным в течение всего времени вашей операции.
Также можно зарегистрировать широковещательный приёмник не через манифест, а программно. Приёмник, зарегистрированный таким способом, будет отвечать на поступающие намерения только в том случае, если компонент приложения, которому он принадлежит, выполняется в этот момент.
Это может быть полезным, когда приёмник используется для обновления элементов пользовательского интерфейса внутри активности, запуска служб или уведомления через NotificationManager. В таких случаях вы можете отменять регистрацию широковещательного приёмника, если активность не отображается на экране или находится в неактивном состоянии.
В коде программы можете написать приблизительно такой код (обычно используют метод onResume()):
Для отмены регистрации используется метод unregisterReceiver() в контексте приложения, передавая ему в качестве параметра экземпляр широковещательного приёмника (обычно в методе onPause()):
Для объекта BroadcastReceiver нет никаких возможностей видеть или фиксировать намерения, используемые в методе startActivity(). Аналогично, когда вы передали намерение для запуска активности через объект BroadcastReceiver, вы не сможете найти или запустить требуемую активность. Эти две операции семантически полностью различаются: запуск активности через намерение является приоритетной операцией для системы, изменяющей содержимое экрана устройства, с которым в настоящее время взаимодействует пользователь. Передача широковещательных сообщений для системы является фоновой работой, о которой обычно не знает пользователь и которая, соответственно, имеет более низкий приоритет.
Приёмники системных событий
Android использует широковещательные сообщения для системных событий, таких как уровень зарядки батареи, сетевые подключения, входящие звонки, изменения часового пояса, состояние подключения данных, входящие сообщения SMS или обращения по телефону. Вы можете использовать эти сообщения, чтобы добавлять к вашим собственным проектам новые функциональные возможности, основанные на системных событиях.
Следующий список показывает некоторые из встроенных действий, представленных как константы в классе Intent, которые используются для того, чтобы проследить изменения состояния устройства:
Типы трансляций
Есть три способа отправки трансляций
Если важно, чтобы приёмники получали намерения в определённом порядке или могли влиять на транслируемое намерение, можно использовать метод sendOrderedBroadcast():
С помощью этого метода ваше намерение дойдёт до всех зарегистрированных приёмников, обладающих необходимым доступом (если он был указан), в порядке их приоритета. Приоритет задаётся с помощью атрибута android:priority внутри узла фильтра намерений в манифесте. Чем больше значение, тем выше приоритет.
Производить упорядоченные трансляции с использованием приоритетов рекомендуется только для тех приёмников, которым необходим конкретный порядок приёма сообщений.
Ограничения в Android 8.0 Oreo (API 26)
Часть неявных (implicit) широковещательных сообщений, задаваемых через манифест, запретили. Теперь нужно регистрировать их программно. Существует список исключений, которые будут работать как прежде без ограничений.
В качестве замены для некоторых случаев подойдёт JobScheduler.
Примерами устаревшего способа работы с приёмником является android.net.conn.CONNECTIVITY_CHANGE, ACTION_POWER_CONNECTED и др.
Ограничения в Android 9.0 Pie (API 28)
Стало доступно меньше информации, получаемой при трансляции системы Wi-Fi и Network_State_Changed_Action.
Broadcast (Широковещательные сообщения)
В Android существует понятие широковещательных сообщений, которые можно отправлять или принимать. Оба процесса между собой не связаны и их можно использовать по отдельности.
Передача сообщений
Для начала научимся отправлять сообщения. В одном из уроков мы учились запускать другую активность с помощью намерения Intent. Но намерения можно использовать для отправки сообщений, предназначенные не какому-то отдельному приложению, объекту или компоненту, а всем. И любая программа, оборудованная специальным приёмником, может поймать это сообщение и предпринять свои шаги на основе полученной информации.
Любой человек, имеющий специальный оборудованный радиоприёмник, может принять это сообщение. Так же поступают и программы. Они обзаводятся приёмниками и прослушивают определённый тип сообщений.
Сообщения может создавать сама система, а также ваша программа и чужие программы.
Передача сообщений весьма проста в реализации. В вашем приложении необходимо создать сообщение, которое вы хотите передать. Установите при необходимости поля action, data и category (действие, данные и категорию) вашего сообщения и путь, который позволяет приёмникам широковещательных сообщений точно определять «своё» сообщение. В этом сообщении строка действия ACTION должна быть уникальной, чтобы идентифицировать передаваемое действие. В таких случаях создают строку-идентификатор действия по правилам именования пакетов Java. Например, для обнаружения кота в большом здании:
Далее вы создаёте объект Intent, загружаете в него нужную информацию и вызываете метод sendBroadcast(), передав ему в качестве параметра созданный объект Intent. Дополнительные данные можно использовать в extras как необязательные параметры.
Виртуальный код для обнаружения кота:
В этом примере мы создали намерение с уникальной строкой, передали дополнительные данные (имя кота и его координаты), отправили сообщение. Другое приложение, связанное с картами, может принять сообщение и показать кота на карте.
Существуют также родственные методы sendStickyBroadcast() и sendOrderedBroadcast().
Для старых устройств этого было вполне достаточно, но начиная с Android 3.0, в целях безопасности сообщения будут игнорироваться остановленными приложениями, чтобы они не запускались. Поэтому следует добавлять дополнительный флаг, разрешающий запуск активности.
Мы напишем простой пример, который будет отправлять сообщения и также создадим приёмник для его получения. О приёмнике мы поговорим подробно во второй части урока. А пока получим первое представление о нём.
Создайте новый проект и разместите на экране кнопку с надписью «Отправить сообщение». Присвойте атрибуту onClick название метода, в котором будет происходит отправка широковещательного сообщения.
Запустив пример, вы можете нажать на кнопку и отправлять сообщение. Только ваше сообщение уйдёт в никуда, так как ни одно приложение не оборудовано приёмником для него. Исправим ситуацию и создадим приёмник в своём приложении. Мы будем сами принимать свои же сообщения.
Приёмник представляет собой обычный Java-класс на основе BroadcastReceiver. Вы можете создать вручную класс и наполнить его необходимыми методами. Раньше так и поступали. Но в студии есть готовый шаблон, который поможет немного сэкономить время.
Щёлкаем правой кнопкой мыши на названии пакета и выбираем New | Other | Broadcast Receiver
В диалоговом окне задаём имя приёмника, остальные настройки оставляем без изменений.
Студия создаст изменения в двух местах. Во-первых, будет создан класс MessageReceiver:
Во-вторых, в манифесте будет добавлен новый блок.
В него следует добавить фильтр, по которому он будет ловить сообщения.
Вернёмся в класс приёмника и модифицируем метод onReceive().
Снова запустим пример и ещё раз отправим сообщение. Так как наше приложение теперь оборудовано не только передатчиком, но и приёмником, то оно должно уловить сообщение и показать его нам.
Вы можете создать другое приложение с приёмником, чтобы одно приложение посылало сообщение, а другое принимало.
Приёмники широковещательных сообщений
Вот плавно мы перешли к приёмникам широковещательных сообщений. На самом деле вам не так часто придётся рассылать сообщения, гораздо чаще встречается потребность принимать сообщения. В первую очередь, сообщения от системы. Примерами таких сообщений могут быть:
Приёмник, созданный программно, может работать только в том случае, когда активность вашего приложения активна. Казалось, это является недостатком и нет смысла использовать такой подход. Но всё не так просто. Некоторые системные сообщения могут обрабатываться только приёмниками, созданными программно. И в этом есть свой резон. Например, если ваше приложение не запущено, ему нет смысла принимать сообщения о заряде батареи. Иначе заряд батареи будет расходоваться ещё быстрее при лишней бесполезной работе. Информацию о заряде батареи ваше приложение может получить, когда в этом есть необходимость. Следует сверяться с документацией, какой вид приёмника следует использовать.
При программной регистрации приёмника мы можем также снять регистрацию, когда больше не нуждаемся в нём с помощью метода unregisterBroadcastReceiver().
Периодическое срабатывание каждую минуту
Рассмотрим пример периодического срабатывания приёмника каждую минуту с помощью системного намерения android.intent.action.TIME_TICK. Приёмник будет создан программно. Добавим на экран активности две кнопки для регистрации и отмены регистрации широковещательного сообщения.
Создадим вручную новый класс TimeBroadcastReceiver, наследующий от BroadcastReceiver:
Вы можете создать класс приёмника и через шаблон, как мы это сделали в предыдущем примере. Но в этом случае удалите запись о нём в манифесте, так как нам он не понадобится. Но если вы забудете сделать это, то ничего страшного не произойдёт, так как там не прописаны фильтры.
Откроем код главной активности и зарегистрируем (а также снимем регистрацию) приёмник:
Запускаем проект и нажимаем на первую кнопку, чтобы включить рассылку широковещательного сообщения. Теперь каждую минуту будет срабатывать запуск всплывающего сообщения с текущим временем. Даже если вы переключитесь на другое приложение, то всё равно будете видеть сообщения.
Это один из примеров, когда приёмник следует регистрировать программно. Я видел часто на форумах вопросы, почему не работает данное намерение android.intent.action.TIME_TICK. А не надо было его регистрировать в манифесте.
В нашем примере мы устанавливали и снимали регистрацию через нажатия кнопок. Обычно включают регистрацию в методе onResume(), а снимают регистрацию в методе onPause().
Необходимо помнить, что программная регистрация широковещательного сообщения создаётся в основном потоке приложения и это может послужить источником ошибок, если операции в BroadcastReceiver занимают длительное время. Как вариант, используйте сервисы. Почитайте на эту тему статью (en).
TIME_TICK на Kotlin
Напишем похожий пример на Kotlin. Разместите на экране TextView, в котором будет отображаться время. Код для активности ниже. Обратите внимание, что мы не создаём отдельный класс для BroadcastReceiver, включаем регистрацию в onResume() и снимаем регистрацию в onPause().
Автостарт Activity или Service при загрузке (перезагрузке) девайса
Ещё один полезный пример, который часто используется приложениями.
Если ваше приложение (сервис) должно запускаться сразу после перезагрузки устройства, то используйте намерение android.intent.action.BOOT_COMPLETED:
Мы создали отдельный класс для широковещательного сообщения. Также нужно создать разрешение и зарегистрировать приёмник в манифесте.
Следим за питанием
Нет, речь пойдёт не о правильном питании кота. Имеется в виду питание от электричества. Если ваше устройство отключить от зарядки, то система оповещает об этом событии через широковещательное намерение android.intent.action.ACTION_POWER_DISCONNECTED.
Не станем заводить новый приёмник, а откроем манифест и добавим дополнительный фильтр к приёмнику сообщений от радистки Кэт.
А в классе MessageReceiver добавим код для метода.
Пример нужно проверять на реальном устройстве. Подключите устройство к питанию, а затем выдерните кабель. На экране появится сообщение.
Android Broadcast Receivers для начинающих
Перевод статьи на Медиуме о технологии Broadcast Receivers (широковещательные приемники). Это компоненты андроид, которые отслеживают широковещательные сообщения (broadcast messages) или события (events).
Для чего нужны Broadcast Receivers?
Допустим, у вас есть приложение, которое зависит от постоянного интернет-соединения. Вы хотите, чтобы ваше приложение получало уведомление при изменении интернет-соединения. Как это сделать? Возможным решением будет сервис, который всегда проверяет интернет-соединение. Эта реализация плоха по разным причинам, поэтому мы не будем ее рассматривать. Решением этой проблемы является широковещательный приемник (Broadcast Receiver), который прослушивает изменения, о которых вы сообщаете. Получатель трансляции всегда будет получать уведомления о трансляции, независимо от состояния вашего приложения. Неважно, работает ли ваше приложение в фоновом режиме или вообще не работает.
Теория Broadcast Receivers
Широковещательные приемники — это компоненты в вашем приложении Android, которые прослушивают широковещательные сообщения (или события) из разных точек:
Это означает, что они вызываются, когда происходит определенное действие, которое они запрограммированы на прослушивание, например, трансляция ( broadcast).
Трансляция ( broadcast) — это просто сообщение, заключенное в объект Intent. Трансляция может быть неявной или явной.
Есть два способа объявить приемник:
1.Объявив его в файле AndroidManifest.xml с тегом (также называемый статическим способом):
Вы заметите, что заявленный широковещательный приемник имеет свойство exported = ”true”. Этот атрибут сообщает получателю, что он может принимать широковещательные сообщения вне области приложения.
2. Или динамически путем регистрации экземпляра с помощью registerReceiver (так называемый зарегистрированный контекст):
Реализация Broadcast Receivers
Чтобы создать собственный широковещательный приемник, вы должны сначала расширить родительский класс BroadcastReceiver и переопределить обязательный метод onReceive:
Собрав все вместе, получим:
Метод onReceive выполняется в главном потоке, и поэтому его выполнение должно быть кратким.
Если выполняется долгий процесс, система может завершить процесс после возврата метода. Чтобы обойти это, рассмотрите возможность использования goAsync или планировщиков заданий (scheduling a job). Вы можете прочитать больше об этом в нижней части этой статьи.
Пример динамической регистрации
Чтобы зарегистрировать приемник с контекстом, вам сначала нужно создать экземпляр вашего широковещательного приемника:
Затем вы можете зарегистрировать его в зависимости от конкретного контекста, который вы хотите:
Первый параметр для IntentFilter — это строка, представляющая действие.
Не забудьте отменить регистрацию вашего вещательного приемника, когда он вам больше не нужен
Трансляция события
Смысл трансляции сообщений из вашего приложения заключается в том, чтобы позволить вашему приложению реагировать на события, происходящие внутри него. Подумайте о сценарии, когда в одной части кода пользователь выполняет определенное действие, и из-за этого вы хотите выполнить какую-то другую логику, которая есть в другом месте.
Есть три способа отправки трансляций:
На что обратить внимание
Изменения в новых версиях
Следующие пункты относятся к изменениям в широковещательных приемниках, относящихся к каждой версии ОС Android (начиная с 7.0). Для каждой версии были установлены определенные ограничения, а также изменилось поведение. Помните об этих ограничениях, думая об использовании Broadcast Receivers.
Изменения в Android O — это те, о которых вам нужно знать больше всего. Причина, по которой эти изменения были внесены, заключалась в том, что они приводили к проблемам с производительностью, разрядке аккумулятора и ухудшали работу пользователя. Это произошло из-за того, что многие приложения (даже те, которые в данный момент не запущены) прослушивали общесистемные изменения, и когда это изменение произошло, возник хаос. Представьте, что каждое приложение, зарегистрированное на действия, ожило, чтобы проверить, нужно ли что-то делать из-за трансляции. Примите во внимание что-то вроде состояния Wi-Fi, которое часто меняется, и вы начнете понимать, почему произошли эти изменения.
Альтернативы Broadcast Receivers
Чтобы упростить навигацию по всем этим ограничениям, ниже приводится разбивка других компонентов, которые можно использовать при отсутствии широковещательного приемника. У каждого из них своя ответственность и свой вариант использования, поэтому постарайтесь определить, какой из них отвечает вашим потребностям.
Ссылки на исходники
Если вы хотите из первых рук испытать радость и удивление, которые получают приемники вещания, вы можете перейти по этим ссылкам на репозитории, которые я настроил: