移动数据开启时通过wifi(无互联网)发送数据
Send data through wifi (no internet) when mobile data on
我正在开发通过 wifi(由设备生成)连接到硬件设备并通过套接字连接向其发送数据的应用程序。
问题是当移动数据 (3G/4G) 被激活时 android 尝试通过它发送数据而不是通过设备生成的 wifi 发送数据,因为 wifi 没有互联网连接。
我正在考虑使用 ConnectivityManager#setNetworkPreference() 但它已在 api 21.
中被弃用
如何设置为使用设备生成的wifi而不是移动数据接口发送数据?
设置ProcessDefaultNetwork到wifi后网络会切换回mobile,不能通过这种方式发送大数据,因为这种方式创建的所有socket都将停止工作。目前没有找到完美的方法,仅供参考
1.If 你可以获得 root 访问权限,在连接到 wifi 之前执行此操作:
Process process = runtime.exec("su");
DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream());
dataOutputStream.writeBytes("settings put global captive_portal_server 127.0.0.1\n");
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
int status = process.waitFor();
发送数据后删除:
dataOutputStream.writeBytes("settings delete global captive_portal_server\n");
2.If你可以获得WRITE_SECURE_SETTINGS权限:
Settings.Global.putString(getContentResolver(),"captive_portal_server","127.0.0.1");
或者:
Settings.Global.putInt(getContentResolver(),"captive_portal_detection_enabled",0);
经过大量的研究和时间的尝试,我发现这在 Android 5.0 (Lollipop) 之前的版本中是不可能的,OS 只保留一个网络一次打开界面,应用程序无法控制它。
因此,为了在大于或等于 Lollipop 的版本上执行此操作,我执行了以下操作:
- 在进行套接字连接之前,请检查 android 是否大于或等于 Lollipop,以防它不是您正常情况下必须做的任何事情;
如果版本等于或高于 Lollipop,您需要执行以下操作:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
final ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder;
builder = new NetworkRequest.Builder();
//set the transport type do WIFI
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
manager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
manager.bindProcessToNetwork(network);
} else {
//This method was deprecated in API level 23
ConnectivityManager.setProcessDefaultNetwork(network);
}
try {
//do a callback or something else to alert your code that it's ok to send the message through socket now
} catch (Exception e) {
e.printStackTrace();
}
manager.unregisterNetworkCallback(this);
}
});
}
完成后,您应该停止绑定进程:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ConnectivityManager manager = (ConnectivityManager) InovePlugApplication.getContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
manager.bindProcessToNetwork(null);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ConnectivityManager.setProcessDefaultNetwork(null);
}
这个答案帮助我理解了如何去做 。
我正在开发通过 wifi(由设备生成)连接到硬件设备并通过套接字连接向其发送数据的应用程序。 问题是当移动数据 (3G/4G) 被激活时 android 尝试通过它发送数据而不是通过设备生成的 wifi 发送数据,因为 wifi 没有互联网连接。 我正在考虑使用 ConnectivityManager#setNetworkPreference() 但它已在 api 21.
中被弃用如何设置为使用设备生成的wifi而不是移动数据接口发送数据?
设置ProcessDefaultNetwork到wifi后网络会切换回mobile,不能通过这种方式发送大数据,因为这种方式创建的所有socket都将停止工作。目前没有找到完美的方法,仅供参考
1.If 你可以获得 root 访问权限,在连接到 wifi 之前执行此操作:
Process process = runtime.exec("su");
DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream());
dataOutputStream.writeBytes("settings put global captive_portal_server 127.0.0.1\n");
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
int status = process.waitFor();
发送数据后删除:
dataOutputStream.writeBytes("settings delete global captive_portal_server\n");
2.If你可以获得WRITE_SECURE_SETTINGS权限:
Settings.Global.putString(getContentResolver(),"captive_portal_server","127.0.0.1");
或者:
Settings.Global.putInt(getContentResolver(),"captive_portal_detection_enabled",0);
经过大量的研究和时间的尝试,我发现这在 Android 5.0 (Lollipop) 之前的版本中是不可能的,OS 只保留一个网络一次打开界面,应用程序无法控制它。
因此,为了在大于或等于 Lollipop 的版本上执行此操作,我执行了以下操作:
- 在进行套接字连接之前,请检查 android 是否大于或等于 Lollipop,以防它不是您正常情况下必须做的任何事情;
如果版本等于或高于 Lollipop,您需要执行以下操作:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { final ConnectivityManager manager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkRequest.Builder builder; builder = new NetworkRequest.Builder(); //set the transport type do WIFI builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); manager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { manager.bindProcessToNetwork(network); } else { //This method was deprecated in API level 23 ConnectivityManager.setProcessDefaultNetwork(network); } try { //do a callback or something else to alert your code that it's ok to send the message through socket now } catch (Exception e) { e.printStackTrace(); } manager.unregisterNetworkCallback(this); } }); }
完成后,您应该停止绑定进程:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ConnectivityManager manager = (ConnectivityManager) InovePlugApplication.getContext() .getSystemService(Context.CONNECTIVITY_SERVICE); manager.bindProcessToNetwork(null); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ConnectivityManager.setProcessDefaultNetwork(null); }
这个答案帮助我理解了如何去做