2

正如我们所知,谷歌已经更新了他们的政策,新应用程序必须以 Android 11(API 级别 30)或更高版本为目标。如果我使用目标较低的 SDK,我的应用程序将按预期工作,但是当我使用目标 SDK 30 时,它没有按预期工作。

应用程序中有以下主要功能:

  • 适用于 Android 6 至 11(最新 Android 版本)的可用 WiFi 应在列表中可见
  • 单击任何列表项后,用户应连接到他们尊敬的 WiFi。它可以是 OPEN 或其他。
  • 与各自的 WiFi 连接后,如果有,它将重定向到强制页面。Captive 页面将 WebView 放入应用程序。

现在说到重点,我面临着目标 30 SDK 的以下问题。

  • 当我使用最新的建议 wifi 连接代码[1]时,它可以部分工作。有一个问题,假设我们已经连接到另一个 WiFi 连接,我正在尝试连接新的 WiFi,那么它没有连接到新的 WiFi,但我需要连接新的 Wifi。

在具有目标 SDK 30 的应用程序中使用的代码(未与新 Wifi 连接)-

    val suggestion = WifiNetworkSuggestion.Builder()
        .setSsid(SSID) // SSID of network
        .setWpa2Passphrase(wifiPassword) // password is network is not open
        //.setIsAppInteractionRequired(true) // Optional (Needs location permission)
        .build()

    val suggestionsList = listOf(suggestion)

    val wifiManager =
        applicationContext.getSystemService(WIFI_SERVICE) as WifiManager

    if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
        // do error handling here
        Log.e("NETWORK", "Error")
    }

    // Optional (Wait for post connection broadcast to one of your suggestions)
    val intentFilter =
        IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

    val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Log.e("NETWORK", "broadcastReceiver")

            if (!intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
                return;
            }
            // do post connect processing here
            Log.e("NETWORK", "post connect")
        }
    };
    registerReceiver(broadcastReceiver, intentFilter)
  • 每当我的目标 SDK 为 29 时,我就会使用 WifiNetworkSpecifier [2]方法在 Android 10 和 11 中连接 WiFi。它也可以正常工作。

