How to send a custom broadcast action to receivers in manifest?
Asked Answered
S

5

25

MyReceiver.java

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.i("MyReceiver", "MyAction received!");
    }
}

In AndroidManifest.xml (under the application tag)

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="MyAction" />
    </intent-filter>
</receiver>

MainActivity.Java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sendBroadcast(new Intent("MyAction"));
    }
}

MyReceiver.onReceive method is never triggered. Did I miss something?

Sink answered 9/3, 2018 at 15:41 Comment(3)
You cannot register receivers for most Intent actions in the manifest on Android 8.0+. What version of Android are you testing on? Also, if both MainActivity and MyReceiver are in the same app, there are better options for in-process messages, such as LocalBroadcastManager, greenrobot's EventBus, RxJava-based event buses, etc.Torbert
I use Android 8. And yes they are in the same app. Even though there many libraries, I wish to know how BroadcastReceiverworks. Furthermore, I don't want to declare my receiver programatically since the MyReceiver will have some system actions in its intent-filter tag. I really want it to be declared in the manifest (as long as it's possible).Sink
It's painful that Android broke this functionality. My use case is this -- I have an app that has several flavors. Some flavors require knowing when the app has been updated so that they can update their database accordingly. The code that updates the app version would like to broadcast the update to receivers that may or may not be registered in the manifest depending on the flavor. Rx & eventbus won't work since the code must already be running to register listeners. The beauty of BR is the ability to invoke code by statically registering it in the manifest.Janetjaneta
T
42

I use Android 8.

Then you have to use an explicit Intent, one that identifies the receiver, such as:

sendBroadcast(new Intent(this, MyReceiver.class).setAction("MyAction"));

See Broacast limitations in Android 8 release docs.

