One, foreword

Recently, I was working on a wifi-related project, so I went to understand the official documents and relevant technical data, and sorted out the feasibility and methods of current WIFI connection, including scanning, connection and status monitoring.

Two, use method

The android 10 official has abandoned the original connection wifi, switch to peer connections: developer.android.com/guide/topic… This peer-to-peer connection is actually connected to the wifi within the APP, but the phone itself keeps the original wifi connection, so the original modification of wifi connection in the system has been abandoned. If you want to continue using it, you need to change the targetSdkVersion of the project to be less than 29.

1. The wifi management class

object WifiUtils { val mWifiManager by lazy { WiFiMoneyApplication.getApplication ()? .applicationContext? .getSystemService(Context.WIFI_SERVICE) as WifiManager } }Copy the code

Open the wifi

    fun openWifi() {
        mWifiManager.isWifiEnabled = true
    }
Copy the code

Connect the wifi

@SuppressLint("MissingPermission") fun connectWifi(context: Context, scanResults: List<ScanResult>, ssid: String, connect: (success: Boolean, scanResult: ScanResult) -> Unit) { if (! mWifiManager.isWifiEnabled) { return } val scanResult = scanResults.singleOrNull { it.SSID == ssid } if (scanResult ! = null) { val config = mWifiManager.configuredNetworks.singleOrNull { it.SSID.replace("\"", "") == ssid } if (config ! = null && config.status ! = WifiConfiguration.Status.DISABLED) { if (BuildConfig.LOG_DEBUG) { Log.d(TAG, "Found the history of wifi: ${scanResult. SSID}")}. Connect the invoke (mWifiManager. EnableNetwork (config.net workId, true), scanResult) } else { val type = getCipherType(scanResult.capabilities) if (type == WifiCapability.WIFI_CIPHER_NO_PASS) { Val padWifiNetwork = createWifiConfig(scanresult. SSID, type = getCipherType(scanResult.capabilities)) val netId = mWifiManager.addNetwork(padWifiNetwork) if (BuildConfig.LOG_DEBUG) { Log.d(TAG, "Don't need the password to connect wifi: ${scanResult. SSID}")}. Connect the invoke (mWifiManager. EnableNetwork (netId, true), ScanResult)} else {if (buildconfig.log_debug) {log. d(TAG, "Need password to connect wifi:${scanresult.ssid}")} connect.invoke(false, scanResult) } } } else { if (BuildConfig.LOG_DEBUG) { Log.d(TAG, "ConnectWifi not found ")}}} @SuppressLint("MissingPermission") fun createWifiConfig(SSId: String, password: String = "", type: WifiCapability ): WifiConfiguration {/ / initialization WifiConfiguration val config = WifiConfiguration () config. AllowedAuthAlgorithms. The clear () config.allowedGroupCiphers.clear() config.allowedKeyManagement.clear() config.allowedPairwiseCiphers.clear() Config. AllowedProtocols. The clear () / / specify the corresponding SSID config. The SSID = "\" "+ SSID +" \ "" / / if you have any similar configuration before val tempConfig = mWifiManager.configuredNetworks.singleOrNull { it.BSSID == "\"$ssid\"" } if (tempConfig ! = null) {/ / remove the old configuration is not create your own network here is delete not to drop the val isDisable = mWifiManager. DisableNetwork val workId (tempConfig.net) isRemove = mWifiManager.removeNetwork(tempConfig.networkId) val isSave = mWifiManager.saveConfiguration() if (BuildConfig.LOG_DEBUG) { Log.d(TAG, "Clear wifi configuration :${tempconfig. SSID + (isDisable && isRemove && isSave)}")}} // Scenario without password if (type == WifiCapability. WIFI_CIPHER_NO_PASS) {config. AllowedKeyManagement. Set (WifiConfiguration. KeyMgmt. NONE) / / with WEP encryption scenario} the else  if (type == WifiCapability.WIFI_CIPHER_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 / / in WPA encryption scenario} else if (type = = WifiCapability.WIFI_CIPHER_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.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP) config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP) config.status = WifiConfiguration.Status.ENABLED } return config } fun getCipherType(capabilities: String): WifiCapability { return when { capabilities.contains("WEB") -> { WifiCapability.WIFI_CIPHER_WEP } capabilities.contains("PSK") -> { WifiCapability.WIFI_CIPHER_WPA } capabilities.contains("WPS") -> { WifiCapability.WIFI_CIPHER_NO_PASS } else -> { WifiCapability.WIFI_CIPHER_NO_PASS } } } enum class WifiCapability { WIFI_CIPHER_WEP, WIFI_CIPHER_WPA, WIFI_CIPHER_NO_PASS }Copy the code

