当应用程序被杀死/在后台运行时,检测Android 7及更高版本中的连接更改

问题描述:

问题:

所以问题是我有一个应用程序,该应用程序在WiFi连接(具有连接的SSID和其他信息)或断开连接(通过移动网络)时向后端发送请求.但是,随着Android 7/N及更高版本中的更改,CONNECTIVITY_CHANGE和CONNECTIVITY_ACTION在后台不再起作用.现在,在大多数情况下,人们会滥用此广播,因此我可以完全理解为什么进行了更改.但是,我不知道如何在当前状态下解决此问题.

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.

现在我根本不是一个Android开发人员(这是一个Cordova插件),所以我指望你们!

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

预期的行为: 每当WiFi切换连通性时,即使应用程序被杀死/在后台,应用程序也会被唤醒并发送请求.

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.

到目前为止已尝试: 到目前为止,我已经将隐式意图从清单中监听到CONNECTIVITY_ACTION,然后手动将其注册到应用程序的主要部分(插件)中.只要应用程序在内存中,它就可以正常工作,但不能在冷启动或实际背景下运行

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

已查看: 大多数答案都谈论使用计划的作业来代替丢失的广播.我了解了它如何工作,例如,重试下载或类似操作,但不适用于我的情况(但如果我错了,请更正我).以下是我已经看过的SO帖子:

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:

​​检测连接更改当应用程序处于前台状态时,在Android 7.0牛轧糖上运行

ConnectivityManager.CONNECTIVITY_ACTION已弃用

使用JobScheduler检测连接更改

​​ Android O-在后台检测连接性变化

牛轧糖及以上: 我们必须使用JobScheduler和JobService进行连接更改.

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

我可以将其分为三个步骤.

All I can divide this into three steps.

在活动内部注册JobScheduler.另外,启动JobService( 用于处理JobScheduler中的回调的服务.预定的请求 与JobScheduler一起最终落在该服务的"onStartJob"上 方法.)

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-to-kiss-by-to-yous-implicit-broadcastreceivers-eefafd9f4f8a