Torbert answered 9/3, 2018 at 15:56 Comment(27)
It's impossible to use only the action? If I've got multiple receivers to trigger. Why Android have restricted its broadcast system? Where does it talk about it in its documentation?Sink
@Yairopro: "It's impossible to use only the action?" -- on Android 8.0+, yes, at least for a receiver that you also intend to use for other broadcasts. See the documentation for more.Torbert
@ChRoNoN: There are only a few IPC mechanisms in Android. If you need to talk across process boundaries within an app, a "broadcast" to a specific receiver is one possibility. It's not an especially common need, and for in-process use, there are many other options that I outlined in a comment on the question.Torbert
@ChRoNoN The action, as its name indicates, tell the receiver what it should do.Sink
@Commonsware For IPC, assuming two users have the same app, is there a way to set up an explicit intent for user A to send an Intent with data to a BroadcastReceiver in user B's app via default SMS app for both? I was able to set up using implicit intent that requires RECEIVE_SMS permission, but now that permission requires approval from Google Play Store administrators.Vaporish
@AJW: I am sorry, but I do not understand the scenario. You might want to ask a separate Stack Overflow question, where you can provide more details.Torbert
@Torbert See more details at this question: #62240017Vaporish
@AJW: Nothing of what you describe there is practical. There are hundreds, if not thousands, of SMS clients, any of which could be the default one for a user. There is no requirement for any of them to support any form of link in a message. Those that do will use startActivity(), not sendBroadcast(), because "click on a link to do something silently on the device without the user's knowledge" is a great vector for malware.Torbert
@Torbert I understand. The objective for clicking on the link is for the recipient to approve taking in the data into the app, from the sender. The sender is a known and trusted friend, family member, co-worker etc. It doesn't have to be a link though, but I thought that would be a convenient way for the recipient to provide approval. As for the malware concern, if the recipient trusts the sender and they trust the app to deliver the data securely, I don't think they will have any problem approving the link. Somehow there could be malware added, like getting a malware email.Vaporish
@AJW: "As for the malware concern, if the recipient trusts the sender and they trust the app to deliver the data securely, I don't think they will have any problem approving the link" -- in your particular case, perhaps. But you are advocating for a feature (send a broadcast from an SMS client) that malware authors would drool over. I worry about an entire planet's worth of users, and so I sincerely hope that no SMS client has that sort of capability.Torbert
@Torbert So I should avoid sending dat thru SMS because a legitimate app with protections like: published with same apk certificate, setPackage() is the same for both sender and recipient and android: protection level is set with signature level permission, the app would be too big of a target for attackers? If so, would sending data via email be any better? Or do I need to rely on a server because that is much more secure than the SMS protections? Struggling with a solution to deliver the data.Vaporish
@AJW: "a legitimate app with protections like: published with same apk certificate, setPackage() is the same for both sender and recipient and android: protection level is set with signature level permission, the app would be too big of a target for attackers?" -- those defenses only have a meaning when you are talking actual IPC (inter-process communication) between two apps on the same device. "would sending data via email be any better?" -- no, in that no email client should be sending a broadcast in response to something contained in an email.Torbert
@AJW: SMS clients and email clients, to the extent they handle links at all, will start activities, not send broadcasts. I do not know why you want to send a broadcast, but neither of those sorts of clients are going to do that for you. "Or do I need to rely on a server" -- that certainly is a typical approach and it gets you away from dealing with other infrastructure interference. But, if you could switch your mental model to activities instead of broadcasts, you might find that SMS or email will work for your needs.Torbert
@Torbert I am happy to switch over to activities for SMS. The only thing I need to work on is not jarring the user by just starting my app when the SMS arrives because they may be doing something else on the device. That is why I thought of the clickable link or clickable image because it doesn't open the activity right away, it is like a pendingIntent on the Activity...it waits for approval from the recipient and then the activity can open to display the new data. Starting an activity will be much safer from malware bad actors than the broadcasts?Vaporish
@AJW: "The only thing I need to work on is not jarring the user by just starting my app when the SMS arrives because they may be doing something else on the device" -- nothing would happen until the user clicked a link. And your question to me was about broadcasts, not activities. "Starting an activity will be much safer from malware bad actors than the broadcasts?" -- yes, in that the user has to click a link, at minimum. SMS clients might offer other protections (e.g., confirmation dialog).Torbert
@Torbert The broadcast was to send the data from the SMS to a BroadcastReceiver, that then starts a JobIntentService that then starts the Activity. So if the broadcast is not safe I will just include a link in the SMS and clicking on the link will start the Activity to show the data (in a CardView). I could then add a popup dialog to confirm user would like to accept the data. Sound copacetic from your vantage point?Vaporish
@AJW: Sure. That is how I would expect this sort of thing to work. And what you wanted ("a JobIntentService that then starts the Activity") isn't possible on modern versions of Android anyway (no background activity starts). The question that you linked to is about the details of the message to pull that off, and I think that what you want is going to be too fancy to be reliable. But, the general flow of "you send message with a deep link, and recipient clicks that link to trigger their copy of the app to do some work" is perfectly reasonable.Torbert
@Torbert Excellent, I appreciate all of the feedback. Cheers.Vaporish
@Torbert One more issue I am struggling with is the passing of the data from app user A to same app user B's MainActivity. What would I need to do to pass the plain/text data received into user B's default SMS app to user B's MainActivity? I don't think I get access to the default SMS app and I am avoiding use of a BroadcastReceiver so can't use Object[], .get("pdus") and creatFromPdu() methods that I see in other answers on stackoverflow.Vaporish
@AJW: Put it in the URL that you are using for your deeplink. Or, put an identifier in that URL that allows App B to obtain the data from your Web service.Torbert
@Torbert There is no Web service, just user A texting user B with the default SMS app. So just attach the data (JSONObject) to the URL clickable link?Vaporish
@AJW: "There is no Web service, just user A texting user B with the default SMS app" -- if you wish to pass significant data, SMS is a lousy transport mechanism. "So just attach the data (JSONObject) to the URL clickable link?" -- you are giving yourself no other choice, AFAICT.Torbert
@Torbert Not significant data and will try the URL route, ty!Vaporish
@Torbert I'm not finding any good examples or tutorials on stackoverflow or google search on attaching a JsonObject to a URL...do you know of any examples or tutorials that can steer me in the right direction?Vaporish
@AJW: I don't know which JsonObject you are referring to. Converting an object to a JSON string is fairly commonly done. I tend to use Moshi, and it is covered in the very first section of the README. Once you have a JSON string, you can put it as a query parameter on a URL, as you would any other string or number.Torbert
@Torbert So I'm able to send data between the 2 users. But the String value as a query parameter is added to the end of the URL's scheme/host. If the String has many characters then the URL link becomes very long, not user-friendly i/m/o. Is there any way to pass the String characters by attaching them say as an object for the query parameter value? The object could then have a much shorter name, so that the clickable link ends ups much shorter. Then the object would be "unpacked" (like JSON parsing?) to get the String characters that were sent to the other user's Activity via SMS?Vaporish
@AJW: "Is there any way to pass the String characters by attaching them say as an object for the query parameter value?" -- no more than you can do that for a Web URL, which in effect is what you are creating.Torbert
D
5

