Android 12 Wifi development (get list, connect, disconnect)

Get Wifi list:

Scanning (this method was deprecated as early as Android 9.0), but if it is not called, it is impossible to obtain the broadcast of the Wifi list in time. (It can be obtained normally without any delay, and there is no difference after experiment)

public static void searchWifiList(WifiManager manager) {
        manager.startScan();
}

Create broadcast and receive:

/**
     * 获取附近的WiFi列表
     *
     * @param manager WifiManager
     * @param flag    是否保留重名但BSSID不同的wifi     true保留,false不保留
     * @return wifi列表
     */
    public static List<ScanResult> scanResults(WifiManager manager, boolean flag) {
        List<ScanResult> scanResults = new ArrayList<>();
        HashSet<String> hs = new HashSet<>();
        Log.d("WifiUtils", "scanResults: " + manager.getScanResults().size());
        if (flag) {
            scanResults = manager.getScanResults();
            return scanResults;
        }
        for (ScanResult scanResult : manager.getScanResults()) {
            if (hs.add(scanResult.SSID)) {
                scanResults.add(scanResult);
            }
        }
        return scanResults;
    }
private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                Log.d("WifiFragment", "onReceive: 刷新数据");
                results = WifiUtils.scanResults(manager, true);
                mainBinding.scanResult.getAdapter().notifyDataSetChanged();
            } else if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
                int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
                switch (wifiState) {
                    case WifiManager.WIFI_STATE_DISABLED:
                        Log.d("WifiFragment", "onReceive: wifi 关闭");
                        mainBinding.switchWifi.setText("已停用");
                        results = new ArrayList<>();
                        mainBinding.scanResult.getAdapter().notifyDataSetChanged();
                        break;
                    case WifiManager.WIFI_STATE_DISABLING:
                    case WifiManager.WIFI_STATE_ENABLING:
                    case WifiManager.WIFI_STATE_UNKNOWN:
                        break;
                    case WifiManager.WIFI_STATE_ENABLED:
                        Log.d("WifiFragment", "onReceive: wifi 打开");
                        mainBinding.switchWifi.setText("已启用");
                        break;
                }
            }
        }
    };

Configure and connect ( no system signature ):

