问题描述:
在一个 android 项目中 需要 开发 类似于 系统 wifi 连接的功能,选择可用 wifi 后,输入正确的密码后,WifiManager.SUPPLICANT_STATE_CHANGED_ACTION 中的 WifiManager.ERROR_AUTHENTICATING
密码错误广播 偶尔也会收到监听,文章最后已有解决方案
先看看 wifi 功能开发的常规流程
1、注意 wifi状态的监听
private void regiterWifiBroadcast() {
wifiReceiver = new WifiBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);//监听wifi是开关变化的状态
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);//监听wifi连接状态广播,是否连接了一个有效路由
filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);//监听wifi列表变化(开启一个热点或者关闭一个热点)
filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); //监听密码
registerReceiver(wifiReceiver, filter);
}
2、创建 wifi 监听的广播
//获取WifiManager
WifiManager wifiManager = (WifiManager)Context.getSystemService(Context.WIFI_SERVICE);
public class WifiBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())){
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
switch (state){
/**
* WIFI_STATE_DISABLED WLAN已经关闭
* WIFI_STATE_DISABLING WLAN正在关闭
* WIFI_STATE_ENABLED WLAN已经打开
* WIFI_STATE_ENABLING WLAN正在打开
* WIFI_STATE_UNKNOWN 未知
*/
case WifiManager.WIFI_STATE_DISABLED:{
Log.e(TAG,"wifi已经关闭");
break;
}
case WifiManager.WIFI_STATE_DISABLING:{
Log.e(TAG,"wifi正在关闭");
break;
}
case WifiManager.WIFI_STATE_ENABLED:{
Log.e(TAG,"wifi已经打开");
connectType = -1;
wifiManager.startScan();
break;
}
case WifiManager.WIFI_STATE_ENABLING:{
Log.e(TAG,"wifi正在打开");
break;
}
case WifiManager.WIFI_STATE_UNKNOWN:{
Log.e(TAG,"wifi未知状态");
break;
}
}
}else if(WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())){
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
Log.e(TAG, "--网络状态--" + info.toString());
if(NetworkInfo.State.DISCONNECTED == info.getState()){//wifi没连接上
Log.e(TAG,"wifi没连接上,已断开");
if(connectType!=0) {
connectType = 0;
for (int i = 0; i < realWifiList.size(); i++) {//没连接上将 所有的连接状态都置为“未连接”
realWifiList.get(i).setState(WifiSupport.WIFI_STATE_UNCONNECT);
}
adapter.setList(realWifiList);
listView.post(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
connectType = 0;
}else if(NetworkInfo.State.CONNECTED == info.getState()){//wifi连接上了
if(connectType!=1) {
connectType = 1;
WifiInfo connectedWifiInfo = WifiSupport.getConnectedWifiInfo(context);
String ssidName = connectedWifiInfo.getSSID();
wifiListSet(ssidName,connectType);
Log.e(TAG,ssidName + ":wifi连接上了");
//连接成功
Toast.makeText(context,ssidName + " 连接成功",Toast.LENGTH_SHORT).show();
//连接成功保持密码(用系统自己的方式保存密码)
//PreferenceHelper.write(mContext,ssidName,inputPass);
}
connectType = 1;
}else if(NetworkInfo.State.CONNECTING == info.getState()) {//正在连接
if(connectType!=2) {
connectType = 2;
WifiInfo connectedWifiInfo = WifiSupport.getConnectedWifiInfo(context);
String ssid = connectedWifiInfo.getSSID();
wifiListSet(ssid, connectType);
Log.e(TAG, ssid + "-->wifi正在连接");
}
connectType = 2;
}
}else if(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())){
Log.e(TAG,"网络列表变化了");
wifiListChange();
}else if(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())){ //密码监听
SupplicantState supplicantState = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
NetworkInfo.DetailedState state = WifiInfo.getDetailedStateOf(supplicantState);
int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1);
Log.e(TAG, "当前网络连接状态码:" + error + ";连接状态 --->>> " + state);
if (error == WifiManager.ERROR_AUTHENTICATING) {
String ssidName = wifiManager.getConnectionInfo().getSSID();
Log.e(TAG, ssidName + ":密码错误,连接状态 --->>>" + state +",connectType:" + connectType);
//状态为 DISCONNECTED 断开的 时候才是真的密码错误
if(state == NetworkInfo.DetailedState.DISCONNECTED){
Toast.makeText(context,"密码错误,连接失败",Toast.LENGTH_SHORT).show();
//用系统自己的方式忘记wifi
boolean b = WifiSupport.forgetWifiNetWork(ssidName, mContext);//连接失败后需要忘记密码,不然会因为重连机制导致反复广播
//密码错误时清空保持中的密码
//PreferenceHelper.write(mContext,ssidName,"");
}else if(state == NetworkInfo.DetailedState.SCANNING){
//密码正确的时,第一次会走密码错误的逻辑 进入 SCANNING 扫描的状态,或者进入 CONNECTING 连接的状态
}
}
}
}
}
3、监听到wifi开启后开始扫描周围可用 wifi
case WifiManager.WIFI_STATE_ENABLED:{
Log.e(TAG,"wifi已经打开");
connectType = -1;
wifiManager.startScan();
break;
}
4、监听到 wifi 发生变化的时候开始封装 可用的 wifi 信息
if(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())){
Log.e(TAG,"网络列表变化了");
sortScaResult();
}
/**
* 扫描周围可用的wifi,封装到List中
*/
public void sortScaResult(){
List<ScanResult> scanResults = WifiSupport.noSameName(WifiSupport.getWifiScanResult(this));
WifiInfo connectedWifiInfo = WifiSupport.getConnectedWifiInfo(this);
realWifiList.clear();
int index = -1;
String conn = "";
if (connectedWifiInfo != null) {
conn = connectedWifiInfo.getSSID();
if(!TextUtils.isEmpty(conn)){
if (conn.startsWith("\"")) {
conn = conn.substring(1, conn.length());
}
if (conn.endsWith("\"")) {
conn = conn.substring(0, conn.length() - 1);
}
}
}
Log.e(TAG,"附近有多少可用wifi: "+scanResults.size()+"\n当前连接的wifi信息="+connectedWifiInfo);
if(!isNullOrEmpty(scanResults)){
for(int i = 0;i < scanResults.size();i++){
WifiBean wifiBean = new WifiBean();
wifiBean.setWifiName(scanResults.get(i).SSID.trim());
wifiBean.setState(WifiSupport.WIFI_STATE_UNCONNECT); //只要获取都假设设置成未连接,真正的状态都通过广播来确定
wifiBean.setCapabilities(scanResults.get(i).capabilities);
wifiBean.setLevel(WifiSupport.getLevel(scanResults.get(i).level)+"");
realWifiList.add(wifiBean);
if (wifiBean.getWifiName().equals(conn)) {
wifiBean.setState(WifiSupport.WIFI_STATE_CONNECT);
index = i;
}
}
//排序
if (index != -1) {
WifiBean bean = realWifiList.get(index);
realWifiList.remove(index);
realWifiList.add(0, bean);
}
}
// Collections.sort(realWifiList);
if (adapter != null) {
adapter.setList(realWifiList);
listView.post(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
if(realWifiList.size() == 0){
ll_box.setVisibility(View.GONE);
tv_tips.setVisibility(View.VISIBLE);
}else {
ll_box.setVisibility(View.VISIBLE);
tv_tips.setVisibility(View.GONE);
}
}
5、点击 列表的 Adapter 选中 要连接的 wifi,输入密码,开始连接
/**
* Adapter条目的点击事件
*/
RVBaseAdapter.OnItemClickListener onItemClickListener = new RVBaseAdapter.OnItemClickListener() {
@Override
public void OnItemClick(View view, RVBaseAdapter.ViewHolder holder, int position, Object o) {
WifiBean wifiBean = realWifiList.get(position);
if (wifiBean.getState() == WifiSupport.WIFI_STATE_UNCONNECT || wifiBean.getState() == WifiSupport.WIFI_STATE_ON_CONNECTING) {
String capabilities = realWifiList.get(position).getCapabilities();
//当前wifi的加密方式是不需要密码的
if (WifiSupport.getWifiCipher(capabilities) == WifiSupport.WifiCipherType.WIFICIPHER_NOPASS) {//无需密码
WifiConfiguration tempConfig = WifiSupport.isExsits(wifiBean.getWifiName(), view.getContext());
if (tempConfig == null) {
WifiConfiguration exsits = WifiSupport.createWifiConfig(wifiBean.getWifiName(), null, WifiSupport.WifiCipherType.WIFICIPHER_NOPASS);
WifiSupport.addNetWork(exsits, view.getContext());
} else {
WifiSupport.addNetWork(tempConfig, view.getContext());
}
} else {
//String s = PreferenceHelper.readString(mContext, wifiBean.getWifiName());
WifiConfiguration wifiConfiguration = WifiSupport.isExsits(wifiBean.getWifiName(), view.getContext());
if (wifiConfiguration != null) {
//如果以前连接过的wifi就直接进行连接(如果连接失败会被删除)
WifiSupport.addNetWork(wifiConfiguration,mContext);
}else {
//需要密码,弹出输入密码dialog
noConfigurationWifi(position);
}
}
}
}
};
//输入密码dialog
public void noConfigurationWifi(int position) {
final WifiBean wifiBean = realWifiList.get(position);
String wifiName = wifiBean.getWifiName();
final CommonDialog inputDialog = new CommonDialog(mContext);
inputDialog.setTitle(wifiName);
final ClearEditText inputView = (ClearEditText) LayoutInflater.from(
mContext).inflate(R.layout.layout_input_edit, null);
inputDialog.setContent(inputView);
inputView.setHint("请输入密码");
inputView.setInputType(InputType.TYPE_CLASS_TEXT);
inputDialog.setPositiveButton(R.string.confirm,
new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String wifiName = wifiBean.getWifiName();
inputPass = inputView.getText().toString();
String capabilities = wifiBean.getCapabilities();
if(wifiEditCheck(capabilities,inputPass)){
WifiConfiguration wifiConfiguration = WifiSupport.createWifiConfig(wifiName,inputPass,WifiSupport.getWifiCipher(capabilities));
//连接wifi
WifiSupport.addNetWork(wifiConfiguration,mContext);
inputDialog.cancel();
}
}
});
inputDialog.setNegativeButton(R.string.cancel,
new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
inputDialog.cancel();
}
});
inputDialog.show();
}
问题:输入正确的密码后,
WifiManager.SUPPLICANT_STATE_CHANGED_ACTION
中的 WifiManager.ERROR_AUTHENTICATING
密码错误广播 偶尔也会收到监听
解决方案
网络连接状态码为: WifiManager.ERROR_AUTHENTICATING
并且连接状态为:NetworkInfo.DetailedState.DISCONNECTED
的时候才是真的密码错误,然后再去忘记密码!
if(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())){ //密码监听
SupplicantState supplicantState = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
NetworkInfo.DetailedState state = WifiInfo.getDetailedStateOf(supplicantState);
int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1);
Log.e(TAG, "当前网络连接状态码:" + error + ";连接状态 --->>> " + state);
if (error == WifiManager.ERROR_AUTHENTICATING) {
String ssidName = wifiManager.getConnectionInfo().getSSID();
Log.e(TAG, ssidName + ":密码错误,连接状态 --->>>" + state +",connectType:" + connectType);
//状态为 DISCONNECTED 断开的 时候才是真的密码错误
if(state == NetworkInfo.DetailedState.DISCONNECTED){
Toast.makeText(context,"密码错误,连接失败",Toast.LENGTH_SHORT).show();
//用系统自己的方式忘记wifi
boolean b = WifiSupport.forgetWifiNetWork(ssidName, mContext);//连接失败后需要忘记密码,不然会因为重连机制导致反复广播
//密码错误时清空保持中的密码
//PreferenceHelper.write(mContext,ssidName,"");
}else if(state == NetworkInfo.DetailedState.SCANNING){
//密码正确的时,第一次会走密码错误的逻辑 进入 SCANNING 扫描的状态,或者进入 CONNECTING 连接的状态
}
}
}
文中用到的工具类 下载地址