** 前言:早在去年,我曾写过一个针对android6.0连接指定WiFi的文章。虽然能成功连接,但有好多不合理甚至错误的地方,因此现在对那篇文章进行重新编辑发布**。
最近项目中有通过已知WiFi名称和密码连接传感器WiFi,实现数据交换的需求。在网上找了许多资料发现都是复制黏贴,也有好多bug,现在我将其整理封装并在项目中使用。
github地址:https://github.com/tangjiang24/WifiConnector
用法
step1
在根build.gradle中添加:
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
在使用的模块build.gradle中添加:
dependencies {
implementation 'com.github.tangjiang24:WifiConnector:Tag'
}
(请替换 Tag 为最新的版本号: img)
Step2
分两种方法:
第一种:
1.将需要连接的activity继承 库中的 WifiActivity :
public class WifiConnectActivity extends WifiActivity{}
2.直接调用父类中的 connectWifi(String ssid, String pwd, int type) 方法:
connectWifi(String ssid,String pwd,int type);
3.重写连接失败成功的抽象方法即可:
@Override
public void onConnectWifiSucess() {
ToastUtil.showShortToast(this,"连接成功!!");
}
@Override
public void onConnectWifiFail(String failMsg) {
ToastUtil.showShortToast(this,failMsg);
}
第二种:
1.构建WifiConnector对象
WifiConnector connector = new WifiConnector(context);
2.调用其connectWifi () 方法,并在回调中写成功或者失败后的逻辑
connector.connectWifi(ssid, pwd, WifiUtil.TYPE_WPA, new WifiConnector.WifiConnectCallBack() {
@Override
public void onConnectSucess() {
Toast.makeText(WifiConnectActivity.this,"连接成功!!",Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectFail(String msg) {
Toast.makeText(WifiConnectActivity.this,msg,Toast.LENGTH_SHORT).show();
}
});
参数说明:
参数名 类型 意义
ssid String WiFi名称
pwd String WiFi 密码
type int 密码类型
wifiConnectCallBack WifiConnectCallBack 连接回调
三种密码类型:
WifiUtil.TYPE_NO_PWD(无密码)
WifiUtil.TYPE_WEB (WEB)
WifiUtil.TYPE_WPA(WPA)
注意:由于Java的单继承性,第一种方法有很大的局限,建议使用第二种方法。
原理:
1.判断当前手机wifi网络是否开启可用;
开启WiFi代码:
public boolean openWifi() {
boolean sucess = true;
if(!this.mWifiManager.isWifiEnabled()) {
sucess = this.mWifiManager.setWifiEnabled(true);
}
return sucess;
}
开启WiFi一般需要一定的时间,因此不能立马去连接,需要等WiFi稳定可用,经测试一般2.5秒即可完成,因此我们每隔100毫秒就去判断WiFi是否可用,代码如下:
if(!this.openWifi()) {
return false;
} else {
long timeMills = System.currentTimeMillis();
while(this.mWifiManager.getWifiState() != 3) {
try {
if(System.currentTimeMillis() - timeMills > 2500L) {
break;
}
Thread.sleep(100L);
} catch (InterruptedException var8) {
var8.printStackTrace();
}
}
2.根据WiFi名称,获取/创建WifiConfiguration;
首先我们需要判断是否包含有当前WiFi名称的WifiConfiguration,若包含则试着将其删除再添加。1.为什么是试着删除?因为在android6.0以上,只允许删除由本应用创建的wificonfiguratin,不能改变删除其他应用所创建的。 2.为什么不直接连接而要删除再添加?因为wificonfiguratin不一定是连接成功后的wificonfiguratin,也有可能是手残输错了密码,这样直接去连接会导致一辈子也连接不上。
具体代码如下:
private WifiConfiguration createWifiInfo(String SSID, String Password, int Type) {
WifiConfiguration config = new WifiConfiguration();
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
config.SSID = "\"" + SSID + "\"";
WifiConfiguration tempConfig = this.IsExsits(SSID);
List<WifiConfiguration> beforeConfig = this.mWifiManager.getConfiguredNetworks();
if(tempConfig != null) {
this.removeWifi(tempConfig.networkId);
}
List<WifiConfiguration> afterConfig = this.mWifiManager.getConfiguredNetworks();
if(tempConfig != null && beforeConfig.size() == afterConfig.size()) {
return tempConfig;
} else {
if(Type == 1) {
config.allowedKeyManagement.set(0);
}
if(Type == 2) {
config.hiddenSSID = true;
config.wepKeys[0] = "\"" + Password + "\"";
config.allowedAuthAlgorithms.set(1);
config.allowedGroupCiphers.set(3);
config.allowedGroupCiphers.set(2);
config.allowedGroupCiphers.set(0);
config.allowedGroupCiphers.set(1);
config.allowedKeyManagement.set(0);
config.wepTxKeyIndex = 0;
}
if(Type == 3) {
config.preSharedKey = "\"" + Password + "\"";
config.hiddenSSID = true;
config.allowedAuthAlgorithms.set(0);
config.allowedGroupCiphers.set(2);
config.allowedKeyManagement.set(1);
config.allowedPairwiseCiphers.set(1);
config.allowedGroupCiphers.set(3);
config.allowedPairwiseCiphers.set(2);
config.status = 2;
}
return config;
}
}
3.注册网络变化的广播,当监听到网络连接上时,判断当前WiFi网络的名称是否和目标WiFi的一致;
广播中主要代码:
NetworkInfo info = (NetworkInfo)intent.getParcelableExtra("networkInfo");
Log.i("wifi:", "接受到网络连接变化的广播,当前网络状态为:" + info.getState());
if(info.getState().equals(State.CONNECTED)) {
WifiManager wifiManager = (WifiManager)context.getSystemService("wifi");
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ssid = wifiInfo.getSSID();
Log.i("wifi:", "接受到网络连接变化的广播,已连接的网络的ssid=" + ssid);
this.mListner.isConnectMyWifi(ssid);
}
public void setOnWifiConnetListner(WifiConnectReceiver.onWifiConnectListner listner) {
this.mListner = listner;
}
public interface onWifiConnectListner {
void isConnectMyWifi(String var1);
}
activity中实现receiver中声明的接口onWifiConnectListner,主要代码:
public void isConnectMyWifi(String s) {
if(!TextUtils.isEmpty(this.ssid)) {
if(s.equals("\"" + this.ssid + "\"")) {
this.handler.removeMessages(1);
this.handler.removeMessages(2);
this.handler.sendEmptyMessageDelayed(1, 1000L);
} else {
Log.i("wifi:", "未连接到指定网络!");
this.sendFailMessage("未连接到指定网络!", 1L);
}
}
}
private void registWifiConnectReceiver() {
if(!this.mReceiverTag) {
this.wifiConnectReceiver = new WifiConnectReceiver();
this.mReceiverTag = true;
this.wifiConnectReceiver.setOnWifiConnetListner(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.wifi.STATE_CHANGE");
this.registerReceiver(this.wifiConnectReceiver, intentFilter);
}
总结及注意点:
1.开启WiFi时需要时间的,必须等稳定后再去连接;
2.手机中保存的wificonfiguratin不一定可用,连接时需要先删除再添加;
3.在6.0以后调用mWifiManager.removeNetwork(netId)只对本应用添加的有效;
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);