[英]Programatically connected android device to Hotspot (no internet) switches back to wifi with internet
对不起我的英语不好。 我正在编写一个代码来连接到另一个Android设备热点。 它连接起来了。 但是,在我的情况下,热点将没有互联网。 现在连接的设备,切换回与互联网的另一个wifi网络。 除了我的方式,有没有更好的方法连接到热点? 我的代码如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
AppCompatButton btnConnect=findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
registerReceiver(mWifiBroadcastReceiver , new IntentFilter("android.net.wifi.STATE_CHANGE"));
EditText eSSID=findViewById(R.id.ssid);
EditText ePassword=findViewById(R.id.password);
String ssid = eSSID.getText().toString();
String key = ePassword.getText().toString();
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = String.format("\"%s\"" , ssid);
wifiConfig.preSharedKey = String.format("\"%s\"" , key);
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
int netId = wifiManager.addNetwork(wifiConfig);
wifiManager.disconnect();
wifiManager.enableNetwork(netId , true);
wifiManager.reconnect();
}
});
}
接收器是:
private BroadcastReceiver mWifiBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context , Intent intent) {
switch (intent.getAction()) {
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean isConnected = info.isConnected();
boolean isConnecting = info.isConnectedOrConnecting();
//TODO: probably better to use the EXTRA_ info here
String ssid = wifiManager.getConnectionInfo() != null ?
wifiManager.getConnectionInfo().getSSID() : null;
ssid = normalizeAndroidWifiSsid(ssid);
String stateName = "";
switch (info.getState()) {
case CONNECTED:
stateName = "connected";
break;
case CONNECTING:
stateName = "connecting";
break;
case DISCONNECTED:
stateName = "disconnected";
break;
case DISCONNECTING:
stateName = "disconnecting";
break;
case SUSPENDED:
stateName = "suspended";
break;
case UNKNOWN:
stateName = "unknown";
break;
}
if (Build.VERSION.SDK_INT >= 21) {
if (isConnected) {
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
final String connectedSsid = ssid;
connectivityManager.registerNetworkCallback(builder.build() , new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
//This is always the SSID if it's wifi, even though this is *not* documented
String networkSsid = networkInfo.getExtraInfo();
if (networkSsid.equals(connectedSsid)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context,"Connected Successfully",Toast
.LENGTH_LONG).show();
}
});
/*
* We can now use network.openURLConnection and network.getSocketFactory()
* to communicate using the wifi network that has no Internet
*/
connectivityManager.unregisterNetworkCallback(this);
}
}
});
}
}
break;
}
}
};
由于Android中WiFi处理的异步特性,我将专注于寻找解决方案的4条线路
int netId = wifiManager.addNetwork(wifiConfig);
wifiManager.disconnect();
wifiManager.enableNetwork(netId , true);
wifiManager.reconnect();
disconnect
和reconnect
呼叫是错误的,它们只会混淆内部wifi状态机。 使用参数boolean attemptConnect
设置为true
调用enableNetwork
足以以编程方式选择wifi。
所以只需使用:
int netId = manager.addNetwork(wifiConfig);
manager.enableNetwork(netId, true);
说实话,我已经尝试过浏览内部资源,但内部状态机非常复杂。 如果您有兴趣,可以在这里查看状态机,并在这里查看如何处理wifi配置数据库。
此外,为避免多个配置条目,在调用addNetwork之前,请检查已创建的配置以查找要连接的SSID,并仅调用enableNetwork
。
List<WifiConfiguration> networks = manager.getConfiguredNetworks();
for(WifiConfiguration c : networks) {
if (isThisWifiAppSpecific(c.SSID)) {
manager.enableNetwork(c.networkId, true);
return;
}
}
我在生产中使用它并且工作正常。 从未在API级别低于24进行测试。
由于您可以暂时连接到热点,最终的问题是将手机切换到“更好”的替代网络。 虽然答案https://stackoverflow.com/a/53249295/949224将有助于在连接到您的特定热点时整理您的代码,但您还应该考虑禁用“智能网络切换”和Wi-Fi自动重新连接。 前者也被称为差的网络监视器,并且正在监视当前网络上的连接,并且如果可能改进则将切换到LTE数据,并且后者将在可以改变的情况下改变为另一个已知的Wi-Fi AP提供更好的连接。
可以在高级WiFi设置活动中禁用智能网络交换机。 它不是作为Android中的Java API公开的,第三方应用程序并未设计为获得相关权限,而且不同的OEM供应商具有不同的自定义实现,因此最佳方法是从您的应用程序启动正确的设置面板。 这是一个例子:
public static void requestSmartNetworkSettings(Context ctx){
final Intent i = new Intent(Settings.ACTION_WIFI_IP_SETTINGS);
final PackageManager mgr = ctx.getPackageManager();
if( mgr.resolveActivity(i, PackageManager.MATCH_DEFAULT_ONLY) != null)
{
ctx.startActivity(i);
}
}
在某些设备上,可以通过ConnectivityManager.setProcessDefaultNetwork(Network net)
在没有外部设置对话框的情况下禁用智能网络切换,但我看到这是不可靠的。 我通常设置它然后也使用设置。
通过选择已知的AP并取消选中复选框,可以在WiFi设置活动中手动禁用Wi-Fi自动重新连接。
以编程方式执行此操作的快速方法是在WifiManager中迭代已知的AP ID并调用WifiManager.disableNetwork(int netID)
。 在您想要结束Hotspot连接之后,您始终可以以编程方式再次启用它们。 这样,用户之后应该恢复正常的手机。
顺便说一句,有办法检查是否通过Java反射启用了不良的网络避免(自动切换),但它很麻烦,所以我认为在这里发布示例是不值得的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.