Persistent background services require the service to be re-started after a device reboots. However, in order to achieve this persistence an application must be ran once. This is when the developer has the ability to let the operating system know that there is a service that needs to be started outside of the context of it’s UI application. The reason being is that once the device is rebooted it will use a broadcast receiver to handle its’ initialization.
The way you start a background service on Android at boot is with an Android component called a broadcast receiver. A broadcast receiver can subscribe to different types of broadcasts. A broadcast is more commonly known as an action. There are two types of broadcasts on Android. The first type is a local broadcast which is a broadcast or action defined by the developer within the scope of an application. The second type is a system broadcast which is defined within the Android API.
Android 8.0 Oreo changed the way that broadcast receivers are registered. Only certain types of broadcasted actions can be subscribed to within an intent filter of the manifest.xml file. The majority require it to be done in code within the life-cycle of and Android component such as a service or activity. The system broadcast for BOOT_COMPLETED happens to be one of these actions that are still available for use within the manifest.xml file. Because of this a persistent background service is achieved through registering a broadcast receiver within the Android manifest.xml file. Within this declaration you will apply something called an intent-filter. You list the actions that you would like this broadcast receiver to subscribe to within its’ intent-filter.
The most important action here is BOOT_COMPLETED. All Android devices broadcast a BOOT_COMPLETED action once the device has powered on and finished loading the operating system. This is an ordered broadcast meaning that multiple applications can subscribe to this broadcast with the ability to specify a priority. Apps with a higher priority receive this broadcast first and get first class response time. A greater number means a higher priority. The priority can be set from 1 to 999.
Now you need to create a subclass of BroadcastReciever. Once you have done this you will need to override a single method called onReceive. You will write your code to execute every time a subscribed action is broadcasted within the scope of this callback.
Android 8.0 Oreo brought a new requirement to persistence services on Android. They are now known as foreground services due to the added requirement for all services running in the background to keep a notification in the notification drawer during its’ life span. Meaning if your service is running in the background of the phone without your app in the foreground then you must have a notification present in the drawer. However, if you have a background service running while your app is in use then you do not require a notification in the drawer. It is also a flag to the operating system to request not be killed but it can guarantee no promise as Android has a very complex way of killing background processes.
So the service you start from within the onReceive callback of your BOOT_COMPLETE broadcast receiver needs to be a subclass of service. This service is what handles the responsibility of creating a foreground notification within the service’s onStart callback method.
Aside from this you will also need to declare your service implementation within your manifest.xml file inside of the application tag.
The last thing you will need to add to your manifest file will be the two permissions required for a foreground service as well as subscribing to the BOOT_COMPLETED system broadcast.
There is one final thing to mention regarding a persistent background service. Direct boot mode was a feature added in Android 7.0 Nougat. This feature allows for a BOOT_COMPLETED broadcast to be received before the user unlocks the device after reboot. However, the only partition that is mounted at this time is internal storage. Therefore, in the event that you would like to support direct boot mode then you will need to tell the system that you would like your app to be installed to internal storage only. You do this in the manifest.xml file.
Continuing on with our discussion about direct boot mode, we will need to make some modifications to the manifest.xml file that we’ve already written above to support this feature. Both Android components involved need to be direct boot aware. So let’s make these modifications all at once.
The only time you need to start this service from within an Activity or Fragment is when the app is started for its’ first time.
Now if all this seems to be too much trouble then I fully understand as I began to grow tired of doing these steps every time I wanted to have a persistent service. Because of this, I spent two summers working on a library called Boot Laces. It handles all of the setup and initialization for you.