Android自动连接指定的WiFi热点

“Android自动连接指定的WiFi热点”,看上去这是个再基础不过的功能了。很多人都觉得很简单,网上也有大量的资料。但在以Android作为底层系统的硬件设备的连接上,特别针对我们自主开发的轻推投屏盒子为例,这个技术是比较重要的一个点。接下来我就以轻推投屏盒子为例,讲讲Android系统连接WiFi热点的一些难点。

推投屏盒子有两张无线网卡,一个负责对外上网,一个负责对内提供AP局域网。这样的设计是为了在没有外网的环境下也能够实现投屏功能(避免了很多市面上的投屏盒子的缺点。比如必须连接WiFi,并且不支持8021x/eap的WiFi连接),通过连接轻推投屏盒子的AP,实现某些公司需要的公司内网认证。
好了,接下来进入正题,上网WiFi我们使用Android系统的提供WiFi模块管理——WiFiManager。
WiFiManager:是系统提供给开发者使用的系统服务管理类,WifiManager会调用service和framework层, 驱动层进行函数调用,
然后驱动层会回调至上层, 以广播的形式实现通知。简单来说就是,只需要使用WifiManager进行函数操作完成UI, 监听对应的广播消息, 就可完成功能了。
笔者所用到方法:
WiFiManager.startScan():开始扫描WiFi,扫描结果通过广播通知
WiFiManager.disconnect():断开网络WiFi
WiFiManager.addNetwork(WifiConfiguration config):添加WiFi配置,返回networkId
WiFiManager.enableNetwork(networkId, true):允许与以前配置的网络相关联,并尝试连接WiFi
WiFiManager.getScanResults():获取设备缓存的扫描结果,这里部分手机的缓存会很少,跟实际扫描结果不一致,这个时候需要调用一次扫描更新缓存
第一步:获取WiFiManager

WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

第二步:获取扫描结果缓存
ScanResult.SSID 表示WiFi名,这里需要注意有"",如果界面需要显示,那么得把这个去掉,连接的时候这个得保留才行
ScanResult.BSSID mac,表示WiFi的唯一标识,
ScanResult.frequency 表示WiFi的频率
ScanResult.level 表示WiFi的信号强度,这里为负数,越大表示信号越好

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

第三步:连接WiFi

  /**   * wif连接   *   * @param scanResult ScanResult   * @param userName String  eap连接需要的用户名   * @param pass String  密码   * @return 操作结果   */  public boolean connectionWifi(ScanResult scanResult,String userName,String pass) {        WifiConfiguration config = getWifiConfig(ScanResult scanResult,String userName,String pass);        networkId = wifiManager.addNetwork(config);        wifiManager.saveConfiguration();        return wifiManager.enableNetwork(networkId, true);  }

工具方法
判断WiFi类型

/**   * 获取wifi安全类型.   *   * @param result ScanResult   * @return 0   */  public static int getSecurity(ScanResult result) {    if (null != result && null != result.capabilities) {      if (result.capabilities.contains("WEP")) {        return SECURITY_WEP;      } else if (result.capabilities.contains("PSK")) {        return SECURITY_PSK;      } else if (result.capabilities.contains("EAP")) {        return SECURITY_EAP;      }    }    return SECURITY_NONE;  }

