Android 接收开机广播启动service/activity

前言:

此文章针对于普通手机APP,在没有限制之前直接可以通过接收开机广播,然后通过intent即可实现开机启动service/activity。

Intent intent = new Intent(context,XXXXX.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);//启动activitycontext.startService(intent);//启动service
对于启动service:

Android 8.0 对特定函数做出了以下变更:

  • 如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException
  • 新的 Context.startForegroundService() 函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用 Context.startForegroundService()。不过,应用必须在创建服务后的五秒内调用该服务的 startForeground() 函数。如果不调用就会出现ANR。
对于启动activity:

Android Q限制在没有用户交互的情况下加载Activity。这一变化可以最大限度的减少对用户的打扰,保持用户对屏幕上所显示内容的可控性。
运行在Android Q上的APP仅在以下一种或多种情况下可运行Activity:

  1. APP存在一个可视的窗口,例如一个处于前台的Activity
  2. 另外一个处于前台的APP发送一个属于当前APP的PendingIntent。例如Custom Tabs provider发送一个menu item pending intent。
  3. 系统发送一个PendingIntent,例如点击一个通知。
  4. 系统给APP发送一个广播,如SECRET_CODE_ACTION。
注:APP启动一个前台运行的Service并不代表该APP处于前台运行状态。
所以并不能启动service之后再service中直接启动activity。

解决办法:

启动service:

前面我们已经知道了可以通过startForegroundService()来启动service,然后在oncreate中调用startForeground()即可:

BootReceiver:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {         context.startForegroundService(intent);} else {         context.startService(intent);}

service的onCreate():

//设置点击跳转Intent intent = new Intent(this, MainActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);String id = "1";String name = "channel_name_1";NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);Notification notification = null;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {         NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_DEFAULT);    mChannel.setSound(null, null);    notificationManager.createNotificationChannel(mChannel);    notification = new Notification.Builder(this)                           .setChannelId(id)                           .setContentTitle("123")                           .setContentIntent(pendingIntent)                           .setAutoCancel(false)                           .setSmallIcon(R.drawable.ic_launcher_background).build();} else {         NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)                                                          .setContentTitle("123")                                                             .setContentIntent(pendingIntent)                                                             .setPriority(Notification.PRIORITY_DEFAULT)// 设置该通知优先级                                                             .setAutoCancel(false)                                                             .setSmallIcon(R.drawable.ic_launcher_background);    notification = notificationBuilder.build();}startForeground(1, notification);

这样即可实现在开机时启动服务,但是会在通知栏创建一条消息。

如果不实现startForeground()就会onDestory

最后记得在Mainfest.xml中添加权限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
启动activity:

直接使用context.startactivity(intent)是不能够启动的,会报一些空指针错误之类的。

谷歌官方推荐使用全屏Intent:

BootReceiver:

Intent intent1 = new Intent(context, MainActivity2.class);intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(context, 0,        intent1, PendingIntent.FLAG_UPDATE_CURRENT);String channelId = createNotificationChannel("my_channel_ID", "my_channel_NAME", NotificationManager.IMPORTANCE_HIGH, context);NotificationCompat.Builder notification =        new NotificationCompat.Builder(context, channelId)                .setSmallIcon(R.drawable.ic_launcher_background)                .setContentTitle("Start Activity")                .setContentText("click me")                .setPriority(NotificationCompat.PRIORITY_HIGH)                .setCategory(NotificationCompat.CATEGORY_CALL)                .setAutoCancel(true)                // Use a full-screen intent only for the highest-priority alerts where you                // have an associated activity that you would like to launch after the user                // interacts with the notification. Also, if your app targets Android 10                // or higher, you need to request the USE_FULL_SCREEN_INTENT permission in                // order for the platform to invoke this notification.                .setFullScreenIntent(fullScreenPendingIntent, true);NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);notificationManager.notify(100, notification.build());

createNotificationChannel:

private String createNotificationChannel(String channelID, String channelNAME, int level, Context context) {         if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {             NotificationManager manager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);        NotificationChannel channel = new NotificationChannel(channelID, channelNAME, level);        manager.createNotificationChannel(channel);        return channelID;    } else {             return null;    }}

在接收到开机广播后会在通知栏创建一个消息,然后用户点击消息跳转到对应的activity。

最后记得在Mainfest.xml中添加权限:

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

总结:

随着版本的升级,android对后台限制越来越严格,想要悄无声息的启动service和activity有一定的困难。

而且普通app接收开机广播接收也很慢,在开机后10多秒才能接收到,把优先级设为最高,会有一定的效果

android:priority="2147483647"

最后:不同的手机厂商的限制也有所不同,也有可能以上方法不适用于某些手机。

在锁屏状态下也不会接收到开机广播,应该也是手机厂商做了限制。

参考文献:

Android10适配-针对从后台启动 Activity 的限制

显示有时效性的通知

Android Q 限制后台启动Activity

Android8.0 启动后台Service问题

Android 保活后台启动Service 8.0踩坑记录

更多相关文章

  1. 一个不错的启动菜单显示屏动画效果
  2. Android(安卓)P 系统启动-System Server启动篇
  3. android启动SDK Manager闪退问题
  4. Android(安卓)如何使一个service 开机启动
  5. Android(安卓)检查版本更新 Server后台下载
  6. Android——Intent 相关
  7. android中开机自动运行程序
  8. Android启动过程
  9. Android的Service总结

随机推荐

  1. 在SQL查询中使用LIKE来代替IN查询的方法
  2. 去掉前面的0的sql语句(前导零,零前缀)
  3. sqlserver 多库查询 sp_addlinkedserver
  4. sqlserver 三种分页方式性能比较[图文]
  5. SQL学习笔记七函数 数字,日期,类型转换,空值
  6. SQL学习笔记八 索引,表连接,子查询,ROW_NUMB
  7. SQL学习笔记六 union联合结果集使用
  8. SQL学习笔记五去重,给新加字段赋值的方法
  9. SQL学习笔记四 聚合函数、排序方法
  10. SQL学习笔记三 select语句的各种形式小结