在应用程序中使用目标 SDK 29 的代码(按预期工作,但目标 SDK 必须为 28 或 29,否则互联网将无法在应用程序中运行)-

  private fun android10andMoreVersionsWithoutOuterInternet(
    scanResult: ScanResult,
    wifiSSID: String,
    wifiPassword: String,
    capabilities: String
) {
    // Android 10 (API level 29) -- Android Q (Android 10)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val wifiManager =
            this.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

        val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
            .setSsid(wifiSSID)
            //.setSsidPattern(PatternMatcher(wifiSSID, PatternMatcher.PATTERN_PREFIX))
            .setWpa2Passphrase(wifiPassword)
            .build()

        val networkRequest = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            //.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            //.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            //.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
            .setNetworkSpecifier(wifiNetworkSpecifier)
            .build()
        val connectivityManager =
            this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager


        val networkCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                Log.d("NETWORK", "Network available")
                super.onAvailable(network)

                // To make sure that requests don't go over mobile data
                connectivityManager.bindProcessToNetwork(network)

                //unregister network callback
                //connectivityManager.unregisterNetworkCallback(this)
               // connectivityManager.bindProcessToNetwork(null)

                gotoNextScreen(scanResult, wifiManager)

            }

            override fun onUnavailable() {
                Log.d("NETWORK", "Network unavailable")
                super.onUnavailable()
            }

            override fun onLosing(network: Network, maxMsToLive: Int) {
                Log.d("NETWORK", "onLosing")
                super.onLosing(network, maxMsToLive)
            }

            override fun onLost(network: Network) {
                Log.d("NETWORK", "onLost")
                super.onLost(network)

                //connectivityManager.bindProcessToNetwork(null)
                //connectivityManager.unregisterNetworkCallback(this)
            }

        }
        connectivityManager.requestNetwork(networkRequest, networkCallback)
        val builder = NetworkRequest.Builder()
        builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
        //connectivityManager.registerNetworkCallback(networkRequest, networkCallback) // For listen
    }

}
  • 使用 Android 9 的旧折旧代码,一切都按预期工作。

    在下面的 Android 9 abd 中使用的代码(按预期工作并且不影响任何目标 SDK)-

     private fun android9AndPreviousVersion(
      scanResult: ScanResult,
      wifiSSID: String,
      wifiPassword: String,
      capabilities: String
       ) {
      val conf = WifiConfiguration()
      conf.SSID =
          "\"" + wifiSSID + "\"" // Please note the quotes. String should contain ssid in quotes
      conf.status = WifiConfiguration.Status.ENABLED
      conf.priority = 40
    
      if (Common.checkWifiType(capabilities) == "WEP") {
          Log.e("NETWORK", "Configuring WEP")
          conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
          conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN)
          conf.allowedProtocols.set(WifiConfiguration.Protocol.WPA)
          conf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN)
          conf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED)
          conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
          conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP)
          conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40)
          conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104)
          if (wifiPassword.matches(Regex("^[0-9a-fA-F]+$"))) {
              conf.wepKeys[0] = wifiPassword
          } else {
              conf.wepKeys[0] = "\"" + wifiPassword + "\""
          }
          conf.wepTxKeyIndex = 0
      } else if (Common.checkWifiType(capabilities) == "WPA") {
          Log.e("NETWORK", "Configuring WPA")
          conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN)
          conf.allowedProtocols.set(WifiConfiguration.Protocol.WPA)
          conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
          conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
          conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP)
          conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40)
          conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104)
          conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP)
          conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP)
          conf.preSharedKey = "\"" + wifiPassword + "\""
      } else {
          Log.e("NETWORK", "Configuring OPEN network")
          conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
      }
      val wifiManager =
          this.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
      val networkId = wifiManager.addNetwork(conf)
      Log.e("NETWORK", "Add result $networkId")
    
      if (ActivityCompat.checkSelfPermission(
              this,
              Manifest.permission.ACCESS_FINE_LOCATION
          ) != PackageManager.PERMISSION_GRANTED
      ) {
          return
      }
    
      val list = wifiManager.configuredNetworks
      for (i in list) {
          if (i.SSID != null && i.SSID == "\"" + wifiSSID + "\"") {
              Log.e("NETWORK", "WifiConfiguration SSID " + i.SSID)
              val isDisconnected = wifiManager.disconnect()
              Log.e("NETWORK", "isDisconnected : $isDisconnected")
              val isEnabled = wifiManager.enableNetwork(i.networkId, true)
              Log.e("NETWORK", "isEnabled : $isEnabled")
              val isReconnected = wifiManager.reconnect()
              Log.e("NETWORK", "isReconnected : $isReconnected")
              break
          }
      }
      //val connectionInfo: WifiInfo = wifiManager.getConnectionInfo()
      gotoNextScreen(scanResult, wifiManager)
    

    }

结论:当我使用WifiNetworkSpecifier连接到具有目标 SDK 30的可用 WiFi 时,我可以连接,但我的 Internet 只能在 App 中工作。当我使用最新的Suggestion wifi连接到具有目标 SDK 30的可用 WiFi 时,我无法连接到新的 WiFi。我在 Android 10 和 Android 11 设备中遇到了这个问题。

请向我建议解决方案。请检查我的 POC 代码[这里]

4

1 回答 1

0

To restrict the control of third party app, Android has changed the way of connecting to wifi network in Android 10 and Android 11

If you look closely to your first solution, you can see that you are suggesting the system that these wifi are available to connect, now the system will decide whether to connect or not. Now here if system is already connection to some wifi which have active internet connection then Android will ignore your suggestion until that wifi is unavailable.

Right, if you use WifiNetworkSpecifier it restrict the uses of the network to your app only.

于 2021-09-26T19:28:30.583 回答