问题:
所以问题是我有一个应用程序,当连接WiFi(连接的SSID和其他信息)或断开连接(通过移动网络)时,它会向我们的后端发送请求。但是,随着Android 7 / N及更高版本的更改,CONNECTIVITY_CHANGE和CONNECTIVITY_ACTION不再在后台运行。现在大多数情况下人们滥用这个广播,因此我完全理解为什么要做出改变。但是,我不知道如何在当前状态下解决这个问题。
现在我不是一个Android开发人员(这是一个Cordova插件),所以我指望你们!
预期行为:即使应用程序被杀/在后台,每当WiFi切换连接时,应用程序都会被唤醒并发送请求。
当前行为:应用程序仅在应用程序位于前台时发送请求。
到目前为止尝试过:到目前为止,我已经移动隐藏的意图来从清单中侦听CONNECTIVITY_ACTION,以便在应用程序的主要部分(插件)中手动注册它。这使得它只要应用程序在内存中就可以工作,但不能在冷启动或实际背景下工作
已经看过:大多数答案谈论使用预定的工作来代替丢失的广播。我看到这是如何工作的,例如,重试下载或类似,但不适用于我的情况(但如果我错了请纠正我)。以下是我已经看过的SO帖子:
Detect connectivity changes on Android 7.0 Nougat when app is in foreground
ConnectivityManager.CONNECTIVITY_ACTION deprecated
Nougat及以上:我们必须使用JobScheduler和JobService进行连接更改。
我只能将其分为三个步骤。
在活动中注册JobScheduler。此外,启动JobService(用于处理来自JobScheduler的回调的服务。使用JobScheduler安排的请求最终落在此服务的“onStartJob”方法上。)
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);
}
}
开始和完成工作的服务。
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();
}
}
最后,检查网络连接的接收器类发生了变化。
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);
}
}
不要忘记在清单文件中添加权限和服务。
<?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>
有关更多信息,请参阅以下链接。
https://github.com/jiteshmohite/Android-Network-Connectivity
https://github.com/evant/JobSchedulerCompat
获取连接更改Android Os 7及更高版本的最佳方法是在Application类中注册您的ConnectivityReceiver广播,如下所示,这有助于您在后台进行更改,直到您的应用程序处于活动状态。
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());
}
}
}
然后在清单中
<application
android:name=".app.MyApplication"/>
这是您的ConnectivityReceiver.java
public class ConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
MLog.v(TAG, "onReceive().." + intent.getAction());
}
}
这就是我做到的。我创建了一个IntentService
和onCreate
方法,我已经注册networkBroadacst
检查互联网连接。
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;
}
}
这是我的广播课
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{}
}
}
通过这种方式,您可以检查您的应用程序是在前景中还是在牛轧糖中的背景中的互联网连接。
针对Android 7.0(API级别24)及更高版本的应用如果在其清单中声明广播接收器,则不会收到CONNECTIVITY_ACTION广播。如果应用程序使用Context.registerReceiver()注册其BroadcastReceiver并且该上下文仍然有效,它们仍将接收CONNECTIVITY_ACTION广播。
因此,通过明确注册相同的内容,您将获得此广播,直到您的上下文在Android N及更高版本中有效。
启动完成:
你可以听android.intent.action.BOOT_COMPLETED
广播你需要这个权限。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
App Killed场景:
你不会收到它。
这是非常期待的并且由于各种原因
当您使用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);
}
哪个SendAnyRequestService.class
是您的服务类,您可以在其中调用您的API。
此代码适用于Android 6.0(API 23)及更高版本
参考文件是here