Android 8.0 Oreo AlarmManager с широковещательным приемником и неявным запретом широковещания

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

Раньше в моем манифесте Android было следующее:

    <receiver android:name="com.example.app.AlarmReceiver" >
        <intent-filter>
            <action android:name="${packageName}.alarm.action.trigger"/>
        </intent-filter>
    </receiver>

Приемник вещания:

public class AlarmReceiver extends BroadcastReceiver {

  @Override public void onReceive(
      final Context context,
      final Intent intent) {
// WAKE LOCK
// BUILD NOTIFICATION etc...
  }

}

Как устанавливается будильник:

final PendingIntent operation = PendingIntent.getBroadcast(
          mContext,
          requestCode,
          intent,
          PendingIntent.FLAG_CANCEL_CURRENT);

      if (PlatformUtils.hasMarshmallow()) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);

      } else {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);
      }
}

С Android 8.0 я больше не могу использовать неявную трансляцию, как определено в Manifest. Ничего страшного, есть альтернатива - зарегистрировать его вручную, вот так:

final BroadcastReceiver receiver = new AlarmReceiver();
final IntentFilter intentFilter = new IntentFilter(ALARM_RECEIVER_INTENT_TRIGGER);
context.registerReceiver(receiver, intentFilter);

Мне это не кажется логичным.

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

  2. Даже если я слушаю "android.intent.action.BOOT_COMPLETED" и регистрирую свой приемник сигналов тревоги, приложение вскоре прекращается, и сигнал тревоги не срабатывает. Я тоже не вижу свой будильник через

    adb shell dumpsys будильник

Как создать настраиваемый широковещательный приемник, который принимает неявное широковещательное сообщение для срабатывания сигнализации при нацеливании на Android O (8.0)? Может ли кто-нибудь просветить меня примером кода или ссылкой на документацию. Как Timely или любое другое приложение-будильник работает при нацеливании на O?


person ViciDroid    schedule 19.09.2017    source источник


Ответы (2)


Немного измените свой код, чтобы сделать широковещательную передачу явной, а не неявной, и все будет в порядке (при условии, что this является Activity ссылкой или каким-либо другим Context):

Intent intent = new Intent(ALARM_RECEIVER_INTENT_TRIGGER);
intent.setClass(this, AlarmReceiver.class);

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

person Larry Schiefer    schedule 19.09.2017
comment
Как мне зарегистрировать широковещательный приемник с этим аргументом намерения? Похоже, это для отправки трансляции. - person ViciDroid; 19.09.2017
comment
Ваша регистрация в манифесте в порядке (я предполагаю, что ваша константа ALARM_RECEIVER_INTENT_TRIGGER - это строка com.example.app.alarm.action.trigger из вашего манифеста), хотя вам, вероятно, следует добавить android:export="false" в запись, чтобы другие приложения не пытались отправить вашему приемнику широковещательную рассылку, которая может испортить ты поднялся чувак. - person Larry Schiefer; 19.09.2017
comment
Это сработало, забыл установить класс при создании намерения для ожидающего намерения. Спасибо! - person ViciDroid; 21.09.2017
comment
Добро пожаловать, рад, что смог помочь. Обязательно отметьте ответ как правильный. - person Larry Schiefer; 21.09.2017
comment
Пожалуйста, может кто-нибудь поделиться, как отправлять / получать явные намерения в другое приложение? Лучше всего будет запущенный пример - person hannes ach; 12.10.2017
comment
@hannesach, непонятно, о чем вы спрашиваете. Явный Intent указывает, какой именно пакет приложения и компонент (экземпляр класса) его получат. Одно приложение не может получить явный Intent объект, который отправляется другому приложению. - person Larry Schiefer; 31.10.2017
comment
@LarrySchiefer позвольте мне попытаться уточнить: с api25 можно было установить конкретную связь между приложениями с явным намерением. С api26 гугл пишет: не более implicit Intent, согласен. Но ни слова о явном Intent от Google, на мой взгляд, нового ограничения нет. Но я не могу заставить его работать с api26. Когда вы написали: это невозможно, вы можете иметь в виду только api 26 (потому что api25 работает), но Google пишет только о новом неявном ограничении широковещания. - person hannes ach; 01.11.2017
comment
@hannesach, вы по-прежнему должны иметь возможность отправлять явные широковещательные сообщения другим приложениям, если вы знаете цель пакета / класса для Intent. Явные Intents есть в Android с 1.0, ничего нового там нет. Единственное, что ново, - это ограничение на неявные намерения. - person Larry Schiefer; 01.11.2017
comment
@LarrySchiefer, моя реализация не работает в Android, поэтому я спросил, пожалуйста, может ли кто-нибудь поделиться, как отправлять / получать явные намерения в другое приложение? Лучше всего будет запущенный пример - person hannes ach; 05.11.2017
comment
Ханнес Ах, вам понадобится ваш код, чтобы помочь. - person Larry Schiefer; 05.11.2017
comment
вау. Я работаю над этим уже 2+ дня. Я искал в Google неправильные ключевые слова! Огромное спасибо! Если у вас есть время, могу я попросить вас обратить внимание на stackoverflow.com/questions/50894567/ - person narb; 20.06.2018
comment
@hannesach есть ли у вас решение? - person Debugger; 25.07.2018
comment
в настоящее время нет, но мне нужно решение до конца октября. пожалуйста, напишите мне позже еще раз - person hannes ach; 26.07.2018
comment
Спасибо, это мне очень помогло. Я застрял на какое-то время, потому что мое намерение было сделано в суперклассе, но получатели зарегистрированы в подклассах. Чтобы получить правильное имя класса, используйте: intent.setClass (context, this.getClass ()) - person Georgie; 17.10.2018
comment
Спасибо, вместо setClass тоже работает setPackage. - person Knowledge Drilling; 01.03.2019

Если вы, ребята, привыкли проверять, была ли уже зарегистрирована сигнализация, не забудьте проделать то же самое с этой проверкой:

public boolean isAlarmBroadcastRegistered(Context context, String action, Class clazz) {
    Intent intent = new Intent(action);
    intent.setClass(context, clazz);
    return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE) != null;
}
person Cícero Moura    schedule 24.02.2018