获取wif连接配置

 /**   * 获取wif连接配置   *   * @param scanResult ScanResult   * @return    */  public WifiConfiguration getConfig(ScanResult scanResult,String userName,String pass){  WifiConfiguration config = new WifiConfiguration();  switch(getSecurity(scanResult)){  case SECURITY_NONE:  initOpenConfig(config);  break;  case SECURITY_WEP:  initWepConfig(scanResult,config,pass);  break;  case SECURITY_PSK:  initPskConfig(scanResult,config,pass);  break;  case SECURITY_EAP:  initEapConfig(scanResult,config,userName,pass);  break;  }  }    /**   * 初始化公开类型WiFi   *   * @param config WifiConfiguration   */  private void initOpenConfig(WifiConfiguration config){        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);  }    private void initWepConfig(ScanResult scanResult, WifiConfiguration config,String pass) {        config.hiddenSSID = true;        //安全认证协议        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);        //身份验证算法        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);        config.wepTxKeyIndex = 0;        if (isHexWepKey(pass))            config.wepKeys[0] = wifiConnDO.getPassword();//密码        else            config.wepKeys[0] = convertToQuotedString(pass);//密码  }      private void initPskConfig(ScanResult scanResult, WifiConfiguration config,String pass) {        config.hiddenSSID = true;        //公认安全协议        config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);        config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);        //安全认证协议        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);        //密码为WPA        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);        //公认的的公共组密码        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);        //身份验证算法        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);        config.preSharedKey = convertToQuotedString(pass);//密码        config.status = WifiConfiguration.Status.ENABLED;    }        private void initEapConfig(ScanResult scanResult, WifiConfiguration config,String userName,String pass) {        config.hiddenSSID = false;        //安全认证协议        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);//企业级WiFi的相关信息输入配置        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();        enterpriseConfig.setIdentity(wifiConnDO.getUsername());//用户身份        enterpriseConfig.setPassword(wifiConnDO.getPassword());//用户密码        enterpriseConfig.setAnonymousIdentity("");//匿名身份        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP);//EAP类型        enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);        config.enterpriseConfig = enterpriseConfig;    }        static boolean isHexWepKey(@Nullable String wepKey) {        final int passwordLen = wepKey == null ? 0 : wepKey.length();        return passwordLen != 0 && (passwordLen == 10 || passwordLen == 26 || passwordLen == 58) && wepKey.matches("[0-9A-Fa-f]*");    }        static String convertToQuotedString(@NonNull String string) {        if (TextUtils.isEmpty(string))            return "";        final int lastPos = string.length() - 1;        if (lastPos < 0 || (string.charAt(0) == '"' && string.charAt(lastPos) == '"'))            return string;        return "\"" + string + "\"";    }

在我们的实际使用中发现,公司的WiFi有些问题,已经连接过的再次连接的时候会出现连不上的问题,通过对WifiStateMachine的各种日志分析之后发现是我们公司的认证服务有些异常,但这不是我们负责的,所以我们这边采取的方案是,移除配置,然后添加新的配置,问题成功解决。
获取已经系统保存的WiFi配置信息和新的连接方法

protected boolean connectionWifi(WifiConnDO wifiConnDO) {        //获取已保存的WiFi配置        WifiConfiguration config = getSaved(wifiConnDO);        int networkId;        if (config != null) {            networkId = config.networkId;            //移除以保存的配置并保存操作            wifiManager.removeNetwork(networkId);            wifiManager.saveConfiguration();        }        //获取WiFi配置        config = getWifiConfig(wifiConnDO);//        config.BSSID = wifiConnDO.getBssid();        //添加并保存配置        networkId = wifiManager.addNetwork(config);        wifiManager.saveConfiguration();        //使用WiFi        return wifiManager.enableNetwork(networkId, true);;    }private WifiConfiguration getSaved(ScanResult result) {        List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();        if (existingConfigs == null) {            return null;        }        for (WifiConfiguration existingConfig : existingConfigs) {            if (existingConfig.SSID.equals(result.SSID)) {                return existingConfig;            }        }        return null;    }

关于连接WiFi的广播部分这里就不做过多说明了,与其他技术博客的一样即可。
整个过程中我们遇到很多问题,诸如上网芯片支持的频道过少发现不了公司5GWiFi的信道,公司WiFi上网定期会断之后重新连接会切到其他BSSID的同名WiFi导致上网速度慢…
有疑问和指教的地方请私联:long.zhao@cisdi.com.cn

更多相关文章

  1. 【阿里云镜像】切换阿里巴巴开源镜像站镜像——Debian镜像
  2. 获取android设备 id
  3. Android之——根据手势简单缩放图片
  4. Android编程实现连接Wifi(运用Wifi 相关 API)
  5. AirPods怎么连接Android设备 AirPods与安卓设备连接方法
  6. Android(安卓)通讯录详解contact2.db
  7. Android(安卓)无线调试
  8. Android(安卓)客户端与服务器交互方式
  9. 读懂Android(安卓)(1):使用Android内部的DownloadProvider下载文

随机推荐

  1. Android(安卓)studio下gradle Robolectri
  2. Android的init过程(二):初始化语言(init.rc)解
  3. Android(安卓)界面中隐藏项目名称
  4. 新书内容连载(3):Android(安卓)SDK中常用命
  5. Android(安卓)学习小结
  6. [书目20101207]Google Android开发入门与
  7. android 中SoundPool总结
  8. Android事件分发机制 详解攻略
  9. Android平台简介
  10. android内存处理机制