emmm…最近项目首页重构,UI重新弄,逻辑拆分重新写,变成我来写了…写完了,踩了好几个坑,好几个都忘记了,赶紧记一下防止都忘记了…
既然是WiFi连接,当然首先考虑到的是打开WiFi啊什么的,现在基本都是targetSdkVersion >=23了吧,这些就会有涉及到权限请求的问题.
主要是分为2个部分的权限:
1. 打开WIFI开关
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
这些权限仅仅是普通权限,直接写在清单文件里面即可…
2. 扫描WIFI信号
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
这个权限是隶属于 LOCATION 权限组,需要手动申请该权限.
权限组权限明细
https://developer.android.com/guide/topics/permissions/requesting.html
至于权限请求处理的第三方库,工具类大家自个找吧,多得是…
我这边因为除了常规的打开关闭WiFi,扫描WiFi信号还涉及到实际的业务逻辑,需要检测当前连接的是否为硬件对应的WiFi信号,同时页面和逻辑作不同的处理.撇开业务逻辑,说说常规流程和遇到的坑吧.
工欲善其事必先利其器,先封装一个WifiManager对应的工具类吧,否则操作起来实在麻烦.
判断WiFi是否开启(刚刚进入Activity/Fragment进行判断…)
mWifiManager.isWifiEnabled();
WiFi关闭,点击申请打开WiFi,请求Manifest.permission.ACCESS_FINE_LOCATION权限.
该权限涉及到扫描WiFi列表.
打开WiFi
if (!mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(true);
}
代码在执行到这一步的时候,小米/华为手机会弹窗出来(没有三丧,蓝绿厂的测试机,估计也差不多),是否允许打开WiFi开关,WTF…
这和权限有毛线关系,你们吃多了吧…
小米弹窗只需10秒钟,10秒钟没点击就会自动选择拒绝
华为更狠,15秒…
试了下MOTO X的 类似于原生Google的ROM…好好地,说开就开.
在实际过程中,掺杂着业务逻辑,需要一定时间的连接动画,请务必在动画执行完以后再次判断WiFi当前状态,毕竟在连接动画中,一个手势下拉状态栏,WiFi关掉就1,2秒就搞定,否则执行动画结束后,发现逻辑继续执行,但是WiFi是关闭的就尴尬了.
5.获得WiFi列表
mWifiManager.startScan();
// 得到扫描结果
mWifiList = mWifiManager.getScanResults();
// 得到配置好的网络连接
mWifiConfiguration = mWifiManager.getConfiguredNetworks();
遍历去重,建立制定WiFi名称规则的list进行展示和连接.
连不上就直接跳转设置手动连接吧
startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
以上仅仅是普通流程,主要问题还是在请求权限和打开WiFi,国内ROM设置的弹窗问题…
实际掺杂了业务逻辑后要麻烦的多,得考虑不同WiFi状态页面的显示情况和连接动画执行情况.
part.1主要涉及的是WiFi连接状态和业务逻辑.
这部分主要是对于切换WiFi开关后,通过监听对应广播后进行处理的一些情况和坑.
注册广播和注销广播
/**
* 注册wifi广播监听
*/
private void sendReceiver() {
IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mWiFiReceiver = new WifiStateReceiver();
mContext.registerReceiver(mWiFiReceiver, filter);
}
/**
* 注销wifi广播监听
*/
private void stopReceiver() {
if (mWiFiReceiver != null) {
mContext.unregisterReceiver(mWiFiReceiver);
mWiFiReceiver = null;
}
}
这个没什么好说的,将注册和注销放在对应的生命周期方法内即可.
首先是WiFi打开关闭的广播
WifiManager.WIFI_STATE_CHANGED_ACTION
//WIFI打开和关闭...
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
switch (wifiState) {
case WifiManager.WIFI_STATE_DISABLED:
//这里处理WiFi关闭以后的逻辑
break;
case WifiManager.WIFI_STATE_ENABLED:
break;
default:
break;
}
}
EXTRA_WIFI_STATE 对应的State有5种,分别是DISABLING、DISABLED、ENABLING、ENABLED、UNKNOWN.
后来对于EXTRA_WIFI_STATE,主要使用的就是 DISABLED来处理WiFi关闭的情况.至于WiFi开启则是通过 WifiManager.NETWORK_STATE_CHANGED_ACTION
当WifiManager.WIFI_STATE_ENABLED时,就能接收到NETWORK_STATE_CHANGED_ACTION.
它有6种情况,分别是CONNECTING、CONNECTED、SUSPENDED、DISCONNECTING、DISCONNECTED、UNKNOWN.
主要监听的是DISCONNECTED和CONNECTED.
它们代表的状态是 我WiFi开关是开着,但是我没有连接和我WiFi开关是开着,且我已经连接上.
我这边的办法是通过判断时间来进行去重
private static final int WIFI_DISABLED = 0;
private static final int WIFI_DISCONNECTED = 1;
private static final int WIFI_CONNECTED = 2;
private boolean forOnceByStatus(int index) {
long nowTime = TimeUtils.getCurrentTimeInLong();
if ((nowTime - (index == 0 ? timeForDisabled : (index == 1 ? timeForDisconnect : timeForConnect))) > 800) {
if (index == WIFI_DISABLED) {
timeForDisabled = nowTime;
} else if (index == WIFI_DISCONNECTED) {
timeForDisconnect = nowTime;
} else if (index == WIFI_CONNECTED) {
timeForConnect = nowTime;
}
return true;
} else {
return false;
}
}
分别在DISABLED,DISCONNECTED,CONNECTED进行调用,为true才允许执行相关逻辑.
当关闭WiFi:
WIFI关闭我进来了DISCONNECTED,时间是====1509342281409
WIFI关闭我进来了DISABLED,时间是====1509342281589
当开启WiFi:
WIFI开启我进来了DISCONNECTED,时间是====1509342288210
WIFI开启我进来了CONNECTED,时间是====1509342289212
总体来说,WiFi开启/关闭,扫描,连接,广播监听.API还是挺简单的,当涉及掺杂实际的业务逻辑时,就会变得贼鸡儿麻烦.
需要考虑的情况特别多,什么手动给你关WiFi,权限拒绝,弹窗拒绝,连到一半关,连接的不是指定WiFi……
还是多注意,多测试下各种情况吧.