最近在做Android的WiFi部分的開發,連接的工具類參照了這個文章的工具類。 http://www.cnblogs.com/zhuqiang/p/3566686.html 開發中碰上的一些問題,在這裡對一些解決辦法做了些記錄。 1.對於WiFi加密方式的識別 2.連接WiFi的成功率 開發中發現 ...
最近在做Android的WiFi部分的開發,連接的工具類參照了這個文章的工具類。
http://www.cnblogs.com/zhuqiang/p/3566686.html
開發中碰上的一些問題,在這裡對一些解決辦法做了些記錄。
1.對於WiFi加密方式的識別
String capabilities = scanResult.capabilities;
if (capabilities.contains("WPA") || capabilities.contains("wpa")) {
((WifiHolder) holder).setType(WifiConnector.WifiCipherType.WIFICIPHER_WPA);
} else if (capabilities.contains("WEP") || capabilities.contains("wep")) {
((WifiHolder) holder).setType(WifiConnector.WifiCipherType.WIFICIPHER_WEP);
} else {
((WifiHolder) holder).setType(WifiConnector.WifiCipherType.WIFICIPHER_NOPASS);
}
通過獲取scanResult的capabilities來判斷WiFi的加密方式
2.連接WiFi的成功率
開發中發現當我輸入密碼正確時,沒能連接到我的指定wifi。目前發現原因是由於WifiManager會保存歷史的WiFi配置造成了影響。
public List<WifiConfiguration> cleanWifiConfiguredNetworks(String ssid) {
List<WifiConfiguration> configuredNetworks = wifiManager
.getConfiguredNetworks();
for (int i = 0; i < configuredNetworks.size(); i++) {
wifiManager.removeNetwork(configuredNetworks.get(i).networkId);
}
return configuredNetworks;
}
很簡單直接清空了歷史配置或者設置其他為不可用。
3.wifi連接成功的監聽
不太喜歡廣播監聽,各種問題很多,我直接對當前連接wifi信息進行判斷。
先通過wifiManager.getConnectionInfo() 獲取當前的連接WiFi信息,
connectionInfo.getSSID().contains(ssid) ||
connectionInfo.getSupplicantState() != SupplicantState.COMPLETED
再判斷wifi的ssid以及wifimanager的狀態,兩條件都滿足時則WiFi連接成功。
項目需求我這接下來要進行socket通信,這種狀態下獲取的IP地址存在延遲增加了新的條件判斷,對於wifiinfo中的MeteredHint參數額外的判斷。當這變為true
時,獲取了正確IP。這個參數獲取方法給hide,不能調用需反射才能成功使用代碼如下:
//通過反射方法調用hide方法
public boolean getWifiInfoHint(WifiInfo connectionInfo) throws InstantiationException {
Class aClass = connectionInfo.getClass();
try {
Method getMeteredHint = aClass.getDeclaredMethod("getMeteredHint");
getMeteredHint.setAccessible(true);
Object invoke = getMeteredHint.invoke(connectionInfo);
return (boolean) invoke;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
獲取伺服器的IP地址方法:
DhcpInfo info = wifiManage.getDhcpInfo();
String serverAddress = intToIp(info.serverAddress);
// 將獲取的int轉為真正的ip地址,參考的網上的,修改了下
private String intToIp(int i) {
return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + ((i >> 24) & 0xFF);
}
OK 結束 修改過後的全部代碼如下:
package com.dopool.usersystem.hotspot;
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.dopool.usersystem.Constant;
import com.zhy.http.okhttp.utils.L;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class WifiConnector {
public Handler mHandler;
WifiManager wifiManager;
/**
* 向UI發送消息
*
* @param info 消息
*/
public void sendMsg(String info) {
if (mHandler != null) {
Message msg = new Message();
msg.obj = info;
mHandler.sendMessage(msg);// 向Handler發送消息
} else {
Log.e("wifi", info);
}
}
//WIFICIPHER_WEP是WEP ,WIFICIPHER_WPA是WPA,WIFICIPHER_NOPASS沒有密碼
public enum WifiCipherType {
WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
}
// 構造函數
public WifiConnector(Context context) {
// 取得WifiManager對象
this.wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
// 提供一個外部介面,傳入要連接的無線網
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 + "\"";
// nopass
if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
config.allowedKeyManagement.set(KeyMgmt.NONE);
}
// 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(AuthAlgorithm.OPEN);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedKeyManagement.set(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;
}
private boolean closeifi() {
boolean bRet = true;
if (wifiManager.isWifiEnabled()) {
bRet = wifiManager.setWifiEnabled(false);
}
return bRet;
}
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() {
try {
// 打開wifi
openWifi();
sendMsg("opened");
Thread.sleep(200);
// 開啟wifi功能需要一段時間(我在手機上測試一般需要1-3秒左右),所以要等到wifi
// 狀態變成WIFI_STATE_ENABLED的時候才能執行下麵的語句
while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
try {
// 為了避免程式一直while迴圈,讓它睡個100毫秒檢測……
Thread.sleep(100);
} catch (InterruptedException ie) {
}
}
//去掉以往的WiFi配置
List<WifiConfiguration> saveConfigureNetworks = cleanWifiConfiguredNetworks(ssid);
WifiConfiguration wifiConfig = createWifiInfo(ssid, password,
type);
if (wifiConfig == null) {
sendMsg("wifiConfig is null!");
return;
}
int netID = wifiManager.addNetwork(wifiConfig);
boolean enabled = wifiManager.enableNetwork(netID, true);
boolean connected = wifiManager.reconnect();
WifiInfo connectionInfo = wifiManager.getConnectionInfo();
int num = 0;
int sum = 25;
if (ssid.contains("DoPool")) {
sum = 35;
}
while (!connectionInfo.getSSID().contains(ssid) ||
connectionInfo.getSupplicantState() != SupplicantState.COMPLETED ||
ssid.contains("DoPool") ? !getWifiInfoHint(connectionInfo) : false) {
sendMsg(connectionInfo.getSSID() + "dd" + ssid + connectionInfo.getSupplicantState() + getWifiInfoHint(connectionInfo));
connectionInfo = wifiManager.getConnectionInfo();
try {
num++;
if (num == sum) {
sendMsg(ssid + "exception");
return;
}
// 為了避免程式一直while迴圈,讓它睡個100毫秒檢測……
Thread.sleep(200);
} catch (InterruptedException ie) {
}
}
for (int i = 0; i < saveConfigureNetworks.size(); i++) {
wifiManager.addNetwork(saveConfigureNetworks.get(i));
}
sendMsg(connectionInfo.toString());
sendMsg(ssid + "連接成功!");
} catch (Exception e) {
// TODO: handle exception
sendMsg(ssid + "exception");
e.printStackTrace();
}
}
}
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;
}
public List<WifiConfiguration> cleanWifiConfiguredNetworks(String ssid) {
List<WifiConfiguration> configuredNetworks = wifiManager
.getConfiguredNetworks();
for (int i = 0; i < configuredNetworks.size(); i++) {
wifiManager.removeNetwork(configuredNetworks.get(i).networkId);
}
return configuredNetworks;
}
ArrayList<ScanResult> list;
public List<ScanResult> getNoDopoolWifi() {
List<ScanResult> mSortWifi = getSortWifi();
//去掉帶Dopool的wifi
for (int i = 0; i < mSortWifi.size(); i++) {
if (mSortWifi.get(i).SSID.contains("DoPool")) {
mSortWifi.remove(i);
}
}
return mSortWifi;
}
public List<ScanResult> getSortWifi() {
wifiManager.startScan();
list = (ArrayList<ScanResult>) wifiManager.getScanResults();
ArrayList<ScanResult> scanResults = new ArrayList<>();
//去掉重覆的WiFi SSID的名字
for (int i = 0; i < list.size(); i++) {
if (list.get(i).SSID.equals("") || list.get(i).frequency > 3000) {
continue;
}
for (int j = 0; j <= scanResults.size(); j++) {
if (j == scanResults.size()) {
scanResults.add(list.get(i));
break;
} else if (scanResults.get(j).SSID.equals(list.get(i).SSID)) {
break;
}
}
}
//按照信號強度排序
for (int i = 0; i < scanResults.size(); i++) {
for (int j = 0; j < scanResults.size(); j++) {
if (scanResults.get(i).level > scanResults.get(j).level) {
ScanResult temp = null;
temp = scanResults.get(i);
scanResults.set(i, scanResults.get(j));
scanResults.set(j, temp);
}
}
}
return scanResults;
}
//通過反射方法調用hide方法
public boolean getWifiInfoHint(WifiInfo connectionInfo) throws InstantiationException {
Class aClass = connectionInfo.getClass();
try {
Method getMeteredHint = aClass.getDeclaredMethod("getMeteredHint");
getMeteredHint.setAccessible(true);
Object invoke = getMeteredHint.invoke(connectionInfo);
return (boolean) invoke;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
}