前言
Android适配是老生常谈的问题,现在来看看特别是扫描和连接wifi常常会出现失败的情况,明明是用的标准API为什么却不成功呢?这个时候就得查阅谷歌官方文档一探究竟了。
Android Q以前
mWifiManager可以满足所有功能
/**
* @Author
* @Desc wifi工具类
* @Date 2020/6/12
*/
public class WifiHelpUtils {
public static final int SECURITY_NONE = 0;
public static final int SECURITY_WEP = 1;
public static final int SECURITY_PSK = 2;
public static final int SECURITY_EAP = 3;
public static final int WIFI_NORMAL = 0;
public static final int WIFI_CONNECTING = 1;
public static final int WIFI_CONNECTED = 2;
private static WifiHelpUtils wifiHelpUtils = null;
private Context applicationContext;
private WifiManager mWifiManager;
public static WifiHelpUtils getInstance(Context context) {
if (wifiHelpUtils == null) {
wifiHelpUtils = new WifiHelpUtils(context);
}
return wifiHelpUtils;
}
private WifiHelpUtils(Context context) {
applicationContext = context.getApplicationContext();
mWifiManager = (WifiManager) applicationContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
/**
* 开启或关闭wifi
*/
public void openOrCloseWifi(boolean isOpen) {
if (mWifiManager.isWifiEnabled() ^ isOpen) {
mWifiManager.setWifiEnabled(isOpen);
}
}
/**
* 判断wifi是否开启
*/
public boolean isWifiOpened() {
return mWifiManager.isWifiEnabled();
}
/**
* 开始扫描
*/
public void startScan() {
if (mWifiManager == null)
return;
if (mWifiManager.isWifiEnabled()) {
mWifiManager.startScan();
}
}
/**
* 获取到wifi列表
*/
public List<ScanResult> getScanResult() {
if (mWifiManager == null)
return null;
if (!mWifiManager.isWifiEnabled())
return null;
List<ScanResult> list = new ArrayList<>();
List<ScanResult> scanResults = mWifiManager.getScanResults();
for (ScanResult result : scanResults) {
int i = 0;
for (ScanResult result1 : list) {
if (result1.SSID.equals(result.SSID))
break;
i++;
}
if (i == list.size()) {
list.add(result);
}
}
return list;
}
/**
* 判断有是否需要密码
*/
public static int getSecurity(ScanResult result) {
if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
} else if (result.capabilities.contains("PSK")) {
return SECURITY_PSK;
} else if (result.capabilities.contains("EAP")) {
return SECURITY_EAP;
}
return SECURITY_NONE;
}
/**
* wifi设置
*
* @param ssid
* @param pws
* @param isHasPws
*/
private WifiConfiguration getWifiConfig(String ssid, String pws, boolean isHasPws) {
WifiConfiguration config = new WifiConfiguration();
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
config.SSID = "\"" + ssid + "\"";
WifiConfiguration tempConfig = isExist(ssid);
if (tempConfig != null) {
mWifiManager.removeNetwork(tempConfig.networkId);
}
if (isHasPws) {
config.preSharedKey = "\"" + pws + "\"";
config.hiddenSSID = true;
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.status = WifiConfiguration.Status.ENABLED;
} else {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
}
return config;
}
/**
* 得到配置好的网络连接
*
* @param ssid
* @return
*/
public WifiConfiguration isExist(String ssid) {
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
for (WifiConfiguration config : configs) {
if (config.SSID.equals("\"" + ssid + "\"")) {
return config;
}
}
return null;
}
/**
* 有密码连接
*
* @param ssid
* @param pws
*/
public Boolean connectWifiPws(String ssid, String pws) {
mWifiManager.disableNetwork(getCurrentConnectInfo().getNetworkId());
int netId = mWifiManager.addNetwork(getWifiConfig(ssid, pws, !TextUtils.isEmpty(pws)));
return mWifiManager.enableNetwork(netId, true);
}
public void addNetwork(String ssid, String pws) {
int netID = getCurrentConnectInfo().getNetworkId();
if (netID > 0) {
mWifiManager.disableNetwork(netID);
}
disconnect();
WifiConfiguration wifiConfiguration = getWifiConfig(ssid, pws, !TextUtils.isEmpty(pws));
if (wifiConfiguration.networkId > 0) {
mWifiManager.enableNetwork(wifiConfiguration.networkId, true);
mWifiManager.updateNetwork(wifiConfiguration);
} else {
int wcgID = mWifiManager.addNetwork(wifiConfiguration);
if (wcgID != -1) {
mWifiManager.enableNetwork(wcgID, true);
mWifiManager.saveConfiguration();
// mWifiManager.reconnect();
}
}
}
/**
* 已配置直接重连
*/
public void reconnect(WifiConfiguration wifiConfiguration) {
int netID = getCurrentConnectInfo().getNetworkId();
if (netID > 0) {
mWifiManager.disableNetwork(netID);
}
disconnect();
if (wifiConfiguration.networkId != -1) {
mWifiManager.enableNetwork(wifiConfiguration.networkId, true);
mWifiManager.updateNetwork(wifiConfiguration);
}
}
public void disableNetWork(int id) {
mWifiManager.disableNetwork(id);
}
public void disconnect() {
mWifiManager.disconnect();
}
/**
* 判断指定wifi是否连接
*/
public boolean isConnected(String ssid) {
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
if (wifiInfo == null) {
return false;
}
switch (wifiInfo.getSupplicantState()) {
case AUTHENTICATING:
case ASSOCIATING:
case ASSOCIATED:
case FOUR_WAY_HANDSHAKE:
case GROUP_HANDSHAKE:
case COMPLETED:
return wifiInfo.getSSID().replace("\"", "").equals(ssid);
default:
return false;
}
}
public boolean isWifiConnected(Context context, String wifiHotspotName) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
if (info != null) {
String extraInfo = info.getExtraInfo();
if (extraInfo.equals("\"" + wifiHotspotName + "\"")) {
return true;
}
}
return false;
}
public boolean isConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) applicationContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
return activeNetInfo != null
&& activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI;
}
public WifiInfo getCurrentConnectInfo() {
return mWifiManager.getConnectionInfo();
}
@SuppressLint("PrivateApi")
public void forgetNetwork(int networkId) {
if (mWifiManager == null) {
return;
}
try {
Method forget = mWifiManager.getClass().getDeclaredMethod("forget", int.class, Class.forName("android.net.wifi.WifiManager$ActionListener"));
forget.setAccessible(true);
forget.invoke(mWifiManager, networkId, null);
ToastUtils.showShort("忘记密码成功");
} catch (Exception e) {
ToastUtils.showShort("忘记密码异常");
e.printStackTrace();
}
}
}
补充
创建wifi的方法
// 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况
public enum WifiCipherType {
WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
}
public WifiConfiguration createWifiInfo(String SSID, String password, WifiCipherType type) {
Log.v(TAG, "SSID = " + SSID + "## Password = " + password + "## Type = " + 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);
if (tempConfig != null) {
mWifiManager.removeNetwork(tempConfig.networkId);
}
// 分为三种情况:1没有密码2用wep加密3用wpa加密
if (type == WifiCipherType.WIFICIPHER_NOPASS) {// WIFICIPHER_NOPASS
config.wepKeys[0] = "";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
} else if (type == WifiCipherType.WIFICIPHER_WEP) { // WIFICIPHER_WEP
config.hiddenSSID = true;
config.wepKeys[0] = "\"" + password + "\"";
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers
.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
} else if (type == WifiCipherType.WIFICIPHER_WPA) { // WIFICIPHER_WPA
config.preSharedKey = "\"" + password + "\"";
config.hiddenSSID = true;
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.TKIP);
// config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.CCMP);
config.status = WifiConfiguration.Status.ENABLED;
}
return config;
}
Android Q以后
/**
* 文件名:WifiUtil
* 描 述:
* 作 者:
* 时 间:2022/8/17 10:10
*/
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSpecifier;
import android.net.wifi.WifiNetworkSuggestion;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import static android.content.Context.WIFI_SERVICE;
/**
* @author
*/
public class WifiUtil {
private ConnectivityManager connectivityManager;
private WifiManager mWifiManager;
private ConnectivityManager.NetworkCallback networkCallback;
public interface NetworkChangeListener {
void onNetworkChange(boolean enableNetwork);
}
public void removeNetworkChangeListener() {
if (null != mNetworkChangeListener) {
mNetworkChangeListener = null;
}
if (null != networkCallback) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
}
private NetworkChangeListener mNetworkChangeListener;
public void changeToWifi(NetworkChangeListener networkChangeListener, Activity context, String wifiName, String wifiPwd) {
mNetworkChangeListener = networkChangeListener;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
changeToWifiAfterQ(context, wifiName, wifiPwd);
} else {
changeToWifiBeforeQ(wifiName, wifiPwd);
}
}
/**
* 切换到指定wifi Android版本小于10
*
* @param wifiName 指定的wifi名字
* @param wifiPwd wifi密码,如果已经保存过密码,可以传入null
* @return
*/
public void changeToWifiBeforeQ(String wifiName, String wifiPwd) {
if (mWifiManager == null) {
Log.d(TAG, " ***** init first ***** ");
return;
}
WifiConfiguration wifiNewConfiguration = createWifiInfo(wifiName, wifiPwd);//使用wpa2的wifi加密方式
int newNetworkId = mWifiManager.addNetwork(wifiNewConfiguration);
if (newNetworkId == -1) {
Log.d(TAG, "操作失败,需要您到手机wifi列表中取消对设备连接的保存");
} else {
doChange2Wifi(newNetworkId);
}
// String mWifiName = "\"" + wifiName + "\"";
// /**
// * 判断定位权限
// */
// if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// return;
// }
// //获取wifi列表
// List wifiList = mWifiManager.getConfiguredNetworks();
// boolean bFindInList = false;
// for (int i = 0; i < wifiList.size(); ++i) {
// WifiConfiguration wifiInfo0 = (WifiConfiguration) wifiList.get(i);
//
// // 先找到对应的wifi
// if (mWifiName.equals(wifiInfo0.SSID) || wifiName.equals(wifiInfo0.SSID)) {
// // 1、 先启动,可能已经输入过密码,可以直接启动
// Log.d(TAG, " set wifi 1 = " + wifiInfo0.SSID);
// doChange2Wifi(wifiInfo0.networkId);
//
// return;
// }
// }
//
// // 2、如果wifi还没有输入过密码,尝试输入密码,启动wifi
// if (!bFindInList) {
// WifiConfiguration wifiNewConfiguration = createWifiInfo(wifiName, wifiPwd);//使用wpa2的wifi加密方式
// int newNetworkId = mWifiManager.addNetwork(wifiNewConfiguration);
// if (newNetworkId == -1) {
// Log.d(TAG, "操作失败,需要您到手机wifi列表中取消对设备连接的保存");
// } else {
// doChange2Wifi(newNetworkId);
//
// }
// }
}
/**
* 切换到指定wifi Android版本大于等于10
*
* @param context
* @param wifiName 指定的wifi名字
* @param wifiPwd wifi密码,如果已经保存过密码,可以传入null
* @return
*/
@TargetApi(Build.VERSION_CODES.Q)
public void changeToWifiAfterQ(Activity context, String wifiName, String wifiPwd) {
if (mWifiManager == null || connectivityManager == null) {
Log.d(TAG, " ***** init first ***** ");
return;
}
final WifiNetworkSuggestion suggestion1 =
new WifiNetworkSuggestion.Builder()
.setSsid(wifiName)
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();
final WifiNetworkSuggestion suggestion2 =
new WifiNetworkSuggestion.Builder()
.setSsid(wifiName)
.setWpa2Passphrase(wifiPwd)
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();
final WifiNetworkSuggestion suggestion3 =
new WifiNetworkSuggestion.Builder()
.setSsid(wifiName)
.setWpa3Passphrase(wifiPwd)
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();
final List<WifiNetworkSuggestion> suggestionsList = new ArrayList<WifiNetworkSuggestion>();
suggestionsList.add(suggestion1);
suggestionsList.add(suggestion2);
suggestionsList.add(suggestion3);
int removestatus = mWifiManager.removeNetworkSuggestions(suggestionsList);
if (removestatus == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
Log.d(TAG, "onAvailable 删除成功");
}
int addstatus = mWifiManager.addNetworkSuggestions(suggestionsList);
if (addstatus == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
Log.d(TAG, "onAvailable 添加成功");
}
//保存到wifi列表 API30
// Intent intent = new Intent(Settings.ACTION_WIFI_ADD_NETWORKS);
// intent.putParcelableArrayListExtra(Settings.EXTRA_WIFI_NETWORK_LIST, suggestions);
// context.startActivityForResult(intent, 0x125);
// if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// return;
// }
// 获取wifi扫描列表
// List<ScanResult> wifiList = mWifiManager.getScanResults();
// ScanResult scan = null;
// for (ScanResult scanResult : wifiList) {
// if (wifiName.equals(scanResult.SSID)) {
// scan = scanResult;
// break;
// }
// }
// //扫描到了Wi-Fi
// if (null != scan) {
//setSsidPattern/setSsid/setBssidPattern/setBssid should be invoked for specifier
NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
//.setSsidPattern(new PatternMatcher(wifiName, PatternMatcher.PATTERN_PREFIX))
.setSsid(wifiName)
.setWpa2Passphrase(wifiPwd)
//.setBssid(MacAddress.fromString(scan.BSSID))
.build();
NetworkRequest request =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setNetworkSpecifier(specifier)
.build();
unregisterNetWork();
networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.d(TAG, "onAvailable:" + network);
connectivityManager.bindProcessToNetwork(network);
if (mNetworkChangeListener != null) {
mNetworkChangeListener.onNetworkChange(true);
}
}
@Override
public void onUnavailable() {
super.onUnavailable();
if (mNetworkChangeListener != null) {
mNetworkChangeListener.onNetworkChange(false);
}
Log.d(TAG, "Your Password is incorrect");
}
};
connectivityManager.registerNetworkCallback(request, networkCallback);
connectivityManager.requestNetwork(request, networkCallback);
// } else {
// Log.d(TAG, "未找到目标Wi-Fi");
// }
}
@TargetApi(Build.VERSION_CODES.M)
private void unregisterNetWork() {
if (null != connectivityManager && null != networkCallback) {
connectivityManager.bindProcessToNetwork(null);
connectivityManager.unregisterNetworkCallback(networkCallback);
}
}
private boolean doChange2Wifi(int newNetworkId) {
// 如果wifi权限没打开(1、先打开wifi,2,使用指定的wifi
if (!mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(true);
}
boolean enableNetwork = mWifiManager.enableNetwork(newNetworkId, true);
if (mNetworkChangeListener != null) {
mNetworkChangeListener.onNetworkChange(enableNetwork);
}
if (!enableNetwork) {
return false;
} else {
return true;
}
}
/**
* 创建 WifiConfiguration,这里创建的是wpa2加密方式的wifi
*
* @param ssid wifi账号
* @param password wifi密码
* @return
*/
private WifiConfiguration createWifiInfo(String ssid, String password) {
WifiConfiguration config = new WifiConfiguration();
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
config.SSID = "\"" + ssid + "\"";
config.preSharedKey = "\"" + password + "\"";
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.status = WifiConfiguration.Status.ENABLED;
return config;
}
public static final String TAG = "WifiUtil";
private static final WifiUtil ourInstance = new WifiUtil();
private static Context mContext;
public static WifiUtil getIns() {
return ourInstance;
}
public void init(Context context) {
mContext = context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
connectivityManager = (ConnectivityManager)
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
}
mWifiManager = (WifiManager) mContext.getSystemService(WIFI_SERVICE);
}
}