我有一个无线网络设置,没有互联网接入。只是连接到它的各种其他本地WiFi设备。 DHCP配置为不返回网关或DNS服务器。只有IP和网络掩码。
当我将我的机器人连接到这个无线网络AP时它连接正常,但手机上的所有互联网连接都停止工作。
我希望由于wifi没有网关设置,android应该意识到互联网无法通过该连接而应该通过3G连接进行路由,这是5条吧。
我也尝试在Android手机上设置静态IP,但这没有帮助。
此设置的主要原因是Android设备可以将此远程网络上的数据传输到基于互联网的服务器,因为它可以毫无问题地连接到本地设备。然而,一旦设置了wifi,3G端就会被打破。
有关如何解决此问题的任何想法?
答案 0 :(得分:5)
经过一些编码和测试后,我合并了Squonk和this解决方案。这是我创建的课程:
package it.helian.exampleprj.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;
public class NetworkUtils {
private static final String TAG_LOG = "ExamplePrj";
Context context;
WifiManager wifiMan = null;
WifiManager.WifiLock wifiLock = null;
public NetworkUtils(Context context) {
super();
this.context = context;
}
/**
* Enable mobile connection for a specific address
* @param context a Context (application or activity)
* @param address the address to enable
* @return true for success, else false
*/
public boolean forceMobileConnectionForAddress(Context context, String address) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null == connectivityManager) {
Log.d(TAG_LOG, "ConnectivityManager is null, cannot try to force a mobile connection");
return false;
}
//check if mobile connection is available and connected
State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG_LOG, "TYPE_MOBILE_HIPRI network state: " + state);
if (0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING)) {
return true;
}
//activate mobile connection in addition to other connection already activated
int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
Log.d(TAG_LOG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt);
//-1 means errors
// 0 means already enabled
// 1 means enabled
// other values can be returned, because this method is vendor specific
if (-1 == resultInt) {
Log.e(TAG_LOG, "Wrong result of startUsingNetworkFeature, maybe problems");
return false;
}
if (0 == resultInt) {
Log.d(TAG_LOG, "No need to perform additional network settings");
return true;
}
//find the host name to route
String hostName = extractAddressFromUrl(address);
Log.d(TAG_LOG, "Source address: " + address);
Log.d(TAG_LOG, "Destination host address to route: " + hostName);
if (TextUtils.isEmpty(hostName)) hostName = address;
//create a route for the specified address
int hostAddress = lookupHost(hostName);
if (-1 == hostAddress) {
Log.e(TAG_LOG, "Wrong host address transformation, result was -1");
return false;
}
//wait some time needed to connection manager for waking up
try {
for (int counter=0; counter<30; counter++) {
State checkState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (0 == checkState.compareTo(State.CONNECTED))
break;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
//nothing to do
}
boolean resultBool = connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
Log.d(TAG_LOG, "requestRouteToHost result: " + resultBool);
if (!resultBool)
Log.e(TAG_LOG, "Wrong requestRouteToHost result: expected true, but was false");
state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG_LOG, "TYPE_MOBILE_HIPRI network state after routing: " + state);
return resultBool;
}
/**
* This method extracts from address the hostname
* @param url eg. http://some.where.com:8080/sync
* @return some.where.com
*/
public String extractAddressFromUrl(String url) {
String urlToProcess = null;
//find protocol
int protocolEndIndex = url.indexOf("://");
if(protocolEndIndex>0) {
urlToProcess = url.substring(protocolEndIndex + 3);
} else {
urlToProcess = url;
}
// If we have port number in the address we strip everything
// after the port number
int pos = urlToProcess.indexOf(':');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have resource location in the address then we strip
// everything after the '/'
pos = urlToProcess.indexOf('/');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have ? in the address then we strip
// everything after the '?'
pos = urlToProcess.indexOf('?');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
return urlToProcess;
}
/**
* Transform host name in int value used by {@link ConnectivityManager.requestRouteToHost}
* method
*
* @param hostname
* @return -1 if the host doesn't exists, elsewhere its translation
* to an integer
*/
private int lookupHost(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
@SuppressWarnings("unused")
private int lookupHost2(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
public Boolean disableWifi() {
wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiMan != null) {
wifiLock = wifiMan.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "HelianRCAWifiLock");
}
return wifiMan.setWifiEnabled(false);
}
public Boolean enableWifi() {
Boolean success = false;
if (wifiLock != null && wifiLock.isHeld())
wifiLock.release();
if (wifiMan != null)
success = wifiMan.setWifiEnabled(true);
return success;
}
}
这是用法:
boolean mobileRoutingEnabled = checkMobileInternetRouting();
if(!mobileRoutingEnabled) {
networkUtils.disableWifi();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
networkUtils.forceMobileConnectionForAddress(context, RCA_URL);
if(!mobileRoutingEnabled) {
networkUtils.enableWifi();
}
// This second check is for testing purpose
checkMobileInternetRouting();
return callWebService(RCA_COMPLETE_URL, _plate);
其中 checkMobileInternetRouting 是:
private boolean checkMobileInternetRouting() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
return 0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING);
}
这有点hacky但工作正常。唯一的问题是这个路由有几秒的超时(如20-30),迫使你再次执行整个上述过程。将此超时设置为更高的值将非常好。
答案 1 :(得分:0)
从代码中,当您检测到没有连接时,您可以关闭WiFi ...
至于设置,没有(没有好的方法来检查是否确实存在普遍可靠的连接)。但有些手机会自动执行您所描述的内容,例如我的LG P-970。
(注意:当Android连接到WiFi时,Android会断开与移动网络的连接,因此无法通过移动设备连接到WiFi但通过移动设备进行互联网访问,即使Linux可以执行此操作(使用{{1}工具套件))
答案 2 :(得分:0)
我不能保证这会有效,因为这是我前一段时间才进行的实验。当无线连接网络无法通往外界时,我也有类似的需要使用3G(或其他移动网络)。
以下代码应删除wifi连接以允许移动网络进入播放。你需要在整个过程中进行各种测试,然后再重新建立wifi连接......
WifiManager wifiMan = null;
WifiManager.WifiLock wifiLock = null;
private Boolean disableWifi() {
wifiMan = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifiMan != null) {
wifiLock = wifiMan.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "MyWifiLock");
}
return wifiMan.setWifiEnabled(false);
}
private Boolean enableWifi() {
Boolean success;
if (wifiLock != null)
wifiLock.release();
if (wifiMan != null)
success = wifiMan.setWifiEnabled(true);
return success;
}
答案 3 :(得分:0)
Google为此目的在Android SDK 21中添加了一些有用的方法。
您可以创建NetworkRequest
:
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
然后您可以使用ConnectivityManager
请求此类网络。例如,您希望确保所有HTTP请求都将通过具有Internet访问权限的网络传递。您可以通过以下方式构建Retrofit API:
ApiConfig apiConfig;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
apiConfig = new Retrofit.Builder()
.baseUrl("https://api.imatrix.io/")
.client(new OkHttpClient.Builder()
.socketFactory(network.getSocketFactory())
.build())
.build()
.create(ApiConfig.class);
}
@Override
public void onLost(Network network) {
apiConfig = null;
}
});
请注意使用此类代码段时的线程安全性。
此外,我建议您检查ConnectivityManager#bindProcessToNetwork和此blog。
ConnectivityManager.NetworkCallback
是一个空类,它有several methods。
答案 4 :(得分:-1)
您不需要编码任何东西。我找到了一个完全正确的应用程序。如果此连接没有互联网,您可以配置为自动断开连接。
https://play.google.com/store/apps/details?id=com.nLabs.internetconnectivity&hl=en