脑图
1.WifiManager
基础功能
interface IWifiManager {
// wifi是否打开
fun isWifiEnabled(): Boolean
// 操作wifi开关
fun switchWifi(isOpen: Boolean)
// 开始扫描附近wifi
fun startScan()
// 扫描后,获取扫描wifi列表
fun getScanResults(): MutableList
// 主动连接wifi,password为空则为无密码
fun connectWifi(wifiBean: WifiBean, password: String?): Boolean
// 忘记wifi
fun forgetWifi(wifiBean: WifiBean): Boolean
}
实现流程
1.权限检测
/**
@description 权限相关
*/
private val wifiPermission = activity.multiplePermissionsForResult()
private val permissionList = arrayOf(
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.WRITE_SETTINGS //用于sdk29调用系统wifi设置权限用
)
activity.multiplePermissionsForResult():
使用了registerForActivityResult(resultContract: ActivityResultContract,callback: ActivityResultCallback
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
这三个权限是为了兼容8.0、9.0中所需申请的wifi权限,用于wifi状态的监听和wifi扫描
Manifest.permission.WRITE_SETTINGS //用于sdk29调用系统wifi设置权限用
private fun checkPermission(block: () -> Unit) {
if (permissionList.hasPermission()) {
block.invoke()
} else {
wifiPermission.launch(permissionList) {
// 检测权限完整
var hasPermission = false
for (entry in it) {
if (!entry.value) {
hasPermission = false
break
} else {
hasPermission = true
}
}
if (hasPermission) block.invoke()
}
}
}
2.基础功能的具体实现
// 系统WifiManager的获取
val wifiManager by lazy {
activity.getSystemService(Context.WIFI_SERVICE) as WifiManager
}
override fun isWifiEnabled(): Boolean {
return wifiManager.isWifiEnabled
}
override fun switchWifi(isOpen: Boolean) {
// 新版本如果是android29的,只能通过上面这种凡是操作wifi
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// val panelIntent = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
// activity.startActivity(panelIntent)
// } else {
// wifiManager.isWifiEnabled = isOpen
// }
wifiManager.isWifiEnabled = isOpen
}
override fun startScan() {
checkPermission {
wifiManager.startScan()
}
}
/**
@description 获取系统扫描的wifi列表信息
*/
override fun getScanResults(): MutableList {
//过滤空的ssid并去重
val resultMap =
wifiManager.scanResults?.filter { !it.SSID.isNullOrBlank() }?.groupBy { it.SSID }
val scanResults = mutableListOf()
if (resultMap.isNullOrEmpty()) {
return scanResults
}
for ((_, value) in resultMap) {
// 取首个值
value.firstOrNull()?.let {
scanResults.add(it)
}
}
return scanResults
}
/**
@description 连接有密码的wifi,只支持版本低于29
@return 是否连接成功
*/
override fun connectWifi(wifiBean: WifiBean, password: String?): Boolean {
if (!wifiManager.isWifiEnabled) {
return false
}
// 无密码连接
if (password == null) {
val scanResult = wifiManager.scanResults.filter { it.SSID == wifiBean.ssid }
scanResult.forEach {
if (connectScanResult(it)) {
return true
}
}
return false
} else {
val padWifiNetwork =
createWifiConfig(
wifiBean.ssid ?: "",
password,
WifiBean.getCapabilityTag(wifiBean.capabilities)
)
return wifiManager.enableNetwork(wifiManager.addNetwork(padWifiNetwork), true)
}
}
override fun forgetWifi(wifiBean: WifiBean): Boolean {
val configurations = wifiManager.configuredNetworks
for (configuration in configurations) {
val replace = configuration.SSID.replace("\"", "")
if (replace == wifiBean.ssid) {
var removeResult = wifiManager.removeNetwork(configuration.networkId)
removeResult = removeResult and wifiManager.saveConfiguration()
return removeResult
}
}
return false
}
主要对IWifiMananger的接口方法进行实现,也是定义了对外调用最近本的几个方法
3.其他功能方法
/**
@description 主动连接扫描到的wifi
@param scanResult 系统wifi扫描返回的信息类
@return 是否连接成功
*/
private fun connectScanResult(scanResult: ScanResult?): Boolean {
return if (scanResult != null) {
// 1.查找曾经的wifi配置,已连上系统会存储下来
val config = getWifiConfig(scanResult.SSID)
if (config != null && config.status != WifiConfiguration.Status.DISABLED) {
if (BuildConfig.DEBUG) {
logSettingD(TAG, "找到了历史wifi:{scanResult.SSID}")
}
// 1.1找到以后调用连接
wifiManager.enableNetwork(config.networkId, true)
} else {
// 2.没有wifi配置,判断当前模板wifi加密方式
val capabilityTag = WifiBean.getCapabilityTag(scanResult.capabilities)
if (capabilityTag == WifiBean.CapabilityTag.NONE) {
// 2.1无加密,直接连接
val padWifiNetwork =
createWifiConfig(
scanResult.SSID,
capabilityTag = WifiBean.getCapabilityTag(scanResult.capabilities)
)
val netId = wifiManager.addNetwork(padWifiNetwork)
if (BuildConfig.DEBUG) {
logSettingD(TAG, "不需要密码连接wifi:{scanResult.SSID}")
}
wifiManager.enableNetwork(netId, true)
wifiManager.reconnect()
} else {
// 2.2有加密,并且曾经也没有wifi配置,自然不需要主动连接
if (BuildConfig.DEBUG) {
logSettingD(TAG, "需要密码连接wifi:${scanResult.SSID}")
}
false
}
}
} else {
if (BuildConfig.DEBUG) {
logSettingD(TAG, "connectWifi 没有找到")
}
false
}
}
/**
@description 将"ssid"替换成ssid
*/
private fun getWifiConfig(ssid: String?): WifiConfiguration? {
return wifiManager.configuredNetworks.firstOrNull {
it.SSID.replace("\"", "") == ssid
}
}
/**
@description 根据ssid、密码、加密方式,生产wifi配置信息
*/
private fun createWifiConfig(
ssid: String,
password: String = "",
capabilityTag: WifiBean.CapabilityTag
): WifiConfiguration {
// 1.初始化WifiConfiguration
val config = WifiConfiguration()
config.allowedAuthAlgorithms.clear()
config.allowedGroupCiphers.clear()
config.allowedKeyManagement.clear()
config.allowedPairwiseCiphers.clear()
config.allowedProtocols.clear()
//指定对应的SSID
config.SSID = "\"" + ssid + "\""
// 2.如果之前有类似的配置
val tempConfig = wifiManager.configuredNetworks.singleOrNull { it.BSSID == "\"$ssid\"" }
if (tempConfig != null) {
//则清除旧有配置 不是自己创建的network 这里其实是删不掉的
val isDisable = wifiManager.disableNetwork(tempConfig.networkId)
val isRemove = wifiManager.removeNetwork(tempConfig.networkId)
val isSave = wifiManager.saveConfiguration()
if (BuildConfig.DEBUG) {
logSettingD(TAG, "清除wifi配置:${tempConfig.SSID + (isDisable && isRemove && isSave)}")
}
}
// 3.根据加密方式生成不同配置
when (capabilityTag) {
WifiBean.CapabilityTag.NONE -> {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
//以WEP加密的场景
}
WifiBean.CapabilityTag.WEP -> {
config.hiddenSSID = true
config.wepKeys[0] = "\"" + password + "\""
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN)
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED)
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
config.wepTxKeyIndex = 0
//以WPA加密的场景
}
WifiBean.CapabilityTag.PSK -> {
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.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP)
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
config.status = WifiConfiguration.Status.ENABLED
}
else -> {
}
}
return config
}
/**
@description 获取wifi列表信息,WifiBean是期望的数据类型
*/
fun getWifiBeanList(): List {
//按照强度排序
val wifiList = getScanResults()
.sortedByDescending { it.level }
.map { scanResult ->
WifiBean.transform(scanResult)
}
val connectionInfoSsid = wifiManager.connectionInfo?.ssid?.replace("\"", "")
logSettingD(WifiProxy.TAG, "getWifiBeanList: connectionInfoSsid = $connectionInfoSsid")
return changeWifiListBySsid(connectionInfoSsid, WifiBean.ConnectStatus.CONNECTED, wifiList)
}
/**
@description 修改匹配后的wifiBean列表
@param ssid 要匹配的ssid
@param targetStatus 目标状态
@param list 要修改的wifiList数据
*/
fun changeWifiListBySsid(
ssid: String?,
targetStatus: WifiBean.ConnectStatus,
list: List
): MutableList {
val temps: MutableList = mutableListOf()
temps.addAll(list)
// 为空直接返回原有数据列表
if (ssid == null) return temps
for (i in list.indices) {
val temp = list[i]
if (ssid == temp.ssid) {
temp.connectStatus = targetStatus
temps.remove(temp)
temps.add(0, temp)
} else {
temp.connectStatus = WifiBean.ConnectStatus.DISCONNECT
}
}
return temps
}
2.WifiScanReceiver
/**
@description Wifi连接状态接收器
@param switchListener wifi开关状态监听
@param scanSucListener wifi扫描结果是否成功
@param connectListener wifi请求连接的状态监听
*/
class WifiScanReceiver(
private val wifiManager: WifiManager,
private val switchListener: (Boolean) -> Unit,
private val scanSucListener: (Boolean) -> Unit,
private val connectListener: (String, Boolean) -> Unit,
) : BroadcastReceiver() {
companion object {
const val TAG = "WifiScanReceiver"
}
fun register(activity: AppCompatActivity) {
activity.registerReceiver(this, IntentFilter().apply {
addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)
addAction(WifiManager.RSSI_CHANGED_ACTION)
})
}
override fun onReceive(context: Context?, intent: Intent?) {
logSettingD(TAG, "onReceive: action = ${intent?.action}")
intent?.run {
when (action) {
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION -> {
scanSucListener.invoke(isScanSuc(intent))
}
WifiManager.WIFI_STATE_CHANGED_ACTION -> {
handleSwitchChange(intent)
}
WifiManager.SUPPLICANT_STATE_CHANGED_ACTION -> {
handleSupplicantState(intent)
}
WifiManager.RSSI_CHANGED_ACTION ->{
}
}
}
}
/**
@description 处理wifi连接请求的状态变化
*/
private fun handleSupplicantState(intent: Intent) {
// 密码错误
val error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -1)
if (error == WifiManager.ERROR_AUTHENTICATING) {
wifiManager.connectionInfo?.ssid?.replace("\"", "")?.let {
logSettingD(TAG, "获取连接状态:密码错误")
connectListener.invoke(it, true)
}
return
}
// 获取连接状态
val supplicantState: SupplicantState? =
intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)
when (supplicantState) {
// 成功
SupplicantState.COMPLETED -> {
logSettingD(TAG, "获取连接状态:成功")
wifiManager.connectionInfo?.ssid?.replace("\"", "")?.let {
connectListener.invoke(it, false)
}
}
// 不活跃的
SupplicantState.INACTIVE -> {
logSettingD(TAG, "获取连接状态:不活跃的")
}
// 接口禁用
SupplicantState.INTERFACE_DISABLED -> {
logSettingD(TAG, "获取连接状态:接口禁用")
}
SupplicantState.DISCONNECTED -> {
logSettingD(TAG, "获取连接状态:断开连接")
}
SupplicantState.SCANNING -> {
logSettingD(TAG, "获取连接状态:正在扫描")
}
SupplicantState.AUTHENTICATING -> {
logSettingD(TAG, "获取连接状态:正在验证")
}
SupplicantState.ASSOCIATING -> {
logSettingD(TAG, "获取连接状态:正在关联")
}
SupplicantState.ASSOCIATED -> {
logSettingD(TAG, "获取连接状态:已经关联")
}
SupplicantState.FOUR_WAY_HANDSHAKE -> {
logSettingD(TAG, "获取连接状态:四次握手")
}
SupplicantState.GROUP_HANDSHAKE -> {
logSettingD(TAG, "获取连接状态:组握手")
}
SupplicantState.DORMANT -> {
logSettingD(TAG, "获取连接状态:休眠")
}
SupplicantState.UNINITIALIZED -> {
logSettingD(TAG, "获取连接状态:未初始化")
}
SupplicantState.INVALID -> {
logSettingD(TAG, "获取连接状态:无效的")
}
else -> {
logSettingD(TAG, "wifi连接结果通知")
}
}
}
/**
@description 处理wifi扫描结果是否成功
*/
private fun isScanSuc(intent: Intent): Boolean {
if (wifiManager.isWifiEnabled) {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
} else {
true
}
}
return false
}
/**
@description 处理wifi开关状态变化
*/
private fun handleSwitchChange(intent: Intent) {
val state =
intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
logSettingD(TAG, "handleStateChange: state = ${getWifiStateStr(state)}")
if (state == WifiManager.WIFI_STATE_ENABLED) {
switchListener.invoke(true)
} else if (state == WifiManager.WIFI_STATE_DISABLING || state == WifiManager.WIFI_STATE_DISABLED) {
switchListener.invoke(false)
}
}
private fun getWifiStateStr(state: Int): String {
return when (state) {
WifiManager.WIFI_STATE_DISABLED -> "Wifi已关闭"
WifiManager.WIFI_STATE_DISABLING -> "Wifi关闭中"
WifiManager.WIFI_STATE_ENABLED -> "Wifi已打开"
WifiManager.WIFI_STATE_ENABLING -> "Wifi打开中"
WifiManager.WIFI_STATE_UNKNOWN -> "Wifi未知状态"
else -> "Wifi未知状态"
}
}
}
主要用于配合wifiManager,获取到三种监听
1.SCAN_RESULTS_AVAILABLE_ACTION:监听扫描结果,扫描成功或失败会触发
2.WIFI_STATE_CHANGED_ACTION:处理wifi开关状态变化时,进行回调处理
3.SUPPLICANT_STATE_CHANGED_ACTION:处理wifi连接请求的状态变化
sdk29以后也出现了其他新的api监听回调,wifiManager.registerXXX()就能监听对应状态,但由于不兼容旧设备,因此全部wifi状态都用广播方式获取,广播获取频率会受到具体限制,具体情况详见官方文档
3.ConnectManager
/**
@author: Zed.Qiu
@date: 2022/8/15
@description: 用于管理网络状态发生变化的回调,以及处理信号变化回调
*/
class TyphurConnectManager(private var context: Context = TyphurCoreConst.app) {
companion object {
const val TAG = "TyphurConnectManager"
@Volatile
var instance: TyphurConnectManager? = null
fun getInstance(context: Context = TyphurCoreConst.app): TyphurConnectManager {
if (instance == null) {
synchronized(TyphurConnectManager::class.java) {
if (instance == null) {
instance = TyphurConnectManager(context)
}
}
}
instance?.context = context
return instance!!
}
/**
@description 是否有网络连接
*/
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 当前是否有网络
val nw = connectivityManager.activeNetwork ?: return false
val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false
return when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
// 蜂窝网
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
// 以太网
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
// vpn
actNw.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> true
else -> false
}
} else {
return connectivityManager.activeNetworkInfo?.isConnected ?: false
}
}
}
private var isRegister = false
/**
@description 网络状态变化回调管理列表
*/
private val networkCallbackList = mutableListOf()
/**
@description 网络连接管理器
*/
private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val networkCallback = object :
ConnectivityManager.NetworkCallback() {
override fun onUnavailable() {
super.onUnavailable()
logSettingD(TAG, "NetworkCallback onUnavailable! 网络不可访问")
networkCallbackList.forEach { callback ->
callback.onUnavailable()
}
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
// 网络可访问时绑定
val bindResult = connectivityManager.bindProcessToNetwork(network)
logSettingD(TAG, "NetworkCallback onAvailable! 网络已连接 bindResult = $bindResult")
networkCallbackList.forEach { callback ->
callback.onAvailable(network)
}
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
logSettingD(TAG, "NetworkCallback onLosing! 网络断开连接中")
networkCallbackList.forEach { callback ->
callback.onLosing(network, maxMsToLive)
}
}
override fun onLost(network: Network) {
super.onLost(network)
logSettingD(TAG, "NetworkCallback onLost! 网络已断开连接")
networkCallbackList.forEach { callback ->
callback.onLost(network)
}
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
logSettingD(TAG, "NetworkCallback onCapabilitiesChanged! 信号强度发生变化")
logSettingD(TAG, "networkCapabilities = $networkCapabilities")
networkCallbackList.forEach { callback ->
callback.onCapabilitiesChanged(network, networkCapabilities)
}
}
}
init {
register()
}
fun register(builder :NetworkRequest.Builder? =null) {
if (isRegister) return
if (builder == null){
registerNetworkCallback()
}else{
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
isRegister = true
}
fun unRegister() {
connectivityManager.bindProcessToNetwork(null)
connectivityManager.unregisterNetworkCallback(networkCallback)
networkCallbackList.clear()
isRegister = false
}
/**
@description 添加监听回调
*/
fun addCallback(callback: ConnectivityManager.NetworkCallback?) {
callback?.run {
if (!networkCallbackList.contains(this)) {
networkCallbackList.add(this)
}
}
}
/**
@description 移除监听回调
*/
fun removeCallback(callback: ConnectivityManager.NetworkCallback?) {
networkCallbackList.remove(callback)
}
/**
@description 注册wifi网络状态回调
*/
private fun registerNetworkCallback() {
val builder = NetworkRequest.Builder().apply {
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
addTransportType(NetworkCapabilities.TRANSPORT_VPN)
addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
}
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
}
主要功能:
1.持有系统ConnectivityManager,并注册了相关网络变化回调
2.isNetworkAvailable(),可判断当前网络是否可达
3.生命周期跟随Application,只需注册一次,可在任一地方进行对网络状态的监听
调用方式如下:
// 获取TyphurConnectManager对象
private val typhurConnectManager by lazy { TyphurConnectManager.getInstance() }
// 添加网络回调, isConnect代表是否连接, level代表信号强度
typhurConnectManager.addCallback(TyphurConnectCallback { isConnect, level ->
refreshByNetworkChange(isConnect, level)
}})
4.TyphurConnectCallback
/**
@author: Zed.Qiu
@date: 2022/8/15
@description: 默认网络回调
@param listener 参数1 是否联网 参数2 wifi信号等级
*/
class TyphurConnectCallback(var listener: Function2) : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
onNetworkChange()
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
onNetworkChange()
}
override fun onLost(network: Network) {
super.onLost(network)
onNetworkChange()
}
/**
@description 网络发生变化
*/
private fun onNetworkChange() {
val networkAvailable =
TyphurConnectManager.isNetworkAvailable(TyphurCoreConst.app)
TyphurCoreConst.mainScope.launchOnUi {
listener.invoke(networkAvailable, WifiBean.LEVEL.LEVEL_UNKNOW)
}
}
/**
@description desc
@param methodParameters
@return methodReturnType
*/
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
TyphurCoreConst.mainScope.launchOnUi {
val networkAvailable =
TyphurConnectManager.isNetworkAvailable(TyphurCoreConst.app)
val level = WifiBean.calculateLevel(networkCapabilities.signalStrength)
listener.invoke(networkAvailable, level)
}
}
}
只是对系统的网络回调做了一层简单的封装,暴露期望的回调监听提供给其他人
5.WifiBean
1.属性介绍
属性名称 | 类型 | 作用 |
---|---|---|
wifiName | String | wifi名称 |
levelValue | Int | 原始的信号值 |
ssid | String | wifi唯一标识 |
bssid | String | 无线网址的mac地址 |
connectStatus | ConnectStatus | ConnectStatus.DISCONNECT默认未不连接 |
2.方法介绍
方法名 | 作用 |
---|---|
fun isCapabilityEAP(capabilities: String?): Boolean | 是否为企业加密wifi eap |
fun getCapabilityTag(capabilities: String?): CapabilityTag | 获取加密类型标识 |
fun isCapabilityNone(capabilities: String?): Boolean | 是否为不加密wifi |
fun getCapabilityStr(capability: CapabilityTag): String | 获取加密方式字符 |
fun calculateLevel(levelValue: Int): LEVEL | 计算信号等级 |
fun transform(scanResult: ScanResult): WifiBean | ScanResult:扫描结果类转WifiBean |
3.具体实现
/**
* @author zed
*/
@Keep
data class WifiBean(
var wifiName: String? = null,
var levelValue: Int = 0,
var ssid: String? = null,
var bssid: String? = null,
var connectStatus: ConnectStatus = ConnectStatus.DISCONNECT,
/**
* 加密方式
*/
var capabilities: String? = null
) {
companion object {
const val CAPABILITY_NONE_STR = "NONE"
const val CAPABILITY_WEP_STR = "WEP"
const val CAPABILITY_PSK_STR = "PSK"
const val CAPABILITY_EAP_STR = "EAP"
/**
@description 获取加密类型标识
*/
fun getCapabilityTag(capabilities: String?): CapabilityTag {
capabilities?.run {
return when {
this.contains(CAPABILITY_WEP_STR) -> CapabilityTag.WEP
this.contains(CAPABILITY_PSK_STR) -> CapabilityTag.PSK
this.contains(CAPABILITY_EAP_STR) -> CapabilityTag.EAP
else -> CapabilityTag.NONE
}
}
return CapabilityTag.NONE
}
/**
@description 是否为企业加密wifi eap
*/
fun isCapabilityEAP(capabilities: String?): Boolean {
return CapabilityTag.EAP == getCapabilityTag(capabilities)
}
/**
@description 是否为不加密wifi
*/
fun isCapabilityNone(capabilities: String?): Boolean {
return CapabilityTag.NONE == getCapabilityTag(capabilities)
}
/**
@description 获取加密方式字符
*/
fun getCapabilityStr(capability: CapabilityTag): String {
return when (capability) {
CapabilityTag.WEP -> CAPABILITY_WEP_STR
CapabilityTag.PSK -> CAPABILITY_PSK_STR
CapabilityTag.EAP -> CAPABILITY_EAP_STR
else -> CAPABILITY_NONE_STR
}
}
/**
@description 信号等级, level1 > level2 > level3
*/
const val LEVEL1_ABS_VALUE = 50
const val LEVEL2_ABS_VALUE = 75
const val LEVEL3_ABS_VALUE = 90
/**
@description 计算信号等级
*/
fun calculateLevel(levelValue: Int): LEVEL {
val absValue = abs(levelValue)
return when {
absValue < LEVEL1_ABS_VALUE -> {
LEVEL.LEVEL1
}
absValue < LEVEL2_ABS_VALUE -> {
LEVEL.LEVEL2
}
absValue < LEVEL3_ABS_VALUE -> {
LEVEL.LEVEL3
}
absValue >= LEVEL3_ABS_VALUE -> {
LEVEL.LEVEL4
}
else -> {
LEVEL.LEVEL_UNKNOW
}
}
}
fun transform(scanResult: ScanResult): WifiBean {
return WifiBean().apply {
wifiName = scanResult.SSID?.replace("\"", "")
ssid = scanResult.SSID
bssid = scanResult.BSSID
connectStatus = ConnectStatus.DISCONNECT
capabilities = scanResult.capabilities
levelValue = scanResult.level
}
}
}
/**
@description 加密标识
*/
enum class CapabilityTag {
WEP, PSK, EAP, NONE
}
/**
@description Wifi信号等级
*/
enum class LEVEL {
LEVEL_UNKNOW, LEVEL1, LEVEL2, LEVEL3, LEVEL4
}
/**
@description 连接状态
*/
enum class ConnectStatus {
DISCONNECT, CONNECTED, CONNECTING
}
}
6.WifiProxy
基本功能
/**
@author: Zed.Qiu
@date: 2022/8/2
@description: wifi代理类接口
*/
interface IWifiProxy {
fun register()
fun unRegister()
/**
@description 检测wifi是否连接
*/
fun checkIsOpenWifi()
/**
@description 主动连接wifi
*/
fun connectWifi(wifiBean: WifiBean, password: String?)
}
具体实现
/**
@author: Zed.Qiu
@date: 2022/8/2
@description: Wifi状态代理类
*/
class WifiProxy(
val activity: AppCompatActivity,
private val wifiBeanListListener: ((List) -> Unit),
private val switchListener: Function1,
private val connectListener: (String, Boolean) -> Unit
) :IWifiProxy{
companion object {
const val TAG: String = "WifiProxy"
}
val typhurWifiManager by lazy {
TyphurWifiManager.getInstance(activity)
}
private val typhurConnectManager by lazy {
TyphurConnectManager.getInstance(activity)
}
private var receiver: WifiScanReceiver? = null
private val networkCallback = object :
ConnectivityManager.NetworkCallback() {
override fun onUnavailable() {
super.onUnavailable()
activity.lifecycleScope.launchOnUi {
wifiBeanListListener.invoke(typhurWifiManager.getWifiBeanList())
}
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
// 网络可访问时绑定
activity.lifecycleScope.launchOnUi {
wifiBeanListListener.invoke(typhurWifiManager.getWifiBeanList())
}
}
override fun onLost(network: Network) {
super.onLost(network)
activity.lifecycleScope.launchOnUi {
wifiBeanListListener.invoke(typhurWifiManager.getWifiBeanList())
}
}
}
override fun register() {
registerWifiNetworkCallback()
registerWifiScanReceiver()
}
override fun unRegister() {
// 解绑当前网络
activity.unregisterReceiver(receiver)
typhurConnectManager.removeCallback(networkCallback)
}
/**
@description 注册wifi网络状态回调
*/
private fun registerWifiNetworkCallback() {
typhurConnectManager.register()
typhurConnectManager.addCallback(networkCallback)
}
/**
@description 注册wifi扫描接收器
*/
private fun registerWifiScanReceiver() {
if (receiver == null) {
receiver = WifiScanReceiver(
typhurWifiManager.wifiManager, onWifiEnable(),
onScanWifiList(), connectListener
).apply {
register(activity)
}
}
}
/**
@description 扫描返回最终的WifiBean列表
*/
private fun onScanWifiList(): (Boolean) -> Unit = {
if (it) {
wifiBeanListListener.invoke(typhurWifiManager.getWifiBeanList())
} else {
wifiBeanListListener.invoke(listOf())
}
}
/**
@description wifi开关状态变化
*/
private fun onWifiEnable(): (Boolean) -> Unit = {
switchListener.invoke(it)
if (it) {
typhurWifiManager.startScan()
} else {
wifiBeanListListener.invoke(listOf())
}
}
/**
* 检查是否打开wifi
*/
override fun checkIsOpenWifi() {
val isWifiEnabled = typhurWifiManager.isWifiEnabled()
switchListener.invoke(isWifiEnabled)
if (isWifiEnabled) {
typhurWifiManager.startScan()
}
}
/**
@description 连接wifi
*/
override fun connectWifi(wifiBean: WifiBean, password: String?){
/* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
connectWifiSdk29(wifiBean, password)
}else{
typhurWifiManager.connectWifi(wifiBean, password)
}*/
typhurWifiManager.connectWifi(wifiBean, password)
}
/* *//**
@description 版本大于等于29的新连接方法
*//*
private fun connectWifiSdk29(wifiBean: WifiBean, password: String?) {
val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
.apply {
setSsid(wifiBean.ssid ?: "")
if (password != null) {
setWpa2Passphrase(password)
}
}.build()
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(wifiNetworkSpecifier)
.build()
connectivityManager.requestNetwork(networkRequest, networkCallback)
}
*//**
@description 企业wifi EAP连接,暂不能实现
*//*
fun connectWifiEAP(wifiBean: WifiBean, identity: String, password: String) {
val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
.setSsid(wifiBean.ssid ?: "")
.setWpa2EnterpriseConfig(WifiEnterpriseConfig().apply {
eapMethod = WifiEnterpriseConfig.Eap.PEAP
this.identity = identity
this.password = password
phase2Method = WifiEnterpriseConfig.Phase2.NONE
})
.build()
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(wifiNetworkSpecifier)
.build()
connectivityManager.requestNetwork(networkRequest, networkCallback)
}
*/
}
本质上,是持有俩个Manager,分别是TyphurConnectManager(管理网络状态变化)和TyphurWifiManager(管理wifi列表信息变化),另外对sdk版本29,做了一些差异化的网络连接处理,由于系统会强制弹窗wifi列表,并且不能连接上部分类型wifi,因此在这里注释调了,但旧方法还是可以用的,只是target sdk必须是28。android在sdk29开始就不允许应用层面去修改wifi相关配置,在sdk31也做了大量方法舍弃,在综合设备兼容后,还是考虑用旧版本实现。
compileSdk Integer.parseInt(project.findProperty("android.compile.sdk"))
defaultConfig {
applicationId "com.typhur.module.demo"
minSdk Integer.parseInt(project.findProperty("android.min.sdk"))
targetSdk Integer.parseInt(project.findProperty("android.target.sdk"))
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
//gradle.properties文件
#android sdk info
android.compile.sdk=32
android.min.sdk=28
android.target.sdk=28
7.WifiLifecycleHelper
/**
@author: Zed.Qiu
@date: 2022/8/2
@description: Wifi生命周期管理器
*/
class WifiLifecycleHelper(
private val activity: AppCompatActivity,
private val wifiProxy: WifiProxy
) : LifecycleEventObserver {
init {
activity.lifecycle.addObserver(this)
}
private lateinit var typhurWifiManager: TyphurWifiManager
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
when (event) {
Lifecycle.Event.ON_CREATE -> {
lifeCycleCreate()
}
Lifecycle.Event.ON_START -> {
}
Lifecycle.Event.ON_RESUME -> {
}
Lifecycle.Event.ON_PAUSE -> {
}
Lifecycle.Event.ON_STOP -> {
}
Lifecycle.Event.ON_DESTROY -> {
lifeCycleDestroy()
}
Lifecycle.Event.ON_ANY -> {
}
}
}
private fun lifeCycleCreate() {
typhurWifiManager = TyphurWifiManager.getInstance(activity)
wifiProxy.register()
wifiProxy.checkIsOpenWifi()
}
private fun lifeCycleDestroy() {
wifiProxy.unRegister()
}
fun isWifiEnabled(): Boolean {
return typhurWifiManager.isWifiEnabled()
}
fun switchWifi(wifiEnabled : Boolean){
typhurWifiManager.switchWifi(wifiEnabled)
}
fun forgetWifi(wifiBean: WifiBean){
typhurWifiManager.forgetWifi(wifiBean)
}
fun changeWifiListBySsid(
ssid: String?,
targetStatus: WifiBean.ConnectStatus,
list: List
): MutableList {
return typhurWifiManager.changeWifiListBySsid(ssid, targetStatus, list)
}
fun connectWifi(wifiBean: WifiBean, password: String?){
wifiProxy.connectWifi(wifiBean, password)
}
fun connectWifiEAP(wifiBean: WifiBean, identity: String, password: String){
// wifiProxy.connectWifiEAP(wifiBean, identity, password)
}
}
只是简单的生命周期辅助类,对所有方法同意封装了下
8.UI调用
wifiHelper = WifiLifecycleHelper(
this@SettingWifiActivity, WifiProxy(this,
{ list ->
Log.d("WifiProxy", "refreshList: ${list.toJsonString()}")
adapter.refreshList(list)
},
{
mBinding.btnTop.text = if (it) "关" else "开"
}, { ssid, isPwError ->
if (isPwError) {
Toast.makeText(this, "${connectWifiBean?.ssid} 密码错误", Toast.LENGTH_SHORT)
.show()
}
})
)
// 主动连接wifi,兼容sdk版本
wifiHelper.connectWifi(wifiBean, password)
// 当前是否有网络连接
val networkAvailable = WifiProxy.isNetworkAvailable(context)
// 判断当前wifi是否开启
val wifiEnabled = wifiHelper.isWifiEnabled()
// 切换开关
wifiHelper.switchWifi(!wifiEnabled)
// 忘记wifi
wifiHelper.forgetWifi(wifiBean)
// 修改wifi列表中某个wifi的连接状态
wifiHelper.changeWifiListBySsid(
wifiBean.ssid, wifiBean.connectStatus, adapter.currentList)