首页 > 解决方案 > 以编程方式连接到热点(无互联网)的 android 设备切换回带互联网的 wifi

问题描述

对不起我的英语不好。我正在编写代码以连接到另一个 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

解决方案


由于 Android 中 WiFi 处理的异步性质,我将专注于这 4 行寻找解决方案

        int netId = wifiManager.addNetwork(wifiConfig);
        wifiManager.disconnect();
        wifiManager.enableNetwork(netId , true);
        wifiManager.reconnect();

disconnect并且reconnect这里的调用是错误的,它们只是混淆了内部 wifi 状态机。使用设置为的enableNetwork参数调用足以以编程方式选择 wifi。boolean attemptConnecttrue

所以只需使用:

    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;
        }
    }

我在生产中使用它并且工作正常。从未在低于 24 的 API 级别进行测试。


推荐阅读