Android 接收開機廣播啓動service/activity
前言:
此文章針對於普通手機APP,在沒有限制之前直接可以通過接收開機廣播,然後通過intent即可實現開機啓動service/activity。
Intent intent = new Intent(context,XXXXX.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);//啓動activity
context.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:
- APP存在一個可視的窗口,例如一個處於前臺的Activity
- 另外一個處於前臺的APP發送一個屬於當前APP的PendingIntent。例如Custom Tabs provider發送一個menu item pending intent。
- 系統發送一個PendingIntent,例如點擊一個通知。
- 系統給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"
最後:不同的手機廠商的限制也有所不同,也有可能以上方法不適用於某些手機。
在鎖屏狀態下也不會接收到開機廣播,應該也是手機廠商做了限制。
參考文獻: