本帖最后由 灞波儿奔 于 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十分熟悉,直接用它发起网络请求就可以了。