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

时间:2019-11-08 15:38:04

标签: 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)
    }
}

在API 29上,根据本文https://developer.android.com/about/versions/10/privacy/changes#configure-wifi

,此简单代码不再起作用

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

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

有人已经实现了吗?

预先感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

只要万一有可怜的人遇到这种情况,API很有可能只是在您的设备上被破坏了。在我的OnePlus 5,Android 10,Build 200513上,会发生这种情况:

  1. 呼叫requestNetwork。我是否使用Listener或PendingIntent版本都没关系
  2. 操作系统找到网络,进行连接,onAvailable,并称为朋友
  3. 操作系统立即断开连接。我可以在logcat中看到“应用已释放请求,正在取消NetworkRequest”
  4. 但是,这不是正确的-并未取消请求,Android重新关联了该请求,并重新开始了连接到网络的过程。转到2.并重复一遍。

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

此外,如果您没有以正确的顺序终止应用程序和对话框,并且仅重新启动,则可以使操作系统进入不再显示“要使用的设备”对话框的状态。

只需为自己省事,以Android 9为目标,然后使用WifiManager API(如果以10为目标,则很有用)。与新的requestNetwork API相比,它甚至具有更好的用户体验。

答案 1 :(得分:0)

您可以使用以下代码设置要连接的网络:

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")
        }
    })
}

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

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

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

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

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

  

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

根据the docs

这给了我一个弹出设备的请求,但随后最终向我显示了我要求的Wifi网络。

答案 2 :(得分:0)

我尝试了很多代码,包括 WifiManager.addNetworkSuggestionsConnectivityManager.requestNetwork。最后我发现,只需调用 ConnectivityManager.unregisterNetworkCallback 即可恢复用户 wifi 连接。这个代码唯一让我不满意的地方,如果用户保存了WiFi A和WiFi B,那么系统会自动选择一个连接,而不是我指定的。