// 主动连接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<I, O>,callback: ActivityResultCallback<O>) 这是新的权限申请方式,具体可看官方文档。方法在LifecycleOwner中,调用所需的俩个参数,resultContract是请求结果协议类,用于包裹输入值I和输出值O,其中输入值例如权限传递就是String(Manifest.permission.CHANGE_WIFI_STATE),输出值是Boolean,返回权限授权结果。第二个参数值callback,是onActivityResult的结果,用于最终结果回调。

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<ScanResult> {
        //过滤空的ssid并去重
        val resultMap =
            wifiManager.scanResults?.filter { !it.SSID.isNullOrBlank() }?.groupBy { it.SSID }
        val scanResults = mutableListOf<ScanResult>()
        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<WifiBean> { //按照强度排序 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<WifiBean> ): MutableList<WifiBean> { val temps: MutableList<WifiBean> = 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 { 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<ConnectivityManager.NetworkCallback>() @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<Boolean, WifiBean.LEVEL, Unit>) : 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.属性介绍

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<WifiBean>) -> Unit), private val switchListener: Function1<Boolean, Unit>, 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<WifiBean> ): MutableList<WifiBean> { 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