首先说下Android代码连接Wifi的几个步骤:(以下涉及到具体API函数自查哈,写的时候凭借印象大致写了下)
转载请注明出处:
胖虎:http://blog.csdn.net/ljphhj
1.首先要开启Wifi连接开关,mWifiManager.setWifiEnabled(true)
2.通过获取List<ScanResult>来获取到Wifi连接列表。(mWifiManager.getScanResults)
3.获取List<WifiConfiguration>列表。(mWifiManager.getConfiguredNetworks)
4. (1)创建配置要连接的WifiConfiguration(包括加密方式,SSID, 密码, [优先级]<-这个是这篇博文要说的重点)【如果选了这种方式,才进行第5步】 or (2)你连接第3步获取的Wifi配置列表中的一个NetworkId.(直接跳到第6步)
5.mConnectNetworkId = mWifiManager.addNetwork(WifiConfiguration),添加这个配置到Wifi Config (其实那个文件路径: /data/misc/wifi/wpa_supplicant.conf [ps: 这个文件是网上一堆"查看Wifi密码神器"的根基,包括万能Wifi钥匙噢!])
6.mWifiManager.enableNetwork(netId, true);
7.然后这边你需要等待Wifi连接上(两种方式,一种用广播,一种就是轮询咯,自己选择)
进入正题:
存在的问题(我也是请教别人得知的,有些地方可能不一定准确,如果有大神看到此博文,可以进行补充或者指正,谢谢):
Android 4.0之后加入了Roaming的机制,Android 5.0后又加入了另一个机制:auto join的机制, 两个机制大致差不多,就是当有一个SSID的信号强度,加密方式,或者其他因素计算出来的一个值(就是配置文件中的优先级的概念)比你要连接的Wifi的优先级数值要高的时候,会尝试去连接优先级较高的那个Wifi。
了解了这个存在问题,看看我们现在连接一个Wifi会遇到的问题(Android Version >= 4.0)
个人比较喜欢用图来解释,写博文随便画个图,方便大家理解。
从图中,想必可以知道这个问题出现的原因其实主要是:优先级列表,这个东东在我们Wifi断开跟某个SSID连接的时候,系统读取了一个优先级连接,判断出一个要连接的SSID,而我们只想连接我们的SSID,这样此时相当于有两个线程同时在进行,一但我们的SSID先连接上,System的连接晚我们一步连接上,就会导致我们刚连接上的SSID,马上就断开了。
有网友会自作聪明将要连接的SSID 它的WifiConfiguration的优先级配置很高(最高:100000),保证让它成为配置文件优先级最高的一个。认为这样的话,该SSID就会被系统认可,连接上我们先连接的SSID,但其实这个地方,你不能保证你写入优先级的时候在系统把配置文件中的优先级列表取出来之前。)
最后我个人的解决方案是:用跟系统设置模块相同的连接wifi的方式(即调用Connect来连接Wifi, 有时间可以去看下这块的代码,WifiSettings.java中的submit方法里面是连接逻辑,connect方法也在那里,我个人觉得应该是个队列类似的,这样的话你连接的操作和系统连接的操作应该是有先后关系的,而且Connect方法会更新一下优先级【最后连接上的Wifi优先级比较高】,所以我们要连接的SSID便获取到了最高的优先级)
解决方案:反射出系统设置连接的API(@hide)
/**
* 通过反射出不同版本的connect方法来连接Wifi
*
* @author jiangping.li
* @param netId
* @return
* @since MT 1.0
*
*/
private Method connectWifiByReflectMethod(int netId) {
Method connectMethod = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Logger.i(TAG, "connectWifiByReflectMethod road 1");
// 反射方法: connect(int, listener) , 4.2 <= phone's android version
for (Method methodSub : mWifiManager.getClass()
.getDeclaredMethods()) {
if ("connect".equalsIgnoreCase(methodSub.getName())) {
Class<?>[] types = methodSub.getParameterTypes();
if (types != null && types.length > 0) {
if ("int".equalsIgnoreCase(types[0].getName())) {
connectMethod = methodSub;
}
}
}
}
if (connectMethod != null) {
try {
connectMethod.invoke(mWifiManager, netId, null);
} catch (Exception e) {
e.printStackTrace();
Logger.i(TAG, "connectWifiByReflectMethod Android "
+ Build.VERSION.SDK_INT + " error!");
return null;
}
}
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) {
// 反射方法: connect(Channel c, int networkId, ActionListener listener)
// 暂时不处理4.1的情况 , 4.1 == phone's android version
Logger.i(TAG, "connectWifiByReflectMethod road 2");
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
Logger.i(TAG, "connectWifiByReflectMethod road 3");
// 反射方法:connectNetwork(int networkId) ,
// 4.0 <= phone's android version < 4.1
for (Method methodSub : mWifiManager.getClass()
.getDeclaredMethods()) {
if ("connectNetwork".equalsIgnoreCase(methodSub.getName())) {
Class<?>[] types = methodSub.getParameterTypes();
if (types != null && types.length > 0) {
if ("int".equalsIgnoreCase(types[0].getName())) {
connectMethod = methodSub;
}
}
}
}
if (connectMethod != null) {
try {
connectMethod.invoke(mWifiManager, netId);
} catch (Exception e) {
e.printStackTrace();
Logger.i(TAG, "connectWifiByReflectMethod Android "
+ Build.VERSION.SDK_INT + " error!");
return null;
}
}
} else {
// < android 4.0
return null;
}
return connectMethod;
}
Method connectMethod = connectWifiByReflectMethod(netId);
if (connectMethod == null) {
Logger.i(TAG,
"connect wifi by enableNetwork method, Add by jiangping.li");
// 通用API
mWifiManager.enableNetwork(netId, true);
}