Broadcast Receiver in Android
Broadcast Receiver OverView
Broadcast receivers are one of the basic components of Android. Android apps can send or receive broadcast messages from the Android system and other Android apps. For example, the Android system sends broadcasts when various system events occur, such as when the device starts charging or about the device boot. Apps can also send custom broadcasts such as to notify other apps that something that they might be interested which is occurred.
What is a Broadcast Receiver?
A broadcast receiver is an Android core component which allows you to send or receive broadcast messages from the
Android system and Android apps. These broadcasts are sent when an event of interest occurs.
Receiving Broadcasts
Android apps can receive Broadcasts in two ways, one is through manifest-declared receivers and another one through context-registered receivers.
- Manifest-declared Receivers
To declare a broadcast receiver in the manifest, perform following steps
- Add the <receiver> element in your app’s manifest file
<receiver android:name=".PowerButtonBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
2. Create a subclass of Broadcast receiver class and implement onReceive(Context, Intent) like below example
class PowerButtonBroadcastReceiver : BroadcastReceiver() {
private var screenOff: Boolean = false
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_SCREEN_OFF) {
screenOff = true
} else if (intent.action == Intent.ACTION_SCREEN_ON) {
screenOff = false
}
val mIntent = Intent(context, PowerButtonUpdateClickService::class.java)
mIntent.putExtra("screen_state", screenOff)
context.startService(mIntent)
}
}
2) Context-registered receivers
To register a Context-registered receiver, follow below steps
1. Create an instance of BroadcastReceiver.
val mReceiver = PowerButtonBroadcastReceiver()
2. Create an instance of IntentFilter and register the receiver by calling registerReceiver(BroadCastReceiver, IntentFilter)
// INITIALIZE RECEIVER
val filter = IntentFilter(Intent.ACTION_SCREEN_ON)
filter.addAction(Intent.ACTION_SCREEN_OFF)
mReceiver = PowerButtonBroadcastReceiver()
registerReceiver(mReceiver, filter)
In Context-registered receivers receive broadcasts as long as their registering context is valid(context is of Activity or Fragment), if you use context of Application, you receive broadcasts as long as your application is running. To stop receiving Broadcast, call unregisterReceiver(BroadcastReceiver), You should be very careful while unregistering the BroadcastReceiver, if you are registering BroadcastReceiver in onCreate() then you should unregister it in onDestroy() to prevent leaking the BroadcastReceiver out of the activity context.
Sending broadcasts
There are below ways to send Broadcasts
- The sendOrderedBroadcast(Intent, String)
This method sends broadcasts to one receiver at a time, Ordered Broadcast is the type of broadcast which is sent in a synchronous manner i.e. one by one to each listener. Ordered Broadcast method falls in the Context class of Android, the purpose of this method is to broadcast to listening receivers in a serialised manner and receive the result back to the calling activity. Another key advantage of sendOrderedBroadcast is that we can set the priority of BroadcastReceiver. This way all the BroadcastReceivers listening to that specific broadcast will receive that specific broadcast in an ordered manner.
2. Normal Broadcasts
Under this category broadcasts are sent in an asynchronous fashion i.e. broadcast is received by all the receivers in an asynchronous manner. It has two types:
sendBroadcast(Intent) and LocalBroadcastManager.sendBroadcast — This class LocalBroadcastManager.sendBroadcast is used to send local broadcasts i.e. within the app.
sendBroadcast(Intent) method sends broadcasts to all receivers in an undefined order. This is called a Normal Broadcast. This is more efficient but means that receivers cannot read results from other receivers, propagate data received from the broadcast, or abort the broadcast.
LocalBroadcastManager.sendBroadcast() method sends broadcasts to receivers that are in the same app as the sender. If you don’t need to send broadcasts across apps, use local broadcasts. The implementation is much more efficient (no interprocess communication needed) and you don’t need to worry about any security issues related to other apps being able to receive or send your broadcasts.
Sending Broadcasts with permissions
While sending broadcasts we can enforce restrictions on either receiver side or on sender side of a broadcast. Permissions only those apps which hold specified permission, if sender sends broadcast with Manifest.permission.SEND_SMS then receiver must receive with SEND_SMS permission in android manifest file like below example.
sendBroadcast(Intent("com.example.NOTIFY"), Manifest.permission.SEND_SMS)
To receive the broadcast, the receiving app must request below permission
<uses-permission android:name="android.permission.SEND_SMS"/>
Receiving Broadcasts with permissions
If you write particular permission inside manifest file or programmatically which is registered with sender broadcasts then only we can receive broadcasts from sender like below.
This below example is for your receiving app has a manifest-declared receiver
<receiver android:name=".MyBroadcastReceiver"
android:permission="android.permission.SEND_SMS">
<intent-filter>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
</intent-filter>
</receiver>
Or there is other way for your receiving app has a context-registered receiver as shown below
var filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null)
Security thoughts and best practices while sending broadcasts
2. Always use context registered broadcasts than manifest declared receivers. If we use manifest declared receivers it can cause system to launch a lot of apps and it can effect both device performance and use experience.
3. Do not broadcast sensitive data or information using an implicit intent. In this case the information can be read by any app that has registered to receive the broadcast. There are below ways to control
- You can specify a permission when sending broadcast.
- In android 4.0 and higher, you can specify a package name with setPackage() when sending the broadcasts. The android system restricts the broadcasts to the set of apps that has match for sent package.
- You can send local broadcasts with LocalBroadcastManager.
4. While receiving any broadcast there can be case of receiving malicious broadcasts to your app’s receiver. There are below ways to limit this
- You can specify a permission when registering a broadcast receiver.
- For manifest declared receivers, you can set the android:exported attribute to “false” to avoid broadcasts from sources outside of the app.
5. The method onReceive(Context, Intent) runs on the main thread, it should execute and return quickly.If you need to perform long running operations be careful about creating new threads or starting services because the system may kill the entire process after onReceive() returns.
6. Do not start activities from broadcast receivers because the user experience is unpleasant or jarring.