Android应用程序创建热点以及自动链接Wifi,我遇到的问题以及我是怎么解决的

May 22 2014
技术

急速传歌这个功能需要App能够自动去连接另一个手机创建的热点,本文先说Wifi创建热点以及连接Wifi的原理,然后再讲我遇到的问题和我是怎么解决问题的。

B手机创建热点是一个自动的过程,A手机去连接B手机的热点也是一个自动的过程,此时手机B充当路由器的角色。

自动连接Wifi功能,就像我们通过系统设置WLAN里面,选择一个Wifi并且输入密码(如果有密码)的过程一样,只不过App知道了这个Wifi(带某个前缀)的密码,然后通过相关设置,可以自动去连接。

Android应用如何自动链接Wifi

Android开发里操作Wifi功能的api就在android.net.wifi.WifiManager这个类中,包括:

  • getConnectionInfo() 获取当前Wifi连接信息,返回WifiInfo对象,包括SSIDBSSIDnetworkIdipAddressmacAddress等信息
  • disableNetwork(int netId) 禁用这个network(即使Wifi扫描到这个热点也不会主动去连接),参数netId就是WifiInfo中的networkId
  • disconnect() 断开当前连接
  • getConfiguredNetworks() 返回已经保存的Wifi网络列表,返回值是List<WifiConfiguration>
  • updateNetwork(WifiConfiguration config) 更新Wifi配置,比如更新密码或网络的优先级
  • addNetwork(WifiConfiguration config) 添加一个新的Wifi配置,当我们在设置->WLAN中选择一个网络并输入密码连接后,系统会自动帮我们记住这个网络,这个方法返回int,是networkId
  • enableNetwork(int netId, boolean disableOthers) 调用这个方法后,一般手机会去自动去连接这个wifi网络,但是部分手机会连接失败
  • saveConfiguration(); 部分手机的连接失败
  • reconnect();

Android应用如何创建一个热点

Android开发中,创建热点的方法也是在WifiManager类中,不过都已经被Google @hide了。

@hide annotation就是Google隐藏了不稳定的方法,当稳定之后,自然会公开,如果我们现在要用这些方法,那么必须通过Java反射来调用

创建一个热点最重要的就是:配置一个WifiConfiguration 对象,通过配置

  • SSID: 热点的名字
  • preSharedKey 热点密码
  • hiddenSSID: 是否隐藏SSID
  • status:是否启用这个热点配置
  • allowedAuthAlgorithms:IEEE 802.11认证算法 OPEN
  • allowedGroupCiphers :组秘钥TKIP+CCMP
  • allowedPairwiseCiphers:对称秘钥TKIP+CCMP
  • allowedKeyManagement:秘钥管理WPA_PSK
  • allowedProtocols:加密协议WPA+RSN

启动热点也需要通过Java反射调用WifiManager类中的setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)方法,第一个参数就是前面配置的WifiConfiguration对象,第二个参数true表示打开,false表示关闭热点。

当时连接wifi的主要的代码就是,先配置好WifiConfiguration对象,然后就是添加向添加一个WifiConfiguration,这样就会返回这个Wifi配置的id,然后就enable这个Wifi配置,到此为止,一般的手机都可以连接成功

int networkId = mWifiManager.addNetwork(wifiConfig);

boolean enabled = mWifiManager.enableNetwork(networkId, true);

我遇到的第一个问题:

手机A不能自动的去连接手机B创建的热点,那么问题是手机B创建的热点有问题还是手机A连接热点的配置信息有问题?但是手机C又可以去连接手机B的热点,那么是否说明手机B的热点创建就没问题了呢?

试了很多手机之后,发现都可以连接到手机B的热点,那么我们初步判定就是手机A 的连接Wifi配置信息有问题!后来,我就用手机A系统设置里的Wifi连接功能去连接手机B的热点,可以连接!那么问题就是手机A 连接热点的配置有问题!

问题又来了:

同样的Wifi配置信息,为什么大部分手机都可以连接热点成功,而一些手机就不可以呢?而连接Wifi的方法都是在WifiMnager类中
我看到了一个方法public void connect(WifiConfiguration config, ActionListener listener)方法,看文档就是用来连接Wifi的!!!!但不幸的是,这个方法被@hide了!!!!肯跌啊@_@还好,在文档中可以看到:

For a new network, this function is used instead of a sequence of addNetwork(), enableNetwork(), saveConfiguration() and reconnect()

而这4个方法是pulic并且没有@hide的!!然后按照文档写的,再添加两行代码:

非常关键的两行代码,有些手机必须要在saveConfiguration操作之后才能成功连接热点

mWifiManager.saveConfiguration();
mWifiManager.reconnect();

手机A就可以连接成功了!!

我遇到的第二个问题:

HTC手机创建热点时热点的配置信息中的热点名字不起作用!HTC手机可以成功自动连接Wifi,也可以创建热点,但是不能改热点的名字!!这就导致了其他所有手机都不能自动连HTC手机的热点!那么问题显而易见就是创建热点的时候信息配置有问题!!那么为什么配置有问题呢?其他手机不是都可以的吗?

问题大致已经找到了,但是为什么这样呢?必须求助强大的Google了~~~经过一番搜索之后重要找到了!!!

WIFI热点设置,htc setWifiApEnabled Wificonfiguration
HTC 通过 WifiConfiguration 修改 SSID

原因就在于: HTC就喜欢自己去改一些Android系统的api,导致很多手机都可以正常运行的功能,到了HTC手机上就不能正常运行了!!!这不是肯跌吗?(╯‵□′)╯︵┻━┻

找到原因也找到了解决办法,这个bug就这么愉快的解决了~真的多谢强大的Google啊~~

说到最后

我们做事情过程中,一定会遇到很多各种各样的问题,

找到问题的原因(为什么会这样)比怎样去解决重要的多
怎样把大象放进冰箱呢? 打开冰箱,然后把大象放进去!

怎么解决问题呢?
先找到问题的原因,然后在找解决问题的办法

还是那句话,找到问题的原因比找到解决问题的办法更重要.

找到问题所在的原因,如果你不能解决,那么你可以求助于其他人,而当你不知道问题的原因的时候,你去求助别人的时候,别人还有帮你去找问题的原因,这肯定会浪费很多时间的。先不要找解决问题的办法,先找问题的原因~