通過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
* <code>disableOthers</code> 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.
* <p>
* <b>Note:</b> 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
*/
從第七行開始,大概意思就是,在應用目標版本大於或等於LOLLIPOP(5.0)
就算wifi
是已連接的,網絡通信也可能不用wifi
,比喻說蜂窩數據。當 wifi
與蜂窩數據同時存在時,當wifi
無法使用時,系統會自動切換到蜂窩數據。這不就是我們出現的問題嗎,下面趕緊找解決辦法。接着看,app
確保使用wifi
進行通信,應該使用下面三個方法 APIbindSocket
、openConnection
、bindProcessToNetwork
。這個是不是說的有點抽象,就說三個方法,不告訴到底怎麼樣。額,我們只有迅速補腦了。
ConnectivityManager mConnectivityManager = (ConnectivityManager)Context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
mConnectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback(){
@Override
public void onAvailable(Network network) {
String url = "";
try {
HttpURLConnection conn = (HttpURLConnection) network.openConnection(new URL(url));
} catch (IOException e) {
e.printStackTrace();
}
}
});
原來解決辦法在 ConnectivityManager
這個類的方法 requestNetwork
可以指定使用 wifi
或者蜂窩數據等訪問網絡。如果要指定用蜂窩數據進行通信,將 addTransportType
設置爲TRANSPORT_CELLULAR
即可。在有可用指定傳輸類型連接上後,onAvailable
方法就會調用,其實主要就是獲取到 Network
。 Network
通過 openConnection
得到 HttpURLConnection
,相信大家對HttpURLConnection
十分熟悉,直接用它發起網絡請求就可以了。