9

So I have two different apps made, one sends a broadcast and another receives it and displays a toast. However, when I close the receiver app the broadcast is no longer received by the second app even though I defined the receiver in the manifest file.

The broadcast sender in the MainActivity of app1.

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button b = (Button)findViewById(R.id.button2);
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent i = new Intent();
            i.setAction("com.example.ali.rrr");
            i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
            sendBroadcast(i);
            Log.e("Broadcast","sent");
        }
    });
}

App 2 broadcast receiver:

public class MyReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    // TODO: This method is called when the BroadcastReceiver is receiving
    // an Intent broadcast.
    Toast.makeText(context, "Broadcast has been recieved!", Toast.LENGTH_SHORT).show();
    Log.e("SUCCESS", "IN RECIEVER");
    //throw new UnsupportedOperationException("Not yet implemented");
}

App 2s Manifest:

<?xml version="1.0" encoding="utf-8"?>

<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">
    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.ali.rrr" />
        </intent-filter>
    </receiver>

    <activity
        android:name=".MainActivity"
        android:label="@string/title_activity_main"
        android:theme="@style/AppTheme.NoActionBar" />
    <activity
        android:name=".Main2Activity"
        android:label="@string/title_activity_main2"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

Codey
  • 460
  • 1
  • 8
  • 23
kumail
  • 1,331
  • 4
  • 13
  • 19
  • You should unRegister your broadcast receiver when your app destroyed and you can use Service instead of the broadcast receiver. – Mohit Kacha May 24 '17 at 05:49
  • its working when open app 2 (Receiver app)? – Jd Prajapati May 24 '17 at 05:50
  • @MohitKacha I'm trying to get this to work as a broadcastReceiver, a statically registered receiver in the Manifest should work even when the app is closed. – kumail May 24 '17 at 05:51
  • @JdPrajapati Yes it's working when I keep App2 open in the background. – kumail May 24 '17 at 05:52
  • @kumail you can only achieve this using combination of Service and Reciever. But your code uses Activity to broadcast so it is not possible as activity needs context and context can not be provided while activity is in the background – Pratik Vyas May 24 '17 at 09:56
  • @PratikVyas Your comment is nonsense and wrong. This should work just fine. – David Wasser May 24 '17 at 11:38
  • What device(s) are you testing on? There are devices where your app needs to be in a list of "protected apps" in order for Android to start it in the background. – David Wasser May 24 '17 at 11:39
  • Are you sure that the broadcast is not received? How are you verifying that? Toast is not a reliable debugging method. Check your logcat! – David Wasser May 24 '17 at 11:41
  • @DavidWasser you mean application can broadcast without using service while it is in the background, can you please share your "sensible" example so that I can get where I am lacking? – Pratik Vyas May 24 '17 at 11:43
  • @PratikVyas OP has 2 apps. He broadcasts from `MainActivity` in one app and listens for the broadcast in the other app. There is no requirement here to "broadcast from the background". You need to read the question more carefully. – David Wasser May 24 '17 at 11:47
  • @PratikVyas also your statement "...activity needs context and context can not be provided while activity is in the background" is wrong. An `Activity` is a `Context` and of course you can broadcast from an `Activity` even when it is in the background (if you want to) by starting a thread, setting a timer, etc. – David Wasser May 24 '17 at 11:49
  • @DavidWasser yeah I got that, I read it wrong, thanks for the explanation – Pratik Vyas May 24 '17 at 11:50

5 Answers5

26

After registering my BroadcastReceiver (BR) statically in the manifest, applying the proper intent filters, using JobIntentService (and registering it in the manifest) to handle the work that was called from my BR, I was still getting inconsistent results.

Once all of what I listed above has been done you should be able to send an ADB command to activate your broadcast and process the work in your service even if the app is closed. This was working for me some of the time, but not all of the time.

This article describes limitation to BRs. "As of Android 3.1 the Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu" (AKA a user executes Force Stop)

When I start the app by debugging it, then swipe it closed on my device, my ADB command never activates my BR. However, after my debugging session is over, when I open up the app on my device and swipe it closed, I can activate my BR through ADB commands.

This occurs because when you debug an application, then manually swipe it closed on the device, Android considers this a Force Stop hence why my BR cannot be activated until I re-open the app on the device without debugging.

Scoured the internet for hours, and wasn't able to find my solution, so I thought I'd post it here just in case some poor unfortunate soul is encountering the same weird functionality I was.

Happy coding :)

MedievalCoder
  • 627
  • 7
  • 10
  • I just noticed I'm debugging the apps. After I manually open the apps, its working fine the BR. Thanks ! – Ticherhaz FreePalestine Jun 30 '20 at 06:44
  • I spent a lot of time debugging the app before finding this answer. Thanks a lot for sharing this. I would have wasted a lot more time otherwise! ;-) – Yogesh Nov 27 '20 at 11:57
  • 1
    So any solution to this problem? I want to get call the BroadcastReceiver even after app was force closed. – shaby Aug 11 '21 at 09:20
  • @shaby unfortunately I'm unaware of Android OS changing this behavior and don't think it's likely they would. Think about it from a user perspective. If you Force Stop an app, you wouldn't want it randomly executing (potentially long running) background operations when you haven't re-enabled that application, right – MedievalCoder Aug 19 '21 at 16:11
