是否可以在Android Q上添加网络配置?

and*_*per 6 android wifimanager android-wifi android-10.0

背景

我注意到,在WifiManager类中有一个名为addNetwork的函数,如果我想恢复或保存网络信息(网络名称AKA SSID以及密码和类型),该功能可能很有用,以便我也可以连接到它。

问题

我找不到有关如何执行此操作的太多信息。我在StackOverflow上看到了各种示例,并且如果我以Android API 28(或更低版本)为目标,那么我确实成功地使它添加了网络,甚至连接到它。

但是,以Android 29(Android Q)为目标时,它无法添加网络。

我发现了什么

由于我正在尝试使用Android Q beta 4的Pixel 2,我认为可能是因为addNetwork已弃用,所以文档甚至说了这一点,并且如果我定位到Android Q,它将无法正常工作,并且确实无法使用工作:

兼容性说明:对于面向Build.VERSION_CODES.Q或更高版本的应用程序,此API始终返回-1。

通过准备WifiConfiguration和添加,看来它应该可以运行到Android Q(不包括)的方式。以后,我也可以根据需要连接到它。在Android Q上,它似乎已由WifiNetworkSuggestion取代,但似乎根本就不是在添加网络:

网络建议对象用于提供Wi-Fi网络,以便在自动连接到网络时进行考虑。应用无法直接创建此对象,它们必须使用WifiNetworkSuggestion.Builder#build()来获取此对象的实例。

应用可以使用WifiManager#addNetworkSuggestions(List)向平台提供此类网络的列表。

这是我当前的代码,适用于Android-Q之前的版本

@WorkerThread
fun addNetwork(context: Context, networkName: String, networkPassword: String? = null, keyMgmt: Int = WifiConfiguration.KeyMgmt.NONE) {
    val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
    val conf = WifiConfiguration()
    conf.SSID = "\"$networkName\""
    conf.preSharedKey = if (networkPassword.isNullOrEmpty()) "" else "\"$networkPassword\""
    conf.allowedKeyManagement.set(keyMgmt)
    when (keyMgmt) {
        WifiConfiguration.KeyMgmt.WPA_PSK -> {
            //WPA/WPA2
        }
        WifiConfiguration.KeyMgmt.IEEE8021X -> {
        }
        WifiConfiguration.KeyMgmt.WPA_EAP -> {
        }
        WifiConfiguration.KeyMgmt.NONE -> {
            if (networkPassword.isNullOrEmpty()) {
                //open network
                conf.wepKeys[0] = "\"\""
            } else {
                //wep
                conf.wepKeys[0] = "\"" + networkPassword + "\""
                conf.wepTxKeyIndex = 0
                conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40)
            }
        }
    }
    if (networkPassword.isNullOrEmpty()) {
        //open network
        conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
    } else {
    }
    wifiManager.isWifiEnabled = true
    while (!wifiManager.pingSupplicant()) {
        Log.d("AppLog", "waiting to be able to add network")
    }
    val networkId = wifiManager.addNetwork(conf)
    if (networkId == -1)
        Log.d("AppLog", "failed to add network")
    else {
        wifiManager.enableNetwork(networkId, false)
        Log.d("AppLog", "success to add network")
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎只需要这些权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
Run Code Online (Sandbox Code Playgroud)

但无论如何,只要您不针对Android Q(API 29)及更高版本,此方法就可以使用。当您以它为目标时,实际上我的确总是得到“ -1”,这意味着它失败了。

我也发现了问题跟踪的问题(在这里,我写了一篇关于它在这里),讲述一个人需要的API回来了,但我不知道它是关于添加网络。

WifiNetworkSuggestion来看一下,我没有看到它可以WifiConfiguration通过其构建器进行设置,因此这也是我怀疑不是添加网络的另一个原因。

但是我还是尝试了。例如,这是我尝试添加普通WPA网络的代码:

@WorkerThread
fun addNetworkAndroidQ(context: Context, networkName: String, networkPassword: String? = null) {
    val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
    val list = ArrayList<WifiNetworkSuggestion>()
    val builder = WifiNetworkSuggestion.Builder().setSsid(networkName)
    if (!networkPassword.isNullOrEmpty())
        builder.setWpa2Passphrase(networkPassword)
    list.add(builder.build())
    val result = wifiManager.addNetworkSuggestions(list)
    if (result == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS)
        Log.d("AppLog", "success")
    else Log.d("AppLog", "failed")
}
Run Code Online (Sandbox Code Playgroud)

运行时(我让它忘记了操作系统,我给了它Wifi网络详细信息),它说成功了,但是OS的Wifi设置上什么也没有发生。使用我添加的密码,该网络不存在。所以我真的不知道它做了什么...

几秒钟后,我注意到一条通知,询问我是否可以连接到该应用程序建议的网络:

在此处输入图片说明

但是当我选择接受时,它还是没有做任何事情。

我试图制作另一个POC,以为我可能做错了,但后来它甚至没有显示通知。由于我认为整个行为都是错误,因此我在这里进行了报道。

不仅如此,而且我发现,如果确实应该以一种或另一种方式添加网络,它仍然有一些严重的限制,例如最大添加的网络(在此处)以及在卸载应用程序时被删除(在此处))

