Android global broadcast makes different android apps’ communication easy and clear, but it also has below security issues.
- Any android apps can send the same broadcast intent action which your application broadcast receiver listens. This issue can make your app being attacked.
- Any android apps can listen to your app’s broadcast receiver registered action. So your data may be intercepted by those apps.
To resolve the above security issue, android provides the LocalBroadcastManager class which can make the broadcast sent and received internally just in your app.
1. LocalBroadcastManager Example.
- This example contains two android apps App One and App Two. They are created in the different android projects and executed in the same android emulator.
- The source code of the two apps is almost similar. All have a button, when the user clicks the button, it will send a broadcast to the registered broadcast receiver.
- If the apps send a global broadcast then all the broadcast receivers registered in App One and App Two can receive the broadcast, and each app will show a toast popup message at the screen bottom like the below video shows.
If you can not watch the above video, you can see it on the youtube URL https://youtu.be/22uG_iffAhQ
- If the apps send local broadcasts using LocalBroadcastManager, then each app can only receive the broadcast sent by the app locally shown in the below video.
If you can not watch the above video, you can see it on the youtube URL https://youtu.be/eiV6wQysqgo
2. How To Use LocalBroadcastManager To Send Local Broadcast.
- Get an instance of the LocalBroadcastManager.
localBroadcastManager = LocalBroadcastManager.getInstance(this);
- Create a broadcast receiver and register it use the LocalBroadcastManager object.
localBroadcastManager.registerReceiver(receiverTwo, intentFilter);
- Use LocalBroadcastManager instance to send broadcast.
localBroadcastManager.sendBroadcast(intent);
- Do not forget to unregister the broadcast receiver use LocalBroadcastManager.
localBroadcastManager.unregisterReceiver(receiverTwo);
3. LocalBroadcastManager Example Source Code.
- To run this example, you need to create two android projects. One project includes one android app.
- You should start one android emulator and run the two apps in the same emulator.
- Below is the example project one‘s source files list.
./ ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ └── dev2qa │ │ │ └── example │ │ │ ├── broadcast │ │ │ │ ├── activity │ │ │ │ │ ├── LocalBroadcastOneActivity.java │ │ │ │ ├── receiver │ │ │ │ │ ├── LocalBroadcastReceiverOne.java
- Below is the example project two‘s source files list.
./ ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ └── dev2qa │ │ │ └── androidexample │ │ │ ├── broadcast │ │ │ │ ├── activity │ │ │ │ │ ├── LocalBroadcastTwoActivity.java │ │ │ │ ├── receiver │ │ │ │ │ ├── LocalBroadcastReceiverTwo.java
- From the above example projects files list, we can see that App Two‘s source code is very similar to App One, but just in a different android project.
3.1 Project One App One Source Files.
3.1.1 Layout XML File.
- activity_local_broadcast_one.xml
<Button android:id="@+id/send_local_broadcast_one_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Send Broadcast In Activity One"/>
3.1.2 Activity Java File.
- LocalBroadcastOneActivity.java
package com.dev2qa.example.broadcast.activity; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import com.dev2qa.example.R; import com.dev2qa.example.broadcast.receiver.LocalBroadcastReceiverOne; public class LocalBroadcastOneActivity extends AppCompatActivity { public static final String LOCAL_BROADCAST_ACTION = "com.dev2qa.example.broadcast.activity.LOCAL_BROADCAST"; public static final String LOCAL_BROADCAST_SOURCE = "LOCAL_BROADCAST_SOURCE"; private LocalBroadcastManager localBroadcastManager = null; private LocalBroadcastReceiverOne receiverOne = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_local_broadcast_one); setTitle("App One. dev2qa.com - Local Broadcast Manager Example."); // Get local broadcast manager object. localBroadcastManager = LocalBroadcastManager.getInstance(this); // Create local broadcast receiver one. receiverOne = new LocalBroadcastReceiverOne(); // Create intent filter, add filter action. IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(LOCAL_BROADCAST_ACTION); // Register receiver one to local broadcast manager. localBroadcastManager.registerReceiver(receiverOne, intentFilter); //registerReceiver(receiverOne, intentFilter); Button sendBroadcastOneButton = (Button)findViewById(R.id.send_local_broadcast_one_button); sendBroadcastOneButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // When being clicked, it will send a local broadcast with the sender info. Intent intent = new Intent(LOCAL_BROADCAST_ACTION); intent.putExtra(LOCAL_BROADCAST_SOURCE, "Activity One"); localBroadcastManager.sendBroadcast(intent); //sendBroadcast(intent); } }); } @Override protected void onDestroy() { super.onDestroy(); if(localBroadcastManager!=null) { // Do not forget unregister the local broadcast receiver in onDestroy method. localBroadcastManager.unregisterReceiver(receiverOne); //unregisterReceiver(receiverOne); } } }
3.1.3 Broadcast Receiver One Java File.
- LocalBroadcastReceiverOne.java
package com.dev2qa.example.broadcast.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; import com.dev2qa.example.broadcast.activity.LocalBroadcastOneActivity; public class LocalBroadcastReceiverOne extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(LocalBroadcastOneActivity.LOCAL_BROADCAST_ACTION.equals(action)) { String fromActivity = intent.getStringExtra(LocalBroadcastOneActivity.LOCAL_BROADCAST_SOURCE); Toast.makeText(context, "Receiver one receive broadcast from " + fromActivity, Toast.LENGTH_LONG).show(); } } }
3.1.4 AndroidManifest.xml File.
- AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.dev2qa.androidexample"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".broadcast.activity.LocalBroadcastOneActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Great post! I found the example on Android Local Broadcast Manager really helpful for understanding how to implement this feature in my app. Also, the iPhone tricks you mentioned were an added bonus. Keep up the good work!
what is the use of checking if(LocalBroadcastOneActivity.LOCAL_BROADCAST_ACTION.equals(action)) in LocalBroadcastReceiverOne.java,because you used intentFilter.addAction(LOCAL_BROADCAST_ACTION) in LocalBroadcastOneActivity.java which only listens to LOCAL_BROADCAST_ACTION?
This line of code is for general purpose, because in real android application, there are multiple actions in general. So it is a good habit to check the action value. Another reason is that this can avoid spam attack. If you do not check the action value, then any action can invoke the code. So the invoker app do not need to guess the action value at all.