当应用程序被杀死/在后台时,检测 Android 7 及更高版本中的连接变化 [英] Detect CONNECTIVITY CHANGE in Android 7 and above when app is killed/in background

查看:25
本文介绍了当应用程序被杀死/在后台时,检测 Android 7 及更高版本中的连接变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

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

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

预期行为:每当 WiFi 切换连接时,应用就会被唤醒并发送请求,即使应用被终止/在后台也是如此.

当前行为:应用仅在应用在前台时发送请求.

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

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

​​检测连接变化在 Android 7.0 Nougat 上,当应用程序处于前台时

ConnectivityManager.CONNECTIVITY_ACTION 已弃用

使用 JobScheduler 检测连接变化

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

解决方案

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

我可以把这分为三个步骤.

<块引用>

在活动中注册 JobScheduler.另外,启动 JobService(用于处理来自 JobScheduler 的回调的服务.已安排的请求与 JobScheduler 最终登陆此服务的onStartJob"方法.)

public class NetworkConnectionActivity extends AppCompatActivity {@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_network_connection);工具栏工具栏 = (工具栏) findViewById(R.id.toolbar);setSupportActionBar(工具栏);调度作业();}@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)私人无效 scheduleJob() {JobInfo myJob = new JobInfo.Builder(0, new ComponentName(this, NetworkSchedulerService.class)).setRequiresCharging(真).setMinimumLatency(1000).setOverrideDeadline(2000).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).setPersisted(真).建造();JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);jobScheduler.schedule(myJob);}@覆盖受保护的无效 onStop() {//服务可以启动"和/或绑定".在这种情况下,它是由这个活动启动"的//并绑定"到 JobScheduler(也称为 JobScheduler 的调度").这个电话//stopService() 不会阻止处理预定的作业.然而,失败//调用 stopService() 会使它无限期地保持活动状态.停止服务(新意图(这个,NetworkSchedulerService.class));super.onStop();}@覆盖受保护的无效 onStart() {super.onStart();//启动服务并为其提供与此类通信的方式.Intent startServiceIntent = new Intent(this, NetworkSchedulerService.class);启动服务(启动服务意图);}}

<块引用>

启动和完成工作的服务.

 公共类 NetworkSchedulerService 扩展了 JobService 实现ConnectivityReceiver.ConnectivityReceiverListener {私有静态最终字符串标记 = NetworkSchedulerService.class.getSimpleName();私有 ConnectivityReceiver mConnectivityReceiver;@覆盖公共无效 onCreate() {super.onCreate();Log.i(TAG, "服务已创建");mConnectivityReceiver = new ConnectivityReceiver(this);}/*** 创建应用程序的 NetworkConnectionActivity 时,它会启动此服务.这是为了使*活动和这个服务可以来回通信.参见setUiCallback()"*/@覆盖public int onStartCommand(意图意图,int标志,int startId){Log.i(TAG, "onStartCommand");返回 START_NOT_STICKY;}@覆盖公共布尔 onStartJob(JobParameters 参数){Log.i(TAG, "onStartJob" + mConnectivityReceiver);registerReceiver(mConnectivityReceiver, new IntentFilter(Constants.CONNECTIVITY_ACTION));返回真;}@覆盖公共布尔 onStopJob(JobParameters 参数){Log.i(TAG, "onStopJob");取消注册接收器(mConnectivityReceiver);返回真;}@覆盖public void onNetworkConnectionChanged(boolean isConnected) {字符串消息 = isConnected ?很好!已连接到互联网":抱歉!未连接到互联网";Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();}}

<块引用>

最后,检查网络连接的接收器类变化.

public class ConnectivityReceiver extends BroadcastReceiver {私有 ConnectivityReceiverListener mConnectivityReceiverListener;ConnectivityReceiver(ConnectivityReceiverListener 监听器){mConnectivityReceiverListener = 监听器;}@覆盖public void onReceive(上下文上下文,意图意图){mConnectivityReceiverListener.onNetworkConnectionChanged(isConnected(context));}公共静态布尔 isConnected(上下文上下文){ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo activeNetwork = cm.getActiveNetworkInfo();返回 activeNetwork != null &&activeNetwork.isConnectedOrConnecting();}公共接口 ConnectivityReceiverListener {void onNetworkConnectionChanged(boolean isConnected);}}

<块引用>

不要忘记在清单文件中添加权限和服务.

<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><!-- 在 api 上总是需要 <21,需要在您的工作运行时保持唤醒锁 --><uses-permission android:name="android.permission.WAKE_LOCK"/><!-- 在 api 上需要 <21 如果您使用的是 setRequiredNetworkType(int) --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><!-- 如果您使用 setPersisted(true),则所有 api 级别都需要 --><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/><申请机器人:allowBackup =真"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><活动android:name=".connectivity.NetworkConnectionActivity"android:theme="@style/AppTheme.NoActionBar"><意图过滤器><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></意图过滤器></活动><!-- 定义您的服务,确保添加权限!--><服务android:name=".connectivity.NetworkSchedulerService"机器人:出口=真"android:permission="android.permission.BIND_JOB_SERVICE"/></应用程序></清单>

请参阅以下链接了解更多信息.

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

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

这篇关于当应用程序被杀死/在后台时,检测 Android 7 及更高版本中的连接变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