[英]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.