Outside calls

fun connectWifi(item: ScanResult) { if (item.BSSID == WifiUtils.mWifiManager.connectionInfo.bssid) { ToastUtils.showToast(context, getString(R.string.wifi_home_connect_error)) return } if (BuildConfig.LOG_DEBUG) { Log.d(TAG, } wifiutils.connectwifi (context!! , mWifiList, item.ssid) {success, scanResult -> if (success) {else {// Failed to find wifi to add, Try to enter a password activity? .let { activity -> InputPasswordDialog(activity, scanResult.SSID) { password -> val padWifiNetwork = WifiUtils.createWifiConfig( scanResult.SSID, password, WifiUtils.getCipherType(scanResult.capabilities) ) val netId = WifiUtils.mWifiManager.addNetwork(padWifiNetwork) val success2 = WifiUtils.mWifiManager.enableNetwork(netId, true) if (success2) { if (BuildConfig.LOG_DEBUG) { Log.d(TAG, "At this point find wifi and start connecting: ${success2}") } startConnectAni(item) } else { if (BuildConfig.LOG_DEBUG) { Log.d(TAG, "Failed to create connection ")} toastutils.showtoast (context!! , "failed to create connection ")}}}? .show() } } }Copy the code

Wifi intensity acquisition

fun getNetworkWifiLevel(wifiInfo: ScanResult): Return if (level <= 0 && level >= -50) {// Strongest 5} else if (level < -50 && level >= -70) {// strong 4} else if (level < -70 && level >= -80) {// weak 3} else if (level < -80 && level) {// weak 3} else if (level < -80 && level >= -100) {// weak 2} else {1}}Copy the code

2. Monitor wifi connection status

private fun registerWifiStatusListener() { val filter = IntentFilter() Filter. addAction(SUPPLICANT_STATE_CHANGED_ACTION)// wifi connection result Filter. addAction(WIFI_STATE_CHANGED_ACTION) // wifi enabled or disabled Filter. addAction(NETWORK_STATE_CHANGED_ACTION)// Wifi connection status filter.addAction(SCAN_RESULTS_AVAILABLE_ACTION)// Listening wifi list change a hot (open or closed a hot) filter. The addAction (" android.net.conn.CONNECTIVITY_CHANGE ") / / network type switch activity?.application?.registerReceiver(mWifiReceiver, filter) } private val mWifiReceiver: BroadcastReceiver by lazy { object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent) { if (intent.action === WIFI_STATE_CHANGED_ACTION) { when (intent.getIntExtra(EXTRA_WIFI_STATE, WIFI_STATE_UNKNOWN)) {// WIFI_STATE_DISABLED -> {updateWifiStatus(6)} // WIFI_STATE_DISABLING -> {} // Available WIFI_STATE_ENABLED -> {} // WIFI_STATE_ENABLING -> {updateWifiStatus(5)} // WIFI_STATE_UNKNOWN -> { updateWifiStatus(1) } } } else if (NETWORK_STATE_CHANGED_ACTION == intent.getAction()) { val info: NetworkInfo = intent.getParcelableExtra(EXTRA_NETWORK_INFO) if (NetworkInfo.State.DISCONNECTED == info.state) { // If (buildconfig.log_debug) {log. d(TAG, "Connection has been disconnected")}} else if (NetworkInfo. State. CONNECTED = = info. State) {/ / wifi connection if (BuildConfig. LOG_DEBUG) {the d (TAG, "" "The wifi connection")} refreshWifiList ()} else if (NetworkInfo. State. CONNECTING = = info. State) {/ / the if is connected (BuildConfig.LOG_DEBUG) { Log.d(TAG, }} else if (SCAN_RESULTS_AVAILABLE_ACTION == intent.action) {val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, False) if (success) {scanSuccess()} else {scanFailure()} // wifi connection results notify wifi connection request status change} else if SUPPLICANT_STATE_CHANGED_ACTION == intent.action) {SUPPLICANT_STATE_CHANGED_ACTION == intent.getintextra (supplicant_error, supplicant_action) -1) if (error == ERROR_AUTHENTICATING) {if (buildconfig.log_debug) {log. d(TAG, "Get connection status: Val supplicantState: supplicantState: supplicantState: supplicantState: supplicantState: supplicantState: supplicantState: SupplicantState = intent. GetParcelableExtra (EXTRA_NEW_STATE) when (SupplicantState) {/ / success PLETED - > SupplicantState.COM {if (buildconfig.log_debug) {log. d(TAG, "Get connection status: Active supplicantState. INACTIVE -> {if (buildconfig.log_debug) {log. d(TAG, "Get connection status: Inactive ")} / / todo connection} / / interface disable SupplicantState INTERFACE_DISABLED - > {the if (BuildConfig. LOG_DEBUG) {the d (TAG, "get the connection status: Interface to disable ")}} SupplicantState. DISCONNECTED - > {the if (BuildConfig. LOG_DEBUG) {the d (TAG, "get the connection status: SupplicantState.SCANNING -> {if (buildconfig.log_debug) {log. d(TAG, "SupplicantState: Is scanning ")}} SupplicantState. AUTHENTICATING - > {the if (BuildConfig. LOG_DEBUG) {the d (TAG, "get the connection status: Are validation ")}} SupplicantState. ASSOCIATING - > {if (BuildConfig. LOG_DEBUG) {the d (TAG, "get connection status: Are ASSOCIATED with ")}} SupplicantState. Yahoo - > {if (BuildConfig. LOG_DEBUG) {the d (TAG, "get the connection status: }} supplicantstate.four_way_handshake -> {if (buildconfig.log_debug) {log. d(TAG, "accessstate: }} supplicantstate. GROUP_HANDSHAKE -> {if (buildconfig.log_debug) {log. d(TAG, "Accessstate: Supplicantstate.lyte -> {if (buildconfig.log_debug) {log.d (TAG, "Obtain connection status: Dormancy ")}} SupplicantState. UNINITIALIZED - > {the if (BuildConfig. LOG_DEBUG) {the d (TAG, "get the connection status: Uninitialized ")}} supplicantstate. INVALID -> {if (buildconfig.log_debug) {log. d(TAG, "SupplicantState: Invalid ")}} else -> {if (buildconfig.log_debug) {log.d (TAG, "Wifi connection results notice")}}}} else if (" android.net.conn.CONNECTIVITY_CHANGE "= = intent. The action) {if (BuildConfig. LOG_DEBUG) { Log.d(TAG, "Network type changed ")} updateNetWorkType()}}}}Copy the code

3. Apply for wifi permission

RxPermissions(this).request( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.ACCESS_WIFI_STATE ).subscribe { if (! It) {// No permission}}Copy the code

4. Updated wifi list

fun refreshWifiList() { if (! WifiUtils. MWifiManager. IsWifiEnabled) {return} mWifiList. The clear () / / original wifi list val originList = WifiUtils. MWifiManager. ScanResults / / current wifi val currentWifi = originList. SingleOrNull {it. BSSID = = WifiUtils.mWifiManager.connectionInfo.bssid && WifiUtils.mWifiManager.connectionInfo.supplicantState == SupplicantState.COM PLETED} / / wifi is added to the list for ((I, _) in originList. WithIndex ()) {/ / whether the hotspot SSID has set up a file in the list val position: Int = getItemPosition(mWifiList, originList[I]) if (originList[I].ssid.isnotempty ()) {if (position! = -1) {// already in list // same SSID hotspot, If (mWifiList[position].level < originList[I].level) {mwifilist.removeat (position) mwifilist.add (position, OriginList [I])}} else {originList[I]}} T2 -> t2.level-t1. level})} var p = -1 currentWifi? .let { for ((i, value) in mWifiList.withIndex()) { if (currentWifi.BSSID == value.BSSID) { p = i } } updateWifiName() } if (p ! = -1 && currentWifi ! = null) { mWifiList.removeAt(p) mWifiList.add(0, currentWifi) mWifiAdapter.connectPosition = 0 } else { mWifiAdapter.connectPosition = -1 } MWifiAdapter. NotifyDataSetChanged () / / in the wifi connection, a success if only you switch (mLastStatus! = 2 || (mLastStatus == 2 && currentWifi ! = null)) {if (mwifilist.isNOtempty ()) {updateWifiStatus(1)} else {updateWifiStatus(4)}} // Refresh list updateListOpenOrNot() }Copy the code

5. Determine the type of network being used (when listening to turn off wifi network, this call still returns network)

Object NetworkUtils {const val NETWORK_NOT_DEFINE = -2 // No const val NETWORK_NONE = -1 // No network connection const val NETWORK_WIFI = 1 // wifi connection const val NETWORK_2G = 2 // 2G const val NETWORK_3G = 3 // 3G const val NETWORK_4G = 4 // 4G Const val NETWORK_5G = 5 // 5G const val NETWORK_MOBILE = 0 // Mobile traffic /** * Get the type of current network connection ** @param context context * @return int */ fun getNetworkState(context: Context): Int {val connManager = context.getSystemService(context.connectivity_service) as ConnectivityManager Return no network val activeNetInfo = connManager. ActiveNetworkInfo if (activeNetInfo = = null | |! ActiveNetInfo. IsAvailable) {return NETWORK_NONE} / / determine whether for WIFI val wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI) if (null ! = wifiInfo) { val state = wifiInfo.state if (null ! = state) { if (state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING) { return NETWORK_WIFI } } } // If not WIFI, Val telephonyManager = Context.getSystemService (context.telephony_service) as telephonyManager Val networkType = telephonyManager.networkType return when (networkType) { TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN -> NETWORK_2G TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyManager.NETWORK_TYPE_HSPAP -> NETWORK_3G TelephonyManager.NETWORK_TYPE_LTE -> NETWORK_4G TelephonyManager.NETWORK_TYPE_NR -> NETWORK_5G else -> NETWORK_MOBILE}} /** * Whether mobile data is being used */ fun isMobileNetwork (context: Context): Boolean { val a = getNetworkState(context) if (BuildConfig.LOG_DEBUG) { Log.d(TAG, GetNetworkState :${a}")} return a! = NETWORK_NONE && a ! = NETWORK_NOT_DEFINE && a ! = NETWORK_WIFI } }Copy the code

6. Wifi related API needs positioning function, need to determine whether the user has opened positioning

/** * Whether to enable location service */ fun isLocServiceEnable(context: context): Boolean { val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager val gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) val network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) return gps || network }Copy the code

7. List the new features above android10.

P2P connection Wifi is a peer-to-peer connection. A dialog box will appear inside the APP to request a Wifi connection, which is only used inside the APP

RequiresApi(build.version_codes.q) fun connectByP2P(context: context, scanResult: ScanResult, password: String, successListener: ((Network?) -> Unit)? = null, failListener: (() -> Unit)? = null) { val specifier = WifiNetworkSpecifier.Builder() .setSsidPattern(PatternMatcher(scanResult.SSID, PatternMatcher.PATTERN_PREFIX)) .setWpa2Passphrase(password) .build() val request = NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .setNetworkSpecifier(specifier) .build() val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network?) { connectivityManager.bindProcessToNetwork(network) successListener? .invoke(network) } override fun onUnavailable() { failListener? .invoke() } } connectivityManager.requestNetwork(request, Call this method after using networkCallback) / / connectivityManager. UnregisterNetworkCallback (networkCallback)}Copy the code

This is to give advice to the system, I feel very chicken ribs

RequiresApi(build.version_codes.q) private fun connectBySug(ssiD: String, password: String) { val suggestion = WifiNetworkSuggestion.Builder() .setSsid(ssid) .setWpa2Passphrase(password) .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build() val suggestionsList = listOf(suggestion) //wifiManager.removeNetworkSuggestions(suggestionsList) val status = wifiManager.addNetworkSuggestions(suggestionsList) if (status ! = WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { } val intentFilter = IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION); val broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (! intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) { return } } }; context.registerReceiver(broadcastReceiver, intentFilter); }Copy the code

Summary: In the development process, I found that wifi monitoring is really very much, it is estimated that there is no complete monitoring list, welcome to add, you can comment and discuss any questions.