Android WiFi使用記錄

来源:http://www.cnblogs.com/fuccc/archive/2017/07/12/7157063.html
-Advertisement-
Play Games

最近在做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;
}


}

 

 

 

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 箭頭函數(arrow function) 基本格式 let say333=()= { console.log("333");//333 } say333(); (name)= { console.log(name); } 調用一個小括弧可以去掉 2個小括弧就不能去掉 name= { console. ...
  • 伺服器推送事件(Server-sent Events)WebSocket 協議的一種伺服器向客戶端發送事件&數據的單向通訊。目前所有主流瀏覽器均支持伺服器發送事件,當然除了 Internet Explorer 。2333... WebSocket 協議是繼HTTP協議後又一伺服器客戶端通訊協議,不同 ...
  • JavaScript URL傳值過程中遇到的問題及知識點總結 Web系統開發過程中經常用到URL進行傳值,剛剛接觸時不太會解析,會出現中文亂碼問題等。 1、父子頁面之間的傳值(在一個頁面中以載入iframe框架的形式調出另一個頁面)。 var URL=“XXXX..?code=aaa&name=li ...
  • 上個周周末,接手了一個移動端的(外包)小項目,一直著手於PC端,對移動端還是一知半解,所以這也是我的一個挑戰,因此,今天心血來潮,總結一些移動端的基礎知識和技巧供自己以後方便查閱,歡迎大家補充或轉載: 一.單位(px,em,rem) 1.px:屏幕設備物理上能顯示出的最小的一個點,不同設備上點的長寬 ...
  • 擴展運算符(Spread operator) let zzz=[2,4,6]; console.log(zzz);//[2, 4, 6] console.log(...zzz);//2 4 6 展開併合並 let a=[1,2,3]; let b=[...a,4,5,6]; console.log( ...
  • 非同步:現在與將來 分塊的程式 可以把JavaScript 程式寫在單獨的js 文件中,這個程式是由多個塊組成的,這些塊 中只有一個是現在執行,其餘在撿來執行,最常見的塊單位是函數。 例如: function now() { return 21; } function later() { answer ...
  • 最新 iOS11中的AR特別火爆,自己也到網上找了幾個Demo把玩了下,核心代碼無非以下: //AR視圖:展示3D界面 @property(nonatomic,strong)ARSCNView *arSCNView; 添加模型方法一: // Create a new scene SCNScene * ...
  • 轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/73467267 本文出自 "【趙彥軍的博客】" 在無線測試中,網路測試是必不可少的環節,通過網路限速查看頁面渲染等效果,能有效保障低速網路下的用戶體驗和頁面性能。Fiddler可通過延 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...