Android 接收開機廣播啓動service/activity

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:

  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踩坑記錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章