Detect CONNECTIVITY CHANGE in Android 7 and above when app is killed/in background

android check internet connection
android check internet connection listener
android check internet connection continuously
network change receiver android oreo
detect slow internet connection android
how to check internet connection in android programmatically
connectivity monitor android
android connectivity

Problem:

So the problem is that I have an app which sends a request to our backend whenever WiFi is connected (with the connected SSID and other info) or when it is disconnected (over the mobile network). However with the changes in Android 7/N and above, CONNECTIVITY_CHANGE and CONNECTIVITY_ACTION no longer work in the background. Now in most cases people misuse this broadcast and as such I can completely understand why the change was made. However, I have no idea how to solve this problem in the current state.

Now I'm not at all much of an Android developer (this is for a Cordova plugin) so I'm counting on you guys!

Expected behavior: App is woken up and request is sent whenever WiFi switches connectivity, even when app is killed/in background.

Current behavior: App only sends request when the app is in the foreground.

Tried so far: So far I've moved the implicit intent to listen to CONNECTIVITY_ACTION from the manifest to manually registering it in the main part of the app (plugin). This makes it work as long as the app is in memory but not on cold boot or actual background

Already looked at: Most answers talk about using scheduled jobs to substitute for the missing broadcast. I see how this works for, for example, retrying a download or similar, but not for my case (but please correct me if I'm wrong). Below are the SO posts I've already looked at:

Detect connectivity changes on Android 7.0 Nougat when app is in foreground

ConnectivityManager.CONNECTIVITY_ACTION deprecated

Detect Connectivity change using JobScheduler

Android O - Detect connectivity change in background

Nougat and Above: We have to use JobScheduler and JobService for Connection Changes.

All I can divide this into three steps.

Register JobScheduler inside activity. Also, Start JobService( Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler ultimately land on this service's "onStartJob" method.)

public class NetworkConnectionActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_network_connection);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        scheduleJob();

    }


    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void scheduleJob() {
        JobInfo myJob = new JobInfo.Builder(0, new ComponentName(this, NetworkSchedulerService.class))
                .setRequiresCharging(true)
                .setMinimumLatency(1000)
                .setOverrideDeadline(2000)
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                .setPersisted(true)
                .build();

        JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.schedule(myJob);
    }

    @Override
    protected void onStop() {
        // A service can be "started" and/or "bound". In this case, it's "started" by this Activity
        // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
        // to stopService() won't prevent scheduled jobs to be processed. However, failing
        // to call stopService() would keep it alive indefinitely.
        stopService(new Intent(this, NetworkSchedulerService.class));
        super.onStop();
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Start service and provide it a way to communicate with this class.
        Intent startServiceIntent = new Intent(this, NetworkSchedulerService.class);
        startService(startServiceIntent);
    }
}

The service to start and finish the job.

