Уведомления Android, запускаемые Alarm Manager, не срабатывают, когда приложение находится в режиме ожидания. - PullRequest
5 голосов
/ 05 апреля 2019

У меня есть следующие требования. Пользователь должен иметь возможность планировать повторяющиеся напоминания в моем приложении, которые будут запускать push-уведомления в точное время каждый день.

Это один из тех вопросов, на которые я надеялся, что в конечном итоге не буду отвечать, поскольку подобные вопросы были рекомендованы при его написании. Однако несколько членов команды часами часами просматривали Документы для разработчиков Android и Stackoverflow, и мы, похоже, не приблизились к ответу, поэтому мы здесь.

Если я создаю напоминание и устанавливаю его для запуска уведомления через 5 минут в будущем, уведомление срабатывает очень хорошо.

Я подозреваю, что это может быть проблема, вызванная изменениями в энергосбережении, блокировке пробуждения и т. Д., Появившимися в Android P, поскольку у нас не было этой проблемы до обновления нашего целевого SDK до 28. При этом я не уверен, что это единственная проблема, но я могу последовательно воспроизвести проблему на Pixel и Pixel 3 XL под управлением Android P.

Пример, когда уведомление не срабатывает, возникает, когда, например, пользователь устанавливает напоминание на какое-то время среди ночи (предположительно, когда пользователь спит и, следовательно, не будет использовать телефон в течение нескольких часов). Эти напоминания не стреляют никогда.

В настоящее время я пытаюсь выполнить это с помощью диспетчера аварийных сигналов.

Эта проблема, похоже, похожа на другой вопрос, который использует метод setRepeating Alarm Manager * Manager, который не работает. Вместо этого мы используем метод setExactAndAllowWhileIdle диспетчера тревог. Мы также попробовали эту же реализацию с методом Alarm Managers setAlarmClock , который в соответствии с документацией Android "будет разрешено запускать, даже если система находится в режиме низкого энергопотребления (в режиме ожидания)", однако это было также неудачно.

Я подозреваю, что причина, по которой это не работает, заключается в том, что setExactAndAllowWhileIdle не будет срабатывать, когда телефон находится в режиме ожидания, аналогично проблемам, выраженным в в этом вопросе . В этом вопросе рекомендуется использовать Firebase JobDispatcher, но поскольку это внутреннее уведомление, мне необходимо запустить уведомление с сетевым подключением или без него, что, по-видимому, исключает Firebase JobDispatcher в качестве опции. Этот вопрос также указывает на то, что как только телефон выходит из режима ожидания, пользователь получает уведомление, однако мы никогда не получаем уведомление, они, похоже, теряются из-за отсутствия лучшего термина.

Я добавил разрешение блокировки пробуждения в свой AndroidManifest.xml:

<uses-permission android:name="android.permission.WAKE_LOCK" />

Вот как мой приемник зарегистрирован в AndroidManifest.xml

<receiver android:name="com.myapp.receiver.AlarmReceiver">
    </receiver>

Вот моя текущая реализация:

Ожидание обработки уведомлений

Intent i = new Intent(context, ScheduleAllReceiver.class);
    PendingIntent scheduleAllPendingIntent = PendingIntent.getBroadcast(context, SCHEDULER_DAILY_ALL, i, PendingIntent.FLAG_UPDATE_CURRENT);

Я впоследствии вызываю метод «createAlarm» следующим образом

createAlarm(context, scheduleAllPendingIntent, calendar.getTimeInMillis());

Создание будильника

public static void createAlarm(Context context, PendingIntent pendingIntent, long timeinMilli) {
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    if(alarmManager != null) {

        if (Build.VERSION.SDK_INT >= 23) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeinMilli, pendingIntent);
        } else {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeinMilli, pendingIntent);
        }
    }
}

Ответы [ 5 ]

5 голосов
/ 26 апреля 2019

Добавление флага намерений FLAG_RECEIVER_FOREGROUND

https://developer.android.com/reference/android/content/Intent#FLAG_RECEIVER_FOREGROUND перед вызовом вещательного приемника следует выполнить трюк

Intent intent = new Intent(context, ScheduleAllReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent scheduleAllPendingIntent = PendingIntent.getBroadcast(context, SCHEDULER_DAILY_ALL, intent, PendingIntent.FLAG_UPDATE_CURRENT);
1 голос
/ 16 апреля 2019

Это библиотека , которая работала для меня.

1 голос
/ 13 апреля 2019

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

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

Способ регистрации менеджера аварийных сигналов (используйте заданное точное время вместо повторения)

public static void registerAlarm(Context context){
    final int FIVE_MINUTES_IN_MILLI = 300000;
    final int THIRTY_SECOND_IN_MILLI = 30000;
    long launchTime = System.currentTimeMillis() + FIVE_MINUTES_IN_MILLI;
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent i = new Intent(context, BroadcastAlarmManger.class);
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, launchTime, pi);
    else am.setExact(AlarmManager.RTC_WAKEUP, launchTime, pi);
    Utility.printLog("timestamp "+launchTime);
}

Вещательный приемник для будильника

открытый класс BroadcastAlarmManger расширяет BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    //register alarm again
     registerAlarm(context);
    .
    .
    .
    .
    //do your stuff    
}

Манифест декларации

<receiver
        android:name="com.taxiemall.utility.BroadcastAlarmManger"
        android:enabled="true"
        android:exported="true"/>

Также вы должны обработать Перезагрузка вручную. После каждой перезагрузки зарегистрированные тревоги сбрасываются. Поэтому зарегистрируйте приемник вещания для перезагрузки Android и снова зарегистрируйте в нем сигнал тревоги.

0 голосов
/ 14 апреля 2019

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

Посмотрите на пределы фонового исполнения https://developer.android.com/about/versions/oreo/android-8.0-changes

Предложение от меня, если вы можете использовать FCM, тогда пойдите, потому что такие приложения, как WeChat, Facebook используют его для доставки уведомлений, и они нене сталкиваюсь с какой-либо проблемой ...

Надеюсь, это поможет понять проблему ....

0 голосов
/ 13 апреля 2019

Да, вы правы. Теперь Google рекомендует использовать WorkManager вместо AlarmManager. AlarmManager имеет много ограничений в своей работе. Вы можете найти более подробную информацию здесь (режим ожидания)
Кроме того, у пиксельного телефона есть ошибка с alarmManager

...