4

First of all you need to use the Service for this functionality to work.

In the Activity you can start and stop the service by using the below codes.

// to start a service
Intent service = new Intent(context, MyBrodcastRecieverService.class);
context.startService(service);

// to Stop service
Intent service = new Intent(context, MyBrodcastRecieverService.class);
context.stopService(service);

Then you can use the below service

public class MyBrodcastRecieverService extends Service
{
    private static BroadcastReceiver br_ScreenOffReceiver;

    @Override
    public IBinder onBind(Intent arg0)
    {
        return null;
    }

    @Override
    public void onCreate()
    {
        registerScreenOffReceiver();
    }

    @Override
    public void onDestroy()
    {
        unregisterReceiver(br__ScreenOffReceiver);
        m_ScreenOffReceiver = null;
    }

    private void registerScreenOffReceiver()
    {
        br_ScreenOffReceiver = new BroadcastReceiver()
        {
            @Override
            public void onReceive(Context context, Intent intent)
            {
                Log.d(TAG, "ACTION_SCREEN_OFF");
                // do something, e.g. send Intent to main app
            }
        };
        
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        registerReceiver(br_ScreenOffReceiver, filter);
    }
}
Mohammad Hassany
  • 898
  • 1
  • 14
  • 30
Sujith Ks
  • 360
  • 2
  • 10
  • 1
    any way to do it only using the broadcast receiver? – kumail May 24 '17 at 06:38
  • If you register you own BroadcastReceiver in the manifestfile as reciever it will always be called. – Sujith Ks May 24 '17 at 06:56
  • If you satisfy with my answer can you please make it as accepted so that I can help some others too. – Sujith Ks May 24 '17 at 07:15
  • It is not necessary to use a `Service` for this purpose. – David Wasser May 24 '17 at 11:40
  • 3
    @SujithKs i did register it in the Manifest but its only called when the app is opened. – kumail May 24 '17 at 15:23
  • @SujithKs I also did register it in the Manifest but it's not working when the app is closed. – mazend Oct 11 '20 at 13:09
  • @SujithKs Oh.. I want to correct it. Sometimes it's working. Even though I closed my app it is created from the Application class.. and it receives intents. I'm not sure why it's working now.. – mazend Oct 11 '20 at 13:22
  • From Android 7 (Android 8 made it even more stringent) in most use cases manifest-declared Broadcast won't work anymore and must be replaced with scheduled jobs or services. – alexanderdavide May 19 '22 at 10:39
4

I faced this issue recently. The BroadcastReceiver was working fine even if the app was removed from the background in the emulator and Samsung phones. But it failed to start my app in Chinese manufactured phones like Realme, Mi etc. While struggling to find a way to fix this I found that in the app details page there is battery optimisation settings where the Auto-launch feature was disabled. After I enabled it the app was working fine and BroadcastReceiver was able to start the app. I was unable ti find a way to enable this setting programmatically but I found this question which helped me direct the user to that setting page.

Rauson Ali
  • 111
  • 10
1

You can go through below solution;

Activity.java

Intent intent=new Intent(MainActivity.this,BroadcastService.class);
startService(intent);

BroadcastService.java

public class BroadcastService extends Service {

private static MusicIntentReceiver br_ScreenOffReceiver;

@Override
public IBinder onBind(Intent arg0)
{
    return null;
}

@Override
public void onCreate()
{
    registerScreenOffReceiver();
}

@Override
public void onDestroy()
{

}

private void registerScreenOffReceiver()
{
    br_ScreenOffReceiver = new MusicIntentReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
                int state = intent.getIntExtra("state", -1);
                switch (state) {
                    case 0:
                        Log.e("AAAAAAAAAA", "Headset is unplugged");
                        break;
                    case 1:
                        Log.e("AAAAAAAAA", "Headset is plugged");
                        break;
                    default:
                        Log.e("AAAAAAAAAAAA", "I have no idea what the headset state is");
                }
            }
        }
    };
    IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
    registerReceiver(br_ScreenOffReceiver, filter);
}


}

Menifest

<service android:enabled="true" android:name=".BroadcastService" />
Vishal Vaishnav
  • 3,346
  • 3
  • 26
  • 57
0

Try this way..

Intent i = new Intent();
i.setAction("com.example.ali.rrr");
i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
i.setComponent(  
        new ComponentName("PackageNameApp2","PackageNameApp2.MainActivity"));  
sendBroadcast(i);
Jd Prajapati
  • 1,953
  • 13
  • 24