通過wifi與設備進行通信(Android)
[復制鏈接]
本帖最后由 灞波兒奔 于 2019-2-17 21:40 編輯
通過wifi與設備進行通信(Android)
最近leader決定把app與設備之間的通信改為wifi,通過http協議實現設備之間的通信。
相對與之前的藍牙通信,的確簡單不少,但實際編碼當中也有坑。現在分享出來,希望能給需要的鞋童以幫助,有啥問題大家也可以討論一下。
切換手機wifi到指定wifi熱點
在baidu或者google輸入以上內容搜索,會出現很多相關資料,但是點開之后,才發現大多都是一樣,那么實用性怎么樣,于是我驗證了一下。
大致思路是,首先創建WifiConfiguration,按照wifi加密方式分為無密碼,有密碼(WEP,WPA)。
// 創建 WifiConfiguration
public WifiConfiguration CreateWifiInfo(String ssid, String password, int type) {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + ssid + "\"";
WifiConfiguration tempConfig = this.IsExsits(ssid);
if(tempConfig != null) {
mWifiManager.removeNetwork(tempConfig.networkId);
}
if(Type == 1) //WIFICIPHER_NOPASS {
此處省略……
}
if(Type == 2) //WIFICIPHER_WEP {
此處省略……
}
if(Type == 3) //WIFICIPHER_WPA {
此處省略……
}
return config;
}
從代碼中看,之中還判斷ssid是否存在,如果存在就用removeNetwork將此ssid的wifi從已配置信息wifi列表中remove掉。這一步是必要的,因為ssid就是手機wifi列表中wifi的名稱。具有相同ssid的wifi可能并不是同一wifi,如果使用了上次保留的配置信息,就可能到導致自動連接wifi失敗。但此代碼因為是很早之前寫的,所以在android6.0版本上并不適用。android6.0新特性加強了對手機權限控制,同時在wifi模塊也不再允許對已保存的wifi配置列表進行更新和刪除,這將會導致removeNetwork操作失敗。
下面看一下添加切換手機到指定wifi熱點的代碼
// 更改前寫法
public boolean addNetwork(WifiConfiguration wcg) {
int wcgID = mWifiManager.addNetwork(wcg);
boolean b = mWifiManager.enableNetwork(wcgID, true);
return b;
}
此代碼的確能使部分手機成功切換到指定wifi,但其實代碼并不規范,這將會導致在部分手機中切換失敗。下面介紹正確寫法
//更改后寫法
public boolean addNetwork(WifiConfiguration wifiConfiguration) {
mWifiManager.disconnect();
int networkId = mWifiManager.addNetwork(wifiConfiguration);
boolean res = mWifiManager.enableNetwork(networkId, true);
mWifiManager.saveConfiguration();
mWifiManager.reconnect();
return res;
}
指定通過wifi進行http請求
不要以為這樣就完了,還有個大坑在等我們
在測試過程中,突然發現,在手機wifi和數據流量同時存在時,部分手機會直接使用數據流量進行通信,這樣就導致手機與設備之間無法通信,因為手機與設備只有處在同一局域網下才能正常通信。
這可麻煩了,于是到處到解決辦法,終于在WifiManager 這個類找到一個方法enableNetwork上面有一大段英文,我們一起看一下。
/**
* Allow a previously configured network to be associated with. If
* disableOthers is true, then all other configured
* networks are disabled, and an attempt to connect to the selected
* network is initiated. This may result in the asynchronous delivery
* of state change events.
*
* Note: If an application's target SDK version is
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
* communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
* instead be sent through another network, such as cellular data,
* Bluetooth tethering, or Ethernet. For example, traffic will never use a
* Wi-Fi network that does not provide Internet access (e.g. a wireless
* printer), if another network that does offer Internet access (e.g.
* cellular data) is available. Applications that need to ensure that their
* network traffic uses Wi-Fi should use APIs such as
* {@link Network#bindSocket(java.net.Socket)},
* {@link Network#openConnection(java.net.URL)}, or
* {@link ConnectivityManager#bindProcessToNetwork} to do so.
*
* @param netId the ID of the network in the list of configured networks
* @param disableOthers if true, disable all other networks. The way to
* select a particular network to connect to is specify {@code true}
* for this parameter.
* @return {@code true} if the operation succeeded
*/
原來解決辦法在 ConnectivityManager 這個類的方法 requestNetwork 可以指定使用 wifi 或者蜂窩數據等訪問網絡。如果要指定用蜂窩數據進行通信,將 addTransportType 設置為TRANSPORT_CELLULAR即可。在有可用指定傳輸類型連接上后,onAvailable方法就會調用,其實主要就是獲取到 Network 。 Network 通過 openConnection 得到 HttpURLConnection ,相信大家對HttpURLConnection十分熟悉,直接用它發起網絡請求就可以了。