问题

  1. 如何正确处理Android Q?真的没有API可以添加网络了吗?

  2. 如果WifiNetworkSuggestion不是要添加网络,那么它到底是用来做什么的?

  3. 由于我对添加网络的窍门还不熟悉,因此我的代码关于添加网络的所有可能方式是否正确?我之所以这样问,是因为有人在这里写道,人们应该启用Wifi并确保pingSupplicant返回的值是true。是真的吗 还是打电话就足够了addNetwork?

  4. 如果现在无法使用常规API添加网络,那么是否可以通过使用有根设备代替解决方案?也许一些adb命令?

Moh*_*yed 6

我遇到了同样的问题,但不知何故,我达到了连接所需网络的可重现状态,我想分享我的发现,这可能会有所帮助。

总结: 在应用WifiNetworkSuggestion逻辑之前,您必须禁用所有自动连接

欲知更多详情,请阅读以下内容:

我使用了以下代码(类似于您使用的代码):

private fun connectUsingNetworkSuggestion(ssid: String, password: String) {
    val wifiNetworkSuggestion = WifiNetworkSuggestion.Builder()
        .setSsid(ssid)
        .setWpa2Passphrase(password)
        .build()

    // 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) {
            if (!intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
                return
            }
            showToast("Connection Suggestion Succeeded")
            // do post connect processing here
        }
    }
    registerReceiver(broadcastReceiver, intentFilter)

    lastSuggestedNetwork?.let {
        val status = wifiManager.removeNetworkSuggestions(listOf(it))
        Log.i("WifiNetworkSuggestion", "Removing Network suggestions status is $status")
    }
    val suggestionsList = listOf(wifiNetworkSuggestion)
    var status = wifiManager.addNetworkSuggestions(suggestionsList)
    Log.i("WifiNetworkSuggestion", "Adding Network suggestions status is $status")
    if (status == WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE) {
        showToast("Suggestion Update Needed")
        status = wifiManager.removeNetworkSuggestions(suggestionsList)
        Log.i("WifiNetworkSuggestion", "Removing Network suggestions status is $status")
        status = wifiManager.addNetworkSuggestions(suggestionsList)
    }
    if (status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
        lastSuggestedNetwork = wifiNetworkSuggestion
        lastSuggestedNetworkSSID = ssid
        showToast("Suggestion Added")
    }
}
Run Code Online (Sandbox Code Playgroud)

所以这里是步骤:

  1. 安装新版本/或删除您之前添加的所有建议
  2. 确保您忘记了所有周围的网络,以便您的设备不会自动连接
  3. 添加wifi网络建议列表
  4. 转到 Wifi 设置扫描网络或等到下一次扫描运行
  5. 将出现通知提示:

通知提示 6.当您按“是”时,系统将通过您的应用程序自动连接它,互联网将正常工作。请参阅以下内容:

连接到建议的网络

请注意以下事项:

  1. 如果您从 Wifi 设置断开网络(即按下下图中的断开连接 bin 图标),即使您删除了建议的网络wifiManager.removeNetworkSuggestions(listOf(it))并重新添加,您的网络也会被阻止 24 小时自动连接。即使您再次卸载并安装您的应用程序

已连接的 Wifi 详细信息

不幸的是,这是Android系统的加入限制描述在这里:

如果用户在连接到某个网络建议时使用 Wi-Fi 选择器明确断开与该网络建议的连接,则该网络将被列入黑名单 24 小时。在黑名单期间,该网络不会被考虑自动连接,即使应用程序删除并重新添加与该网络对应的网络建议。

  1. 如果您在连接到建议的 WiFi 时卸载该应用程序,系统将自动关闭连接。
  2. 如果您有多个建议,您可以使用此处WifiNetworkSuggestion.Builder().setPriority(<Priority Integer>)提到的方法优先考虑它们:

