Android 8.0 Oreo中的AlarmManager与广播接收器和隐式广播禁令

14

我有一些关键的提醒通过Alarm Manager设置(它应该和闹钟应用程序的功能一样)。

之前在我的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时,我不能再像在清单文件中定义的那样使用隐式广播。没关系,提供了另一种可行的替代方案,可以手动注册它,方法如下:

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 alarm

我如何创建一个自定义广播接收器,以接收隐式广播触发闹钟,同时针对 Android O (8.0) 进行目标设置?有人能给我提供代码示例或文档链接吗?Timely 或其他闹钟应用程序在针对 O 版本时如何工作?

2个回答

29

稍微修改一下您的代码,使广播显式而非隐式,并且您就可以了(假设this是一个Activity引用或其他Context):

Intent intent = new Intent(ALARM_RECEIVER_INTENT_TRIGGER);
intent.setClass(this, AlarmReceiver.class);
在Oreo中的限制在于对隐式broadcast Intent注册的限制,这意味着如果您发送广播,它只会按照指定的操作、类别或数据进行。您可以通过指定接收广播的类来使其成为显式广播。

1
我该如何使用这个意图参数注册广播接收器?看起来像是用于发送广播。 - ViciDroid
2
您在清单文件中的注册是正确的(我假设您的常量ALARM_RECEIVER_INTENT_TRIGGER是来自您的清单文件中的字符串com.example.app.alarm.action.trigger),但是您可能应该在条目中添加一个android:export="false"以防止其他应用程序尝试发送广播给您的接收器,这可能会使您出现问题。 - Larry Schiefer
这个有用了,创建待定意图时忘记设置类。谢谢! - ViciDroid
请问有人可以分享如何向其他应用程序发送/接收显式意图吗?最好提供一个运行示例。 - hannes ach
1
@LarrySchiefer 我的实现在Android上不起作用,这就是我问的原因:“请问有人可以分享如何向其他应用程序发送/接收显式意图吗?最好有运行示例。” - hannes ach
显示剩余11条评论

1

如果您习惯于检查警报是否已经注册,请不要忘记在此验证中执行相同的操作:

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接