/**
     * 创建连接
     * @param manager WifiManager
     * @param ssid  Wifi名称
     * @param bssid 唯一标识(可以为空)
     * @param passwd    密码  (当前网络是开放网络时,可以为空)
     * @param isHidden  是否是隐藏网络
     * @param capabilities  安全协议(根据协议选择连接方式)
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static void connectWifiForQ(WifiManager manager, String ssid, String bssid, String passwd, boolean isHidden, String capabilities) {
        if (capabilities.contains("WPA-PSK") || capabilities.contains("WPA2-PSK")) {
            setWPA2ForQ(manager, ssid, bssid, passwd, isHidden);
        } else {
            setESSForQ(manager, ssid, isHidden);
        }
    }

    // WPA2-PSK
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static int setWPA2ForQ(WifiManager manager, String ssid, String bssid, String passwd, boolean isHidden) {
        WifiNetworkSuggestion suggestion;
        if (bssid == null) {
            suggestion= new WifiNetworkSuggestion.Builder()
                    .setSsid(ssid)
                    .setWpa2Passphrase(passwd)
                    .setIsHiddenSsid(isHidden)
                    .build();
        } else {
            suggestion= new WifiNetworkSuggestion.Builder()
                    .setSsid(ssid)
                    .setBssid(MacAddress.fromString(bssid))
                    .setWpa2Passphrase(passwd)
                    .setIsHiddenSsid(isHidden)
                    .build();
        }
        List<WifiNetworkSuggestion> suggestions = new ArrayList<>();
        suggestions.add(suggestion);
        int status = manager.addNetworkSuggestions(suggestions);
        if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
            // 连接失败
            Log.d("WifiUtils", "setWPA2ForQ: 添加失败");
        } else {
            Log.d("WifiUtils", "setWPA2ForQ: 添加成功");
        }
        return status;
    }

    // ESS
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static int setESSForQ(WifiManager manager, String ssid, boolean isHidden) {
        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                .setSsid(ssid)
                .setIsHiddenSsid(isHidden)
                .build();
        List<WifiNetworkSuggestion> suggestions = new ArrayList<>();
        suggestions.add(suggestion);
        int status = manager.addNetworkSuggestions(suggestions);
        if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
            // 连接失败
            Log.d("WifiUtils", "setWPA2ForQ: 添加失败");
        } else {
            Log.d("WifiUtils", "setWPA2ForQ: 添加成功");
        }
        return status;

    }

Configure and connect ( with system signature ):

/**
     * 连接wifi
     *
     * @param manager       WifiManager
     * @param configuration Wifi配置
     * @return 是否连接成功
     */
    public static boolean connectWifi(WifiManager manager, WifiConfiguration configuration) {
        int id = manager.addNetwork(configuration);
        WifiInfo connectionInfo = manager.getConnectionInfo();
        manager.disableNetwork(connectionInfo.getNetworkId());
        boolean b = manager.enableNetwork(id, true);
        Log.d("WifiManagerUtils", "connectWifi: 连接状态=" + b);
        if (b) {
            manager.saveConfiguration();
        } else {
            Log.d("WifiManagerUtils", configuration.toString());
        }
        return b;
    }

    /**
     * 创建Wifi配置
     *
     * @param SSID         wifi名称
     * @param password     wifi密码
     * @param hidden       网络是否隐藏(该方法与添加隐藏网络通用)
     * @param capabilities 网络安全协议
     * @return 配置好的wifi
     */
    public static WifiConfiguration createWifiInfo(String SSID, String password, boolean hidden, String capabilities) {
        WifiConfiguration configuration = new WifiConfiguration();
        configuration.SSID = "\"" + SSID + "\"";
        if (hidden) {
            configuration.hiddenSSID = true;
        }
        Log.d("WifiManagerUtils", "createWifiInfo: " + capabilities);
        if (capabilities.contains("SAE") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            setWPA3(configuration, password);
        } else if (capabilities.contains("WPA-PSK") || capabilities.contains("WPA2-PSK")) {
            setWPA(configuration, password);
        } else if (capabilities.contains("WEP")) {
            setWEP(configuration, password);
        } else {
            setESS(configuration);
        }
        return configuration;
    }

    /**
     * 设置wpa3协议
     *
     * @param configuration 配置
     * @param password      密码
     */
    public static void setWPA3(WifiConfiguration configuration, String password) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
        }
        configuration.preSharedKey = "\"" + password + "\"";
    }

    /**
     * WPA协议
     *
     * @param configuration 配置
     * @param password      密码
     */
    public static void setWPA(WifiConfiguration configuration, String password) {
        configuration.preSharedKey = "\"" + password + "\"";
        //公认的IEEE 802.11验证算法。
        configuration.allowedAuthAlgorithms.clear();
        configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
        //公认的的公共组密码。
        configuration.allowedGroupCiphers.clear();
        configuration.allowedGroupCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
        //公认的密钥管理方案。
        configuration.allowedKeyManagement.clear();
        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
        //密码为WPA。
        configuration.allowedPairwiseCiphers.clear();
        configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
        configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
        //公认的安全协议。
        configuration.allowedProtocols.clear();
        configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
    }

    /**
     * WEP协议
     *
     * @param configuration 配置
     * @param password      密码
     */
    public static void setWEP(WifiConfiguration configuration, String password) {
        configuration.wepKeys[0] = "\"" + password + "\"";
        configuration.wepTxKeyIndex = 0;
        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
    }


    /**
     * 无密码
     *
     * @param configuration 配置
     */
    public static void setESS(WifiConfiguration configuration) {
        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    }

Disconnect (no system signature):

//Android11及以上可以使用,清除建议列表,可以断开当前的网络
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                List<WifiNetworkSuggestion> networkSuggestions = wifiManager.getNetworkSuggestions();
                wifiManager.removeNetworkSuggestions(networkSuggestions);
            }

Monitor connection status:

 //监听网络连接状态
        connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback(){
            @Override
            public void onAvailable(@NonNull Network network) {
                super.onAvailable(network);
                Log.d("MainActivity", "onAvailable: 网络已连接");
                Toast.makeText(MainActivity.this, "已连接网络", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onUnavailable() {
                super.onUnavailable();
                Log.d("MainActivity", "onUnavailable: 网络已断开");
                Toast.makeText(MainActivity.this, "已断开网络", Toast.LENGTH_SHORT).show();
            }
        });

Precautions:

After disconnecting the current Wi-Fi, and then reconnecting to the Wi-Fi, it may fail to connect.

In this case, I solved it by turning off Wifi and then turning it on again, but the switch control of Wifi involves permission issues——

System permission is required, add in Manifest:

android:sharedUserId="android.uid.system"

Then the system signature is required, which can be obtained in the system source code.

I don't know if you have any good solutions.

project address:

Have a system signature (recommended)——

https://github.com/Ouanu/WIFI_DEMO icon-default.png?t=N176https://github.com/Ouanu/WIFI_DEMO No system signature——

https://github.com/Ouanu/WifiDemohttps://github.com/Ouanu/WifiDemo

Method without system signature (requires root):

Proceed as follows--

1. Create a text in the /data directory to identify whether Wifi is on or off, for example:

Text file name: node

Content: 0 // (0 is off, 1 is on)

2. chmod 666 /data/node (grant read and write permissions to the file)

3. Create a script that loops to detect the content of the file, and execute the adb command for the content

adb shell svc wifi enable    // 开启WIFI
adb shell svc wifi disable    // 关闭WIFI

4. The application (App) reads and writes the text

It can control the switch of WIFI module without system signature

Guess you like

Origin blog.csdn.net/weixin_44917215/article/details/128609280