指定该网络在同一应用提供的其他网络建议中的优先级(优先级对不同应用的建议没有影响)。数字越大,优先级越高(即值 0 = 最低优先级)。

  1. 如果您在通知提示中按“否”,您可以(Settings > Apps & notifications > Special App access > Wi-Fi Control > App name)按照此处所述进行更改:

拒绝网络建议通知的用户会从应用程序中删除 CHANGE_WIFI_STATE 权限。用户可以稍后通过进入 Wi-Fi 控制菜单(设置 > 应用程序和通知 > 特殊应用程序访问 > Wi-Fi 控制 > 应用程序名称)来授予此批准。


BVa*_*tur 5

看起来他们在 Android 11(API 30)中添加了支持,用于添加在应用程序范围之外持续存在的网络配置,并保存为系统网络配置,就像使用已弃用的 WiFiManager 方法addNetwork所做的那样。您需要做的就是使用ACTION_WIFI_ADD_NETWORKS显示一个系统对话框,询问用户是否要继续向系统添加新的 Wifi 建议。这就是我们启动该对话框的方式:

// used imports
import android.provider.Settings.ACTION_WIFI_ADD_NETWORKS
import android.provider.Settings.EXTRA_WIFI_NETWORK_LIST
import android.app.Activity
import android.content.Intent
import android.net.wifi.WifiNetworkSuggestion





// show system dialog for adding new network configuration
    val wifiSuggestionBuilder = WifiNetworkSuggestion.Builder()
                .setSsid("network SSID")
                .build()

    val suggestionsList = arraylistOf(wifiSuggestionBuilder)
    val intent = new Intent(ACTION_WIFI_ADD_NETWORKS)
    intent.putParcelableArrayListExtra(EXTRA_WIFI_NETWORK_LIST, suggestionsList);
    activity.startActivityForResult(intent, 1000)
Run Code Online (Sandbox Code Playgroud)

该对话框如下所示:

然后我们只需要在onActivityResult这样的方法中处理结果:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == 1000) {
        if (resultCode == Activity.RESULT_OK) {
            // network succesfully added - User pressed Save
        } else if (resultCode == Activity.RESULT_CANCELED) {
            // failed attempt of adding network to system - User pressed Cancel
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我在安装了较旧 Android 版本(低于 API30)的 Android 设备上测试此代码时,每次我希望它显示用于添加新网络配置的对话框时,我都会崩溃。这是崩溃的情况:

java.lang.RuntimeException: Unable to start activity: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.settings.WIFI_ADD_NETWORKS (has extras) }
Run Code Online (Sandbox Code Playgroud)

看起来新方法并不是开箱即用的。因此,对于 API30,我们可以使用新的 Intent 操作,对于 API 28 及以下版本,我们仍然可以使用添加网络的旧方法,但对于 API29,我们有某种灰色区域,我还无法找到好的解决方案。如果有人知道还能做什么,请与我分享。;)

  • 谢谢。关于为什么它在 API 29 上不起作用,这是因为 ACTION_WIFI_ADD_NETWORKS 来自 API 30 :https://developer.android.com/reference/android/provider/Settings#ACTION_WIFI_ADD_NETWORKS (2认同)

Seb*_*zer 4

我希望我能回答您所有的问题,因为我目前正在努力解决类似的问题。

经过几个小时后,我终于能够使用以下方法连接到所需的网络:

val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
    .setSsid(ssid)
    .setWpa2Passphrase(passphrase)
    .setBssid(mac)
    .build()

val networkRequest = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .setNetworkSpecifier(wifiNetworkSpecifier)
    .build()

val connectivityManager = applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?

connectivityManager?.requestNetwork(networkRequest, ConnectivityManager.NetworkCallback())
Run Code Online (Sandbox Code Playgroud)

您可以通过 接收大量事件ConnectivityManager.NetworkCallback()。

  • 与 WiFi 建议 API 不同,上面提到的 API 是为了连接到不提供互联网连接的网络(例如 chromecast 或相机等外部设备)而创建的。使用上述 API,用户将收到一个包含所选 SSID 的弹出窗口,以便他可以确认连接到它。用户将连接到该网络,但该连接仅在应用程序内部可用(它在 Chrome 等外部浏览器中不起作用)。 (2认同)