WiFi的搜索
private void search() {
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
wifiManager.startScan();
}
我們在開始搜索WiFi之前確保當前WiFi功能是處於開啓狀態。如果未開啓,通過調用WifiManager的setWifiEnabled(boolean enable)去開啓。之後調用startScan()就開始掃描附近的WiFi了。而獲取掃描的結果我們就需要創建一個廣播接收者來處理。
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
List<ScanResult> scanResults = wifiManager.getScanResults();
wifiListAdapter.clear();
wifiListAdapter.addAll(scanResults);
}
};
系統在掃描結束後,會發出WifiManager.SCAN_RESULTS_AVAILABLE_ACTION的廣播,當我們的接收者接收到這個廣播的時候,通過WifiManager的getScanResults()就能獲取到掃描結果的集合了。ScanResult保存着每一個WiFi的信息。這裏我將這個集合設置到Adapter中,並在列表中展示出來。下面是Apater中主要的代碼:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(mResource, parent, false);
}
TextView name = (TextView) convertView.findViewById(R.id.wifi_name);
TextView signl = (TextView) convertView.findViewById(R.id.wifi_signal);
ScanResult scanResult = getItem(position);
name.setText(scanResult.SSID);
int level = scanResult.level;
if (level <= 0 && level >= -50) {
signl.setText("信號很好");
} else if (level < -50 && level >= -70) {
signl.setText("信號較好");
} else if (level < -70 && level >= -80) {
signl.setText("信號一般");
} else if (level < -80 && level >= -100) {
signl.setText("信號較差");
} else {
signl.setText("信號很差");
}
return convertView;
}
可以看出列表展示的數據也是比較簡單,只有WiFi的名稱和信號強度,這兩個數據也是平時用得比較多的。獲取到掃描結果後,我們就可以處理連接的邏輯了。
WiFi的連接
WiFi的連接相當於搜索就要複雜一些。首先給列表項設置點擊事件,獲取對應的ScanResult。
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
wifiManager.disconnect();
final ScanResult scanResult = wifiListAdapter.getItem(position);
String capabilities = scanResult.capabilities;
int type = WIFICIPHER_WPA;
if (!TextUtils.isEmpty(capabilities)) {
if (capabilities.contains("WPA") || capabilities.contains("wpa")) {
type = WIFICIPHER_WPA;
} else if (capabilities.contains("WEP") || capabilities.contains("wep")) {
type = WIFICIPHER_WEP;
} else {
type = WIFICIPHER_NOPASS;
}
}
config = isExsits(scanResult.SSID);
});
獲取到ScanResult後我們通過他的capabilities屬性判斷WiFi的加密方式。接着通過isExsits(String SSID)方法判斷系統是否保存着當前WiFi的信息。
private WifiConfiguration isExsits(String SSID) {
List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
for (WifiConfiguration existingConfig : existingConfigs) {
if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
return existingConfig;
}
}
return null;
}
如果之前連接過,則返回WiFi的配置信息,否則返回空對象。然後接着處理連接的邏輯
if (config == null) {
if (type != WIFICIPHER_NOPASS) {
final EditText editText = new EditText(MainActivity.this);
final int finalType = type;
new AlertDialog.Builder(MainActivity.this).setTitle("請輸入Wifi密碼").setIcon(
android.R.drawable.ic_dialog_info).setView(
editText).setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.w("AAA", "editText.getText():" + editText.getText());
config = createWifiInfo(scanResult.SSID, editText.getText().toString(), finalType);
connect(config);
}
})
.setNegativeButton("取消", null).show();
return;
} else {
config = createWifiInfo(scanResult.SSID, "", type);
connect(config);
}
} else {
connect(config);
}
當沒有獲取到所要連接WiFi的配置信息時,我們就需要用到前面獲取到的加密方式判斷是否需要輸入密碼。如果加密方式爲WAP或WEP時,則彈出提示框提示用戶輸入WiFi密碼。用戶輸入密碼後再調用connect(WifiConfiguration config)方法
如果可以獲取到所要連接WiFi的配置信息,則直接調用connect(WifiConfiguration config)。
private void connect(WifiConfiguration config) {
int wcgID = wifiManager.addNetwork(config);
wifiManager.enableNetwork(wcgID, true);
}
直接調用WifiManger的addNetwork方法,將配置信息傳進去後,會創建一個新的網絡描述的身份並返回回來,如果返回來是-1,則表示創建失敗。獲取到身份後,調用enableNetwork方法就能開始連接WiFi了。到了這裏,我們連接部分就完成了一半,接下來需要繼續處理WiFi連接過程中返回來的狀態。這裏同樣我們是需要用到廣播接收者來處理。
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO)
if (info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
text_state.setText("連接已斷開")
} else if (info.getState().equals(NetworkInfo.State.CONNECTED)) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE)
final WifiInfo wifiInfo = wifiManager.getConnectionInfo()
text_state.setText("已連接到網絡:" + wifiInfo.getSSID())
}
} else {
NetworkInfo.DetailedState state = info.getDetailedState()
if (state == state.CONNECTING) {
text_state.setText("連接中...")
} else if (state == state.AUTHENTICATING) {
text_state.setText("正在驗證身份信息...")
} else if (state == state.OBTAINING_IPADDR) {
text_state.setText("正在獲取IP地址...")
} else if (state == state.FAILED) {
text_state.setText("連接失敗")
}
}
}
上面是廣播接收者中的關鍵代碼。WiFi在連接的過程中系統會發出WifiManager.NETWORK_STATE_CHANGED_ACTION的廣播,當接收者接收到這條廣播時,獲取NetworkInfo的state來判斷當前的連接狀態。狀態值分別代表如下
NetworkInfo.State.DISCONNECTED //連接已斷開
NetworkInfo.State.CONNECTED //已成功連接
除了這兩個狀態之外,這裏還判斷了其他狀態
NetworkInfo.DetailedState state = info.getDetailedState();
if (state == state.CONNECTING) {
text_state.setText("連接中...");
} else if (state == state.AUTHENTICATING) {
text_state.setText("正在驗證身份信息...");
} else if (state == state.OBTAINING_IPADDR) {
text_state.setText("正在獲取IP地址...");
} else if (state == state.FAILED) {
text_state.setText("連接失敗");
}
DetailedState中包含了很多連接狀態的信息,這裏只對部分狀態進行處理,其他狀態值解析具體如下
IDLE:空閒
SCANNING:正在掃描
CONNECTING:連接中
AUTHENTICATING:正在進行身份驗證
OBTAINING_IPADDR:正在獲取Ip地址
CONNECTED:已連接
SUSPENDED:已暫停
DISCONNECTING:正在斷開連接
DISCONNECTED:已斷開
FAILED:失敗
BLOCKED:已阻止
VERIFYING_POOR_LINK:暫時關閉(網絡狀況不佳)
CAPTIVE_PORTAL_CHECK:判斷是否需要瀏覽器二次登錄