Изменения в работе точных алармов в Android 12
Android 12 привнес множество изменений, одно из которых, вызывающее вопросы - это новое разрешение для точных алармов (exact alarm). Это статья является быстрым гайдом по новому разрешению и показывает что, как и почему нужно изменить в коде вашего приложения.
Что это за разрешение?
Новое разрешение на точные алармы (SCHEDULE_EXACT_ALARM
) было создано, чтобы сохранить системные ресурсы. Алармы, которые должны срабатывать в точное время могут сработать когда устройство находится в энергосберегающем или Doze режиме, заставляя приложение расходовать батарею сильнее, чем это необходимо.
Когда я должен использовать точные алармы?
Google рекомендует использовать эти алармы в двух ситуациях:
- В приложениях являющимися часами или таймером
- В приложениях содержащих точные события, например в календарях или напоминалках
Какой тип у этого разрешения?
Это тип разрешений "Специальный доступ" (Special app access). Вы можете найти его в Settings > Apps > Special app access > Alarms & reminders
. Это разрешение дается при установке приложения. Чтобы отозвать его, пользователю придется самостоятельно заходить на этот экран.
Что случится, когда юзер отзовет это разрешение?
Прежде всего все ранее установленные точные алармы будут удалены и не сработают. При следующих попытках установить точный аларм приложение будет падать с SecurityException
.
Мое приложение использует AlarmManager. Нужно ли мне что-то менять?
Если приложение вызывает методы AlarmManager
которые устанавливают точный аларм, потребуются изменения. Это касается методов:
- setAlarmClock()
- setExact()
- setExactAndAllowWhileIdle()
Если приложение использует методы AlarmManager
такие, как set()
, setInexactRepeating()
, setAndAllowWhileIdle()
или setWindow()
, то изменений не требуется.
Мое приложение использует WorkManager. Нужно ли мне что-то менять?
Нет. WorkManager
спроектирован учитывающим системные оптимизации и нет гарантий что он отработает в точное время, которое ему было назначено. Это требование работает только для точных алармов в AlarmManager
Что мне нужно, чтобы обновить приложение?
Для того чтобы продолжить пользоваться точными алармами на 12 Android, а также для предосторожности и обеспечения стабильности работы вашего приложения необходимо выполнить следующие шаги:
1. Добавить новое разрешение в AndroidManifest.xml
Для начала нужно добавить пермишен SCHEDULE_EXACT_ALARM
в манифест. Если Android Studio не находит его, убедитесь что для приложения установлена версия API 31 (compileSdkVersion = 31
).
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.escodro.alkaa">
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<application/>
</manifest>
2. Проверять получение разрешения до установки алармов
Поскольку это разрешение может быть отозвано пользователем в любое время, рекомендуется проверять его наличие перед установкой точных алармов. Для этого у AlarmManager
имеется новый метод:
val alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val hasPermission: Boolean = alarmManager.canScheduleExactAlarms()
Метод canScheduleExactAlarms()
возвращает boolean сообщающий получено ли разрешение, или нет
3. Запросить разрешение у пользователя
Если при проверке разрешения метод отдает false
, рекомендуется показать пользователю информацию о том, почему это разрешение необходимо для вашего приложения и перенаправить его на экран "Специальный доступ". Чтобы это сделать используйте следующий Intent
:
val intent = Intent().apply {
action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
}
startActivity(intent)
Стоит отметить, что этот Intent
не перенаправит пользователя на экран с разрешением именно вашего приложения. Пользователю откроется экран "Специальный доступ" со списком все приложений, нуждающихся в данном разрешении. Поэтому будет хорошо все разъяснить пользователю перед его перенаправлением.
4. Зарегистрируйте BroadcastReceiver, чтобы получать сведения о данном разрешении
Также рекомендуется создавать BroadcastReceiver
для получения Intent
когда пользователь снова дает это разрешение нашему приложению. Эта информация очень важна, потому что, как говорилось ранее, при отзыве разрешения все установленные алармы удаляются. Основываясь на этом событии появляется возможность установить их заново.
Для приложений уже использующих алармы это поведение похоже на то, когда устройства выключается. Все алармы удаляются системой и когда устройство включается снова, приложение получает броадкаст RECEIVE_BOOT_COMPLETED
, чтобы переназначить их.
BroadcastReceiver
будет примерно таким:
internal class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED -> {
// переназначить все точные алармы
}
}
}
Событие ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
отправляется как на ресиверы из манифеста, так и на зарегистрированные в рантайме. Например, в манифесте это будет выглядеть так:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.escodro.alarm">
<application>
<receiver
android:name=".TaskReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
</intent-filter>
</receiver>
</application>
</manifest>
Важно отметить, что данный броадкаст отправляется системой только в случае получения разрешения от пользователя. Это событие не будет отправляться при отзыве данного разрешения пользователем. В зависимости от функционала вашего приложения, хорошим решением может стать проверка и информирование пользователя об этом разрешении при открытии приложения.