收藏官网首页
查看: 21754|回复: 2

关于android6.0切换到指定wifi切换不上去的原因

45

主题

92

帖子

507

积分

高级会员

Rank: 4

积分
507
跳转到指定楼层
楼主
发表于 2016-10-10 11:15:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
免费使用STM32、APP自动代码生成工具

https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-network
http://m.blog.csdn.net/article/details?id=51042851
http://seewhy.leanote.com/post/Android-6.0-Changes
最近发现在安卓6.0的机子上,无法切换到指定WiFi,与其说是安卓6.0的问题,不如说是自己以前的代码不符合规范。

问题:

连接到指定WiFi,我之前使用的代码如下:

// 添加一个网络并连接    public void addNetwork(WifiConfiguration wcg) {        int wcgID = mWifiManager.addNetwork(wcg);        boolean b = mWifiManager.enableNetwork(wcgID , true);     }

Android 6.0 中WiFiManager addNetwork(WifiConfiguration config),添加同一ssid时会返回-1,这个时候你再将这个-1 (NetWorkId)传进enableNetwork(-1,true),肯定连不上WiFi。

分析原因

在官方的文章这篇文章翻译的不错)中,介绍了关于安卓6.0中有关WiFi的改变。如下:

Wi-Fi and Networking Changes

This release introduces the following behavior changes to the Wi-Fi and networking APIs.

  • Your apps can now change the state of WifiConfiguration objects only if you created these objects. You are not permitted to modify or delete WifiConfiguration objects created by the user or by other apps.
  • Previously, if an app forced the device to connect to a specific Wi-Fi network by using enableNetwork() with the disableAllOthers=true setting, the device disconnected from other networks such as cellular data. In This release, the device no longer disconnects from such other networks. If your app’s targetSdkVersion is “20” or lower, it is pinned to the selected Wi-Fi network. If your app’s targetSdkVersion is “21” or higher, use the multinetwork APIs (such as openConnection(), bindSocket(), and the new bindProcessToNetwork() method) to ensure that its network traffic is sent on the selected network.

解释:
原因就是第一条,在扫描WiFi列表时,系统会自动创建曾经连接成功过的WiFi的WifiConfiguration ,使用addNetwork()添加这个WiFi时,就是改变了系统创建的WifiConfiguration对象,所以addNetwork()会返回-1。

在addNetwork的源码中发现:

public int addNetwork(WifiConfiguration config) {        if (config == null) {            return -1;        }        //这里改变了WifiConfiguration        config.networkId = -1;        return addOrUpdateNetwork(config);    }

在Android 5.1系统中,即使已经存在指定SSID的WifiConfiguration对象,再次使用addNetwork()添加相同的网络,添加成功而且返回的ID和添加之前的一样,我猜测是返回了系统的WifiConfiguration对象,虽然有改变WifiConfiguration对象

但是手动在WLAN设置中,删除网络A,再次连接网络A,发现网络A的WifiConfiguration的ID,不一样了,如果addNetwork()中不是返回WifiConfiguration对象,那么ID应该不一样。

解决方法:

下面只是一个大概思路,代码并不完整

private void Wificonnect() {        // 连接到外网        WifiConfiguration mWifiConfiguration;        WifiManager mWifiManager = new WifiAdmin(this);        String SSID = wifiName.replace("+", " ");        String password = wifiPwd;        //检测指定SSID的WifiConfiguration 是否存在        WifiConfiguration tempConfig = IsExsits(SSID);        if (tempConfig == null) {            //创建一个新的WifiConfiguration ,CreateWifiInfo()需要自己实现            mWifiConfiguration = CreateWifiInfo(SSID, password, 3);            int wcgID = mWifiManager.addNetwork(mWifiConfiguration );            boolean b = mWifiManager.enableNetwork(wcgID, true);        } else {        //发现指定WiFi,并且这个WiFi以前连接成功过            mWifiConfiguration = tempConfig;            boolean b = mWifiManager.enableNetwork(mWifiConfiguration .networkId, true);        }}//判断曾经连接过得WiFi中是否存在指定SSID的WifiConfiguration public WifiConfiguration IsExsits(String SSID) {        List<WifiConfiguration> existingConfigs = mWifiManager                .getConfiguredNetworks();        for (WifiConfiguration existingConfig : existingConfigs) {            if (existingConfig.SSID.equals("\"" + SSID + "\"")) {                return existingConfig;            }        }        return null;}

45

主题

92

帖子

507

积分

高级会员

Rank: 4

积分
507
沙发
 楼主| 发表于 2016-10-10 11:16:32 | 只看该作者
package com.gizwits.openSource.appKit.CommonModule;

import java.util.List;

import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;

public class WifiAutoConnectManager {

        private static final String TAG = WifiAutoConnectManager.class
                        .getSimpleName();

        WifiManager wifiManager;

        // 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况
        public enum WifiCipherType {
                WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
        }

        // 构造函数
        public WifiAutoConnectManager(WifiManager wifiManager) {
                this.wifiManager = wifiManager;
        }

        // 提供一个外部接口,传入要连接的无线网
        public void connect(String ssid, String password, WifiCipherType type) {
                Thread thread = new Thread(new ConnectRunnable(ssid, password, type));
                thread.start();
        }

        // 查看以前是否也配置过这个网络
        private WifiConfiguration isExsits(String SSID) {
                List<WifiConfiguration> existingConfigs = wifiManager
                                .getConfiguredNetworks();
                for (WifiConfiguration existingConfig : existingConfigs) {
                        if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
                                return existingConfig;
                        }
                }
                return null;
        }

        private WifiConfiguration createWifiInfo(String SSID, String Password,
                        WifiCipherType Type) {
                WifiConfiguration config = new WifiConfiguration();
                config.allowedAuthAlgorithms.clear();
                config.allowedGroupCiphers.clear();
                config.allowedKeyManagement.clear();
                config.allowedPairwiseCiphers.clear();
                config.allowedProtocols.clear();
                config.SSID = "\"" + SSID + "\"";
                // config.SSID = SSID;
                // nopass
                if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
                        // config.wepKeys[0] = "";
                        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                        // config.wepTxKeyIndex = 0;
                }
                // wep
                if (Type == WifiCipherType.WIFICIPHER_WEP) {
                        if (!TextUtils.isEmpty(Password)) {
                                if (isHexWepKey(Password)) {
                                        config.wepKeys[0] = Password;
                                } else {
                                        config.wepKeys[0] = "\"" + Password + "\"";
                                }
                        }
                        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
                        config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
                        config.allowedKeyManagement.set(KeyMgmt.NONE);
                        config.wepTxKeyIndex = 0;
                }
                // wpa
                if (Type == WifiCipherType.WIFICIPHER_WPA) {
                        config.preSharedKey = "\"" + Password + "\"";
                        config.hiddenSSID = true;
                        config.allowedAuthAlgorithms
                                        .set(WifiConfiguration.AuthAlgorithm.OPEN);
                        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
                        config.allowedPairwiseCiphers
                                        .set(WifiConfiguration.PairwiseCipher.TKIP);
                        // 此处需要修改否则不能自动重联
                        // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                        config.allowedPairwiseCiphers
                                        .set(WifiConfiguration.PairwiseCipher.CCMP);
                        config.status = WifiConfiguration.Status.ENABLED;

                }
                return config;
        }

        // 打开wifi功能
        private boolean openWifi() {
                boolean bRet = true;
                if (!wifiManager.isWifiEnabled()) {
                        bRet = wifiManager.setWifiEnabled(true);
                }
                return bRet;
        }

        // 关闭WIFI
        private void closeWifi() {
                if (wifiManager.isWifiEnabled()) {
                        wifiManager.setWifiEnabled(false);
                }
        }

        class ConnectRunnable implements Runnable {
                private String ssid;

                private String password;

                private WifiCipherType type;

                public ConnectRunnable(String ssid, String password, WifiCipherType type) {
                        this.ssid = ssid;
                        this.password = password;
                        this.type = type;
                }

                @Override
                public void run() {
                        // 打开wifi
                        openWifi();
                        // 开启wifi功能需要一段时间(我在手机上测试一般需要1-3秒左右),所以要等到wifi
                        // 状态变成WIFI_STATE_ENABLED的时候才能执行下面的语句
                        while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
                                try {
                                        // 为了避免程序一直while循环,让它睡个100毫秒检测……
                                        Thread.sleep(100);

                                } catch (InterruptedException ie) {
                                        Log.e(TAG, ie.toString());
                                }
                        }

                        WifiConfiguration tempConfig = isExsits(ssid);

                        if (tempConfig != null) {
                                // wifiManager.removeNetwork(tempConfig.networkId);

                                boolean b = wifiManager.enableNetwork(tempConfig.networkId,
                                                true);
                        } else {
                                WifiConfiguration wifiConfig = createWifiInfo(ssid, password,
                                                type);
                                //
                                if (wifiConfig == null) {
                                        Log.d(TAG, "wifiConfig is null!");
                                        return;
                                }

                                int netID = wifiManager.addNetwork(wifiConfig);
                                boolean enabled = wifiManager.enableNetwork(netID, true);
                                Log.d(TAG, "enableNetwork status enable=" + enabled);
                                boolean connected = wifiManager.reconnect();
                                Log.d(TAG, "enableNetwork connected=" + connected);
                        }

                }
        }

        private static boolean isHexWepKey(String wepKey) {
                final int len = wepKey.length();

                // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
                if (len != 10 && len != 26 && len != 58) {
                        return false;
                }

                return isHex(wepKey);
        }

        private static boolean isHex(String key) {
                for (int i = key.length() - 1; i >= 0; i--) {
                        final char c = key.charAt(i);
                        if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
                                        && c <= 'f')) {
                                return false;
                        }
                }

                return true;
        }

        // 获取ssid的加密方式

        public static WifiCipherType getCipherType(Context context, String ssid) {
                WifiManager wifiManager = (WifiManager) context
                                .getSystemService(Context.WIFI_SERVICE);

                List<ScanResult> list = wifiManager.getScanResults();

                for (ScanResult scResult : list) {

                        if (!TextUtils.isEmpty(scResult.SSID) && scResult.SSID.equals(ssid)) {
                                String capabilities = scResult.capabilities;
                                // Log.i("hefeng","capabilities=" + capabilities);

                                if (!TextUtils.isEmpty(capabilities)) {

                                        if (capabilities.contains("WPA")
                                                        || capabilities.contains("wpa")) {
                                                Log.i("hefeng", "wpa");
                                                return WifiCipherType.WIFICIPHER_WPA;
                                        } else if (capabilities.contains("WEP")
                                                        || capabilities.contains("wep")) {
                                                Log.i("hefeng", "wep");
                                                return WifiCipherType.WIFICIPHER_WEP;
                                        } else {
                                                Log.i("hefeng", "no");
                                                return WifiCipherType.WIFICIPHER_NOPASS;
                                        }
                                }
                        }
                }
                return WifiCipherType.WIFICIPHER_INVALID;
        }
}

45

主题

92

帖子

507

积分

高级会员

Rank: 4

积分
507
板凳
 楼主| 发表于 2016-10-10 11:17:25 | 只看该作者
这个类是我修改后的可以适配6.0以及以上机型切换wifi需求的工具类有需要的可以copy
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

加入Q群 返回顶部

版权与免责声明 © 2006-2024 Gizwits IoT Technology Co., Ltd. ( 粤ICP备11090211号 )

快速回复 返回顶部 返回列表