Android 10 / API 29:如何将手机连接到配置的网络?

rol*_*ndl 15 android android-wifi android-connectivitymanager

我正在开发一个应用程序,用户必须在其中执行以下步骤:

  1. 将手机连接到wifi;
  2. 将手机从连接的对象连接到专用热点。

当用户连接到所连接对象的专用热点时,应用程序会执行一些 HTTP 请求以对其进行配置。然后,我想将应用程序自动重新连接到步骤 1 的全局 wifi。

从 API 21 到 API 28,此功能非常容易实现,因为我知道 SSID,我也想重新连接手机。它可以通过几行代码完成:

private fun changeCurrentWifiNetworkLegacy(ssidToConnect: String) {
    val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

    var ssidIdentifier: Int? = null

    wifiManager.configuredNetworks?.forEach { config ->
        Log.d("SSID", config.SSID)

        if (config.SSID == "\"${ssidToConnect}\"") {
            ssidIdentifier = config.networkId
        }
    }

    ssidIdentifier?.let { id ->
        wifiManager.enableNetwork(id, true)
    }
}
Run Code Online (Sandbox Code Playgroud)

在 API 29 上,根据这篇文章,这个简单的代码不再起作用:https : //developer.android.com/about/versions/10/privacy/changes#configure-wifi

根据文章,现在,我应该使用 2 个类:WifiNetworkSpecifier和/或WifiNetworkSuggestion.

不幸的是,我找不到使用这些类的工作示例来将用户连接到以前配置的 SSID。

有人已经做到了吗?

预先感谢您的帮助。

Tas*_*dar 6

万一任何可怜的人遇到这种情况,完全有可能是您的设备上的 API 损坏了。在我的 OnePlus 5、Android 10、Build 200513 上,会发生这种情况:

  1. 调用请求网络。无论我使用 Listener 还是 PendingIntent 版本都没有关系
  2. 操作系统找到网络,连接,onAvailable 和朋友被调用
  3. 操作系统立即断开连接。我可以在 logcat 中看到“应用发布请求,取消 NetworkRequest”
  4. 然而,事实并非如此 - 请求没有被取消,Android 重新启动并重新开始连接到网络的过程。转到 2. 并永远重复。

为此创建了一个 Android 错误:https : //issuetracker.google.com/issues/158344328

此外,如果您不以正确的顺序终止应用程序和对话框,并且只有重新启动有帮助,您可以让操作系统进入状态,当它不再显示“与设备一起使用”对话框时。

只需为自己省去麻烦,针对 Android 9 并使用 WifiManager API(如果您针对 10,这些 API 会很有帮助)。它甚至比新的 requestNetwork API 具有更好的用户体验。


Mun*_*Rae 3

您可以使用以下代码设置连接到哪个网络:

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
    val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkRequest = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .setNetworkSpecifier(
            WifiNetworkSpecifier.Builder()
                .setSsid("My ssid")
                .build()
        )
        .build()
    cm.requestNetwork(networkRequest, object: ConnectivityManager.NetworkCallback() {
        override fun onUnavailable() {
            Log.d("TEST", "Network unavailable")
        }

        override fun onAvailable(network: Network) {
            Log.d("TEST", "Network available")
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

这使用 ConnectivityManager 的networkRequest方法来请求具有特定 SSID 的网络。

此方法要求调用者拥有Manifest.permission.CHANGE_NETWORK_STATE修改系统设置的权限或能力(由 确定)Settings.System.canWrite(Context)

有关可以获取哪些信息的更多文档,请参阅NetworkCallback类。

(编辑:错过添加传输类型。)

进一步编辑:我需要使用.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)它才能正常工作。因为在WifiNetworkSpecifier中

只能用于请求本地 wifi 网络(即没有互联网功能)

根据文档

这会向我弹出设备请求,但最终会显示我请求的 Wifi 网络。

  • 设备弹出窗口花费了太多时间。有什么办法可以减少这种情况吗? (5认同)
  • 谢谢您的回答。我在互联网上找到了这段代码,但当我尝试它时它不起作用。不幸的是,当我调用 requestNetwork 方法时,我可以看到一个带有进度条的对话框,上面写着“与我的应用程序一起使用的设备”。一段时间后,会出现另一个对话框,内容为“未找到设备。请确保设备已打开并可连接”。我从来没有达到 onAvailable 方法。 (3认同)
  • 这是非常脆弱的代码,因为它无法与已经发布的 API 30 一起运行。将 == 更改为 >= (2认同)