Android 11及以上版本如何设置应用开机自动启动?
Android 11+ 开机后发送通知的解决方案
从Android 11开始,系统对BOOT_COMPLETED广播接收器的触发条件做了严格限制:只有用户手动启动过至少一次的应用,或者应用持有特定权限(如前台服务权限),才能接收到该广播。如果应用从未被用户打开过,即使注册了广播接收器也无法触发。以下是几种可行的解决方案:
方案一:使用WorkManager实现(推荐)
WorkManager是Jetpack官方推荐的后台任务调度组件,支持设备重启后自动重新调度任务,且符合Android 11+的权限规范。
- 添加依赖
在build.gradle(app)中引入WorkManager依赖:
implementation "androidx.work:work-runtime:2.8.1"
- 创建Worker类处理通知逻辑
class BootNotificationWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { sendBootNotification(applicationContext) return Result.success() } private fun sendBootNotification(context: Context) { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // 创建通知渠道(Android O及以上必填) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "BOOT_NOTIFY_CHANNEL", "开机通知", NotificationManager.IMPORTANCE_DEFAULT ).apply { description = "设备开机后触发的通知" } notificationManager.createNotificationChannel(channel) } // 点击通知打开应用 val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName) val pendingIntent = PendingIntent.getActivity( context, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) // 构建并发送通知 val notification = NotificationCompat.Builder(context, "BOOT_NOTIFY_CHANNEL") .setSmallIcon(R.drawable.ic_notification) .setContentTitle("设备已开机") .setContentText("你的应用已检测到开机完成") .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .build() notificationManager.notify(1001, notification) } }
- 在应用启动时注册任务
在MainActivity的onCreate方法中,注册一个设备重启后自动触发的WorkManager任务:
val constraints = Constraints.Builder() .setRequiresDeviceIdle(false) .setRequiresCharging(false) .build() val bootWorkRequest = OneTimeWorkRequestBuilder<BootNotificationWorker>() .setConstraints(constraints) .setInitialDelay(10, TimeUnit.SECONDS) // 延迟10秒,确保系统初始化完成 .addTag("BOOT_NOTIFY_TASK") .build() // 确保任务唯一,避免重复调度 WorkManager.getInstance(this).enqueueUniqueWork( "UNIQUE_BOOT_NOTIFY_WORK", ExistingWorkPolicy.REPLACE, bootWorkRequest )
方案二:保留BOOT_COMPLETED广播接收器(需满足权限条件)
如果坚持使用广播接收器,必须满足以下前提:用户手动打开过应用至少一次,部分国产ROM还需开启「自动启动」权限。
- 注册广播接收器与权限
在AndroidManifest.xml中添加:
<!-- 声明权限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 注册广播接收器 --> <receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.QUICKBOOT_POWERON" /> <!-- 适配快速开机 --> </intent-filter> </receiver>
- 实现广播接收器逻辑
class BootCompletedReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (Intent.ACTION_BOOT_COMPLETED == intent.action || Intent.ACTION_QUICKBOOT_POWERON == intent.action) { // 调用发送通知的方法(同方案一中的sendBootNotification) sendBootNotification(context) } } private fun sendBootNotification(context: Context) { // 同方案一的通知构建逻辑 } }
方案三:前台服务结合START_STICKY(不推荐,耗电)
仅适用于需要开机后立即执行任务的场景,会在状态栏显示前台通知,影响用户体验。
- 添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
- 广播接收器启动前台服务
class BootCompletedReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (Intent.ACTION_BOOT_COMPLETED == intent.action) { val serviceIntent = Intent(context, BootForegroundService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent) } else { context.startService(serviceIntent) } } } }
- 实现前台服务
class BootForegroundService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // 创建前台通知 val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "FOREGROUND_BOOT_CHANNEL", "开机服务", NotificationManager.IMPORTANCE_LOW ) notificationManager.createNotificationChannel(channel) } val foregroundNotification = NotificationCompat.Builder(this, "FOREGROUND_BOOT_CHANNEL") .setSmallIcon(R.drawable.ic_notification) .setContentTitle("应用运行中") .setPriority(NotificationCompat.PRIORITY_LOW) .build() startForeground(1002, foregroundNotification) // 发送开机通知 sendBootNotification(this) // 任务完成后停止前台服务 stopForeground(STOP_FOREGROUND_REMOVE) stopSelf() return START_STICKY } private fun sendBootNotification(context: Context) { // 同方案一的通知构建逻辑 } override fun onBind(intent: Intent): IBinder? = null }
内容的提问来源于stack exchange,提问作者RahaKiani
相关产品推荐
相关产品推荐