public class NetworkSchedulerService extends JobService implements
        ConnectivityReceiver.ConnectivityReceiverListener {

    private static final String TAG = NetworkSchedulerService.class.getSimpleName();

    private ConnectivityReceiver mConnectivityReceiver;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service created");
        mConnectivityReceiver = new ConnectivityReceiver(this);
    }



    /**
     * When the app's NetworkConnectionActivity is created, it starts this service. This is so that the
     * activity and this service can communicate back and forth. See "setUiCallback()"
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        return START_NOT_STICKY;
    }


    @Override
    public boolean onStartJob(JobParameters params) {
        Log.i(TAG, "onStartJob" + mConnectivityReceiver);
        registerReceiver(mConnectivityReceiver, new IntentFilter(Constants.CONNECTIVITY_ACTION));
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        Log.i(TAG, "onStopJob");
        unregisterReceiver(mConnectivityReceiver);
        return true;
    }

    @Override
    public void onNetworkConnectionChanged(boolean isConnected) {
        String message = isConnected ? "Good! Connected to Internet" : "Sorry! Not connected to internet";
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();

    }
}

Finally, The receiver class which checks the network connection changes.

public class ConnectivityReceiver extends BroadcastReceiver {

    private ConnectivityReceiverListener mConnectivityReceiverListener;

    ConnectivityReceiver(ConnectivityReceiverListener listener) {
        mConnectivityReceiverListener = listener;
    }


    @Override
    public void onReceive(Context context, Intent intent) {
        mConnectivityReceiverListener.onNetworkConnectionChanged(isConnected(context));

    }

    public static boolean isConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }

    public interface ConnectivityReceiverListener {
        void onNetworkConnectionChanged(boolean isConnected);
    }
}

Don't forget to add permission and service inside manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.yourpackagename">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>


    <!-- Always required on api < 21, needed to keep a wake lock while your job is running -->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <!-- Required on api < 21 if you are using setRequiredNetworkType(int) -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!-- Required on all api levels if you are using setPersisted(true) -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <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=".connectivity.NetworkConnectionActivity"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

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


        <!-- Define your service, make sure to add the permision! -->
        <service
            android:name=".connectivity.NetworkSchedulerService"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE"/>
    </application>

</manifest>

Please refer below links for more info.

https://github.com/jiteshmohite/Android-Network-Connectivity

https://github.com/evant/JobSchedulerCompat

https://github.com/googlesamples/android-JobScheduler

https://medium.com/@iiro.krankka/its-time-to-kiss-goodbye-to-your-implicit-broadcastreceivers-eefafd9f4f8a

Detect network state and Upload video data from background when , Above upload happens when the network gets available even when the app is killed. Now for detecting network change, in Android N and above  So the problem is that I have an app which sends a request to our backend whenever WiFi is connected (with the connected SSID and other info) or when it is disconnected (over the mobile network). However with the changes in Android 7/N and above, CONNECTIVITY_CHANGE and CONNECTIVITY_ACTION no longer work in the background.

The best way to grab Connectivity change Android Os 7 and above is register your ConnectivityReceiver broadcast in Application class like below, This helps you to get changes in background as well until your app alive.

public class MyApplication extends Application {

      private ConnectivityReceiver connectivityReceiver;

      private ConnectivityReceiver getConnectivityReceiver() {
          if (connectivityReceiver == null)
               connectivityReceiver = new ConnectivityReceiver();

          return connectivityReceiver;
       }
       @Override
       public void onCreate() {
         super.onCreate();
         registerConnectivityReceiver();
       }

     // register here your filtters 
     private void registerConnectivityReceiver(){
       try {
          // if (android.os.Build.VERSION.SDK_INT >= 26) {
          IntentFilter filter = new IntentFilter();
          filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
          //filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
          //filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
          //filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
          registerReceiver(getConnectivityReceiver(), filter);
       } catch (Exception e) {
         MLog.e(TAG, e.getMessage());
       }
 }

}

And then in manifest

     <application
      android:name=".app.MyApplication"/>

Here is your ConnectivityReceiver.java

 public class ConnectivityReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
      MLog.v(TAG, "onReceive().." + intent.getAction());
      }
    }

Android 8.0 Behavior Changes, Nougat and Above: We have to use JobScheduler and JobService for Connection Changes. All I can divide this into three steps. Register  Sign up. Detect CONNECTIVITY CHANGE in Android 7 and above whether app is in foreground or in background. 3 commits. 1 branch. 0 packages. 0 releases. Fetching contributors. Java. Java 100.0%.

That's how i did it. I have created a IntentService and in onCreate method and I have registered networkBroadacst which check for internet connection.

public class SyncingIntentService extends IntentService {
    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            networkBroadcast=new NetworkBroadcast();
            registerReceiver(networkBroadcast,
                  new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        }
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onHandleIntent(intent);
        return START_STICKY;
    }
}

This is my broadcast class

public class NetworkBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Constants.isInternetConnected(context)) {
//            Toast.makeText(context, "Internet Connect", Toast.LENGTH_SHORT).show();
           context.startService(new Intent(context, SyncingIntentService.class));
        }
        else{}
    }
}

In this way you can check internet connection in whether your app is in foreground or background in nougat.

Monitoring Wi-Fi Connectivity Status in a post nougat world, The app should be able to monitor Wi-Fi connection status as real-time a single network switch can cause them all to wake up and process the broadcast at once. be in the killed state but we still want to monitor connectivity change. Later, as part of the Android 8.0 (API level 26) Background Execution  I want to check whether the Internet is available or not in the background even when the app is not running. There is no problem in Android version M or below, In Android N broadcast receiver does not work like that. So I am finding a solution check network connectivity in the background – Paras Watts Aug 28 '17 at 4:26

A good example of background service getting location updates , It is impossible to find A GOOD EXAMPLE of how create a service that must run in My app aim is get location updates in background, something which looks like so I need location from GPS but when I remove Network provider and use GPS when i check result android 7 will show up notification above while doing in  Looks like it's not possible to get notified when the connection changes: With Android 7.0 CONNECTIVITY_ACTION receivers declared in the manifest won't receive broadcasts. Additionally receivers declared programmatically only receive the broadcasts if the receiver was registered on the main thread (so using a service won't work).

Another approach which is simpler and easier when you use registerNetworkCallback (NetworkRequest, PendingIntent):

NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
builder.addTransportType(NetworkCapabilities.TRANSPORT_VPN);

ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
Intent intent = new Intent(this, SendAnyRequestService.class);

PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (connectivityManager != null) {
    NetworkRequest networkRequest = builder.build();
    connectivityManager.registerNetworkCallback(networkRequest, pendingIntent);
}

Which is SendAnyRequestService.class is your service class, and you can call your API inside it.

This code work for Android 6.0 (API 23) and above

Ref document is here

How to kill background apps on Android 10, A brand new phone is a wondrous thing, but over time your shiny Switching between apps becomes a frustrating experience and your battery won't get you through a day. Here's how to find your Running services on Android 10. For Android Nougat and Doze 2.0, that feature now works when your  As mentioned above in (2), the AsyncTask is used to make a network call once the ConnectivityManager gives the app the thumbs up that there is connectivity. From here the AsyncTask provides a set of methods that call back to the MainActivity to perform updates during the life cycle of the task.

Notifications Not Shown, If your device has unstable or no internet connection, the push will not show until a You can find your player id with this guide to make sure your device is still of the OneSignal SDK and have the app running in the background when you test Pre-EMUI 5.0 / Android 7 - Go to Settings > "Protected apps", check your app. If an app targets Android 7.0, all of its processes (foreground and background) are notified of the configuration change as described in Handling Runtime Changes. Most apps do not need to make any changes to support this feature, provided the apps follow Android best practices.

Oneplus, OnePlus and their OxygenOS Android modification is known for maximizing the stock This will avoid the app to be killed in background and the Battery optimisation setting to and in those times it will then disable the phone's network connections. manager might be set up in a way that swiping the app to close will kill it. But to detect connectivity change in background is mandatory for any sip-apps (VoIP) those apps are normally running in background for days and jump to foreground only if a call comes in (just like your dialer of the phone) Those apps need to reconnect automatically in background. This kills all those apps (that don't have their own push server) from the android platform as they will be offline. always.

Android Detect Internet Connection Status, Detecting internet connection status in your app is very easy and won't take more than 5mins. Using broadcast receiver, your app will be automatically notified when there is a change in network connection. Follow the above same three steps in all other activities in which in you want to notify Evergreen Posts & Pages. Below Nougat, using CONNECTIVITY_ACTION we can detect connectivity changes when the app is in background, foreground and even when the app is not running. From Nougat, as from documentation : "Apps targeting Android 7.0 (API level 24) and higher do not receive CONNECTIVITY_ACTION broadcasts if they declare their broadcast receiver in the manifest.

Comments
  • Thank you for this elaborate answer! (others as well) My coworker wil be looking into this at a later moment. However, the information looks great
  • By the way, CONNECTIVITY_ACTION is deprecated in API 28 (Pie) developer.android.com/reference/android/net/…
  • Be careful forgetting "setRequiresCharging(true)" in, will make it that you require the phone to be charging for the Job to fire.
  • Does the broadcast receiver continue to work when the app is swiped out from recent apps? (I tried it on Goole Pixel with Oreo and it didn't work)
  • I only want to know if network connectivity change, I don't know why Android makes it terrible
  • Question here is how to get the CONNECTIVITY_CHANGE broadcast when app is in background
  • Please read the question correctly and answer it, the need is to know the network change even when app is killed.
  • @ManojPerumarath I did not said this final answer, I just given my solution, Stack-overflow is there to give different answers.
  • Sorry, this is still considered incorrect since this does not do what the OP wanted.
  • What happens if you application dies? Will the service stay? There's a bug that causes your service to die as soon as your activity is stopped regardless of whether the service and application are in isolated processes.
  • i dont think so. the issue is that connectivity_change doesnt work anymore in N above so the receiver is useless since it cannot get those events.
  • They cannot be serious!!! But I fear you are right... What if there are apps like time-tracking which want to automate start/stop via connected WiFi network?
  • @Marius That's why you use JobScheduler. For newer versions and still keep CONNECTIVITY_CHANGE in manifest for older Android versions
  • Google is extremely serious about their bad APIs, and about the random breaking changes that they keep making to make their bad APIs worse.