对不起,我的英语。 我正在编写代码以连接到另一个Android设备热点。它已连接。但是,就我而言,热点将没有互联网。现在,已连接的设备切换回具有Internet的另一个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;
}
}
};
答案 0 :(得分:5)
由于Android中WiFi处理的异步特性,我将重点关注这4条寻求解决方案的线路
int netId = wifiManager.addNetwork(wifiConfig);
wifiManager.disconnect();
wifiManager.enableNetwork(netId , true);
wifiManager.reconnect();
disconnect
和reconnect
的呼叫在这里是错误的,它们只是使内部wifi状态机混乱。将参数enableNetwork
设置为boolean attemptConnect
的{{1}}足以以编程方式选择wifi。
因此只需使用:
true
说实话,我尝试扫描内部源,但是内部状态机非常复杂。如果您有兴趣,可以在here中查看状态机,并在here中查看wifi配置数据库的处理方式。
此外,为避免有多个配置条目,在调用addNetwork之前,请检查已创建的配置以查找要连接的SSID,而仅调用 int netId = manager.addNetwork(wifiConfig);
manager.enableNetwork(netId, true);
。
enableNetwork
我正在生产中使用它,并且效果很好。从未在低于24的API级别上进行过测试。
答案 1 :(得分:3)
由于您能够暂时连接到热点,因此最终的问题是将电话切换到“更好”的备用网络。虽然答案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反射启用了不良的网络避免(自动切换)功能,但它很麻烦,因此我认为在此处发布示例并不值得。