AlarmManager触发广播接收器后如何在应用不在前台时启动Activity
问题原因
Android 10(API 29)及以上系统新增了后台应用启动Activity的限制,即便是广播接收器正常触发,不在前台运行的应用默认也没有启动Activity的权限,这是系统为了减少非用户预期的界面跳转、优化使用体验做的限制。
解决方案
方案1:申请悬浮窗权限(最简单直接,适合闹钟类工具应用)
申请SYSTEM_ALERT_WINDOW权限后即可绕过后台启动Activity限制:
- 在
AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 跳转权限申请页需要的权限 --> <uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
- 在应用首次启动时引导用户开启悬浮窗权限:
// 权限请求码自定义即可 private static final int REQ_OVERLAY_PERMISSION = 1001; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQ_OVERLAY_PERMISSION); } }
方案2:使用全屏Intent配合通知(无需悬浮窗权限,适配系统规范)
如果不想申请悬浮窗权限,可以通过高优先级通知的全屏Intent实现后台唤起:
- 在
AndroidManifest.xml中添加通知权限(Android 13及以上需要):
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- 广播接收器
onReceive中改为弹出通知,通过通知的意图跳转Activity:
@Override public void onReceive(Context context, Intent intent) { Intent scheduledIntent = new Intent(context, MainActivity.class); scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pendingIntent = PendingIntent.getActivity( context, 1002, scheduledIntent, Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT ); String channelId = "alarm_channel"; NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(channelId, "闹钟提醒", NotificationManager.IMPORTANCE_HIGH); notificationManager.createNotificationChannel(channel); } Notification notification = new NotificationCompat.Builder(context, channelId) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("闹钟触发") .setContentText("点击打开应用") .setPriority(NotificationCompat.PRIORITY_MAX) .setCategory(NotificationCompat.CATEGORY_ALARM) .setContentIntent(pendingIntent) .setFullScreenIntent(pendingIntent, true) // 关键:全屏意图,后台会直接唤起Activity .setAutoCancel(true) .build(); notificationManager.notify(1003, notification); }
原有代码修复
你现有AlarmManager设置代码中PendingIntent的标记不符合Android 12及以上系统要求,需要修改标记位避免报错:
AlarmManager alarmManager=(AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent=new Intent(this,AlarmReceiver.class); int flag = PendingIntent.FLAG_UPDATE_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 不需要修改Intent内容用FLAG_IMMUTABLE,需要修改则用FLAG_MUTABLE flag |= PendingIntent.FLAG_IMMUTABLE; } PendingIntent pendingIntent=PendingIntent.getBroadcast(this,1000,intent,flag); // Android 12及以上需要申请精确闹钟权限才能使用setExactAndAllowWhileIdle if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,timeInMillis,pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP,timeInMillis,pendingIntent); }
如果需要定时在低功耗模式也能触发,还需要在Manifest中添加精确闹钟权限:
<uses-permission android:name="android.permission.REQUEST_SCHEDULE_EXACT_ALARM" />
内容的提问来源于stack exchange,提问作者Ali Akram
相关产品推荐
相关产品推荐