In Android 8 onwords

  • We need to provide the explicite class for handling i.e setcomponent param along with action

Example :

  private void triggerBroadCast(String firstFavApp, String secondFavApp) {
        Intent intent = new Intent("FavAppsUpdated");
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
        intent.putExtra("FIRST_FAV_APP", firstFavApp);
        intent.putExtra("SECOND_FAV_APP", secondFavApp);
        intent.setComponent(new
                ComponentName("com.android.systemui",
                "com.android.systemui.statusbar.phone.FavAppsChanged"));

        Log.i(TAG, "Trigger Fav Apps" + firstFavApp + " " + secondFavApp);
        favouriteContract.getAppContext().sendBroadcast(intent);
    }

Below Android 8

  • Only action is enough for receiving Broadcast

   void broadCastParkingStates(Context context) {
        Intent intent = new Intent("ReverseCameraStates");
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
        intent.putExtra("PARKING_GUIDE", ReverseCameraPreference.getParkingGuide(context));
        intent.putExtra("PARKING_SENSOR", ReverseCameraPreference.getParkingSensor(context));
        intent.putExtra("TRAJECTORY", ReverseCameraPreference.getTrajectory(context));
        Log.i("BootCompletedReceiver", "Sending Reverse Camera settings states BaordCast");
        Log.i("BootCompletedReceiver", "States Parking:Sensor:Trajectory="
                + intent.getExtras().getBoolean("PARKING_GUIDE")
                + ":" + intent.getExtras().getBoolean("PARKING_SENSOR")
                + ":" + intent.getExtras().getBoolean("TRAJECTORY")
        );
        context.sendBroadcast(intent);
    }
Dismember answered 29/12, 2018 at 6:55 Comment(2)
Does your solution work for two users who are using the same app? I would like to see if there a way to set up an explicit intent for user A to send an Intent with data to a BroadcastReceiver in user B's app via default SMS app for both? I was able to set up using implicit intent that requires RECEIVE_SMS permission, but now that permission requires approval from Google Play Store administrators.Vaporish
Checked just now it is working inside app as well ThanksDismember
E
4

If you have multiple receivers, you can send broadcast to all the receivers using only custom action defined in manifest for that you need to add the following flag while sending broadcast

Note: I have used adb to test it on Android 10, you can add it in application

FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000

adb shell am broadcast -a MyAction -f 0x01000000
Eructate answered 13/10, 2020 at 5:32 Comment(1)
The -f flag was the difference maker for me to be able to test on Android 10Inpour
I
3

In Kotlin:

val intent = Intent(this, MyBroadCastReceiver::class.java)
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.action = "my.custom.broadcast"
sendBroadcast(intent)
Isidor answered 12/3, 2019 at 7:53 Comment(0)
Z
-1

The string itself does not matter, just need to be the same in all places and unique, I use fully qualified name of the constant.

<receiver android:name="com.mypackage.receivers.MyBroadcastReceiver">
    <intent-filter>
        <action android:name="com.mypackage.receivers.MyBroadcastReceiver.ACTION_CUSTOM"/>
    </intent-filter>
</receiver>

The receiver:

package com.mypackage.receivers;

public class MyBroadcastReceiver extends BroadcastReceiver {
    public static final String ACTION_CUSTOM = "com.mypackage.receivers.MyBroadcastReceiver.ACTION_CUSTOM";
@Override
    public void onReceive(Context context, Intent intent) {
      if (ACTION_CUSTOM.equals(intent.getAction())) {
            // do custom action
        }
    }
}

To broadcast the intent:

sendBroadcast(new Intent(MyBroadcastReceiver.ACTION_CUSTOM));
Zeller answered 10/8, 2018 at 18:28 Comment(2)
On Android 8 it seems you cannot do that anymore.Sink
Indeed, they changed it Oreo.Zeller

© 2022 - 2024 — McMap. All rights reserved.