0

Lets say I have a String test = "value" available in a service and want to send it to my running mainactivity. How does one send that data safely? Im looking for the most simple example possible, where the data can not be seen by other apps. When I look at intents it says:

A broadcast is a message that any app can receive. The system delivers various broadcasts for system events, such as when the system boots up or the device starts charging. You can deliver a broadcast to >>>>other apps<<< by passing an Intent to sendBroadcast() or sendOrderedBroadcast().

However I want to send it to my app only as it contains private data. In my service I tried:

Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(getString(R.string.notification_intent), "6");
startActivity(intent);

Where MainActivity.class is the class that should receive the intent, but in this way I get:

Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

How can I safely send data from a service to an activity?

Sven van den Boogaart
  • 11,833
  • 21
  • 86
  • 169

1 Answers1

2

Q: How do I send data from an Android service to my activity?

A: You have several alternatives:

1. Use intents:

How to get data from service to activity

Send msg from service:

private static void sendMessageToActivity(Location l, String msg) {
    Intent intent = new Intent("GPSLocationUpdates");
    // You can also include some extra data.
    intent.putExtra("Status", msg);
    Bundle b = new Bundle();
    b.putParcelable("Location", l);
    intent.putExtra("Location", b);
    LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

Register to receive message in activity:

LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
            mMessageReceiver, new IntentFilter("GPSLocationUpdates"));

Custom message receiver in activity:

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Get extra data included in the Intent
        String message = intent.getStringExtra("Status");
        Bundle b = intent.getBundleExtra("Location");
        lastKnownLoc = (Location) b.getParcelable("Location");
        ...

I would NOT characterize this as "unsafe" - it can be a perfectly reasonable approach.

2. Have the activity bind to the service

https://developer.android.com/guide/components/bound-services

Service:

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder binder = new LocalBinder();
    ...
public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }


    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

Activity:

@Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
        ...
     @Override
        protected void onStop() {
            super.onStop();
            unbindService(connection);
            mBound = false;
        ...
    /** Defines callbacks for service binding, passed to bindService() */
        private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }
    ...
    // To use the service, your client would call mService.someMethod()...            

I'm not sure exactly what you're looking for, but example 1 is probably your best bet.

Here's a tutorial that might help give you more details/more ideas:

Basics Of Services In Android:


https://developer.android.com/guide/components/broadcasts

Android provides three ways for apps to send broadcast:

  • The sendOrderedBroadcast(Intent, String) method sends broadcasts to one receiver at a time.
  • 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.

Additionally:

https://developer.android.com/guide/components/broadcasts#restrict-broadcasts-permissions

Restricting broadcasts with permissions

Permissions allow you to restrict broadcasts to the set of apps that hold certain permissions. You can enforce restrictions on either the sender or receiver of a broadcast.

Sending with permissions

When you call sendBroadcast(Intent, String) or sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle), you can specify a permission parameter. Only receivers who have requested that permission with the tag in their manifest (and subsequently been granted the permission if it is dangerous) can receive the broadcast. For example, the following code sends a broadcast:

Personally, I don't see any "security" issue at all with simply using an intent.

But if you want or need to, you can use the above techniques to further lock down communications.

'Hope that helps!

FoggyDay
  • 11,962
  • 4
  • 34
  • 48
  • "Security consciousness" is a Good Thing. There are *LOTS* of things you're justified in being paranoid about. But frankly, I don't thnk some other app attempting to register to read one of your intents is one of them :( Nevertheless, Android gives you several options . Please see my updates above. – FoggyDay May 31 '20 at 00:30
  • Thanks a ton for the answer. I have a question what is context in : 'LocalBroadcastManager.getInstance(context).sendBroadcast(intent);' – Sven van den Boogaart May 31 '20 at 00:40
  • 1
    Application Context: https://stackoverflow.com/a/22355974/3135317 – FoggyDay May 31 '20 at 02:20