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

Posted

技术标签:

【中文标题】是否可以在 Android Q 上添加网络配置?【英文标题】:Is it possible to add a network configuration on Android Q? 【发布时间】:2019-11-16 06:13:03 【问题描述】:

背景

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

问题

我找不到太多关于如何做这样的事情的信息。我在 *** 上看到过各种示例,如果我以 android API 28(或更低版本)为目标,我确实成功地使它添加了网络,甚至连接到它。

但是,当面向 Android 29 (Android Q) 时,它无法添加网络。

我发现了什么

由于我正在使用 Android Q beta 4 尝试 Pixel 2,我认为这可能是因为 addNetwork 已被弃用,所以文档甚至这么说,如果我以 Android Q 为目标,它将无法工作,实际上它不起作用:

兼容性说明:适用于面向 Build.VERSION_CODES.Q 的应用程序 或以上,此 API 将始终返回 -1。

在Android Q(不包括)之前它似乎应该工作的方式是准备WifiConfiguration并添加它。以后如果我愿意,我也可以连接到它。在 Android Q 上,它似乎被WifiNetworkSuggestion 取代,但似乎根本不是要添加网络:

Network Suggestion 对象用于为以下用户提供 Wi-Fi 网络 自动连接到网络时的考虑。应用程序不能直接 创建这个对象,他们必须使用 WifiNetworkSuggestion.Builder#build() 获取此实例 对象。

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

这是我当前的代码,适用于 pre-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")
    

似乎只需要这些权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

但无论如何,只要您不以 Android Q (API 29) 及更高版本为目标,这将有效。当你瞄准它时,我确实总是得到“-1”,这意味着它失败了。

我还在问题跟踪器上发现了一个问题(here,我写了关于它here),告诉有人需要返回 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")

运行时(在让操作系统忘记它之后,我给了它我的 Wifi 网络详细信息),它说它成功了,但操作系统的 Wifi 设置上没有发生任何事情。使用我添加的密码的网络不存在。所以我真的不明白它做了什么......

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

但是当我选择接受时,它什么也没做,和以前一样。

我尝试制作另一个 POC,以为我可能做错了,但后来它甚至没有显示通知。由于我认为这整个行为是一个错误,我已经报告了它here

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

问题

    究竟应该如何处理Android Q?真的没有API来添加网络了吗?

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

    由于我对添加网络的花絮不够熟悉,我的代码对于添加网络的所有可能方式是否正确?我问这个是因为有人写了here 说人们应该启用 Wifi 并确保pingSupplicant 返回 true。这是真的吗?还是打电话给addNetwork就够了?

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


编辑:不确定如何正式执行,但使用 adb,您 might be able 在 Android 11 上添加 Wifi-networks 。需要检查adb shell cmd wifi help

【问题讨论】:

这个有什么更新吗?我遇到了同样的问题,并且我看到一些针对 API 29 的应用程序连接到其 wifi 配置而没有此类通知/提示。 @AswinPAshok 根据我的阅读,Google 计划在 Android R 上为这个 API 提供更多的灵活性。可能允许将其设置为永久(在应用删除后保留)。 你能看一下这张图片吗:imgur.com/cdv3fHR,在这个提示之后,一些应用可以连接到他们的wifi配置。这个意图可能是什么?对不起,我很愚蠢。 @AswinPAshok 我不知道。我建议提出一个新问题。我只是出于好奇而测试了这个 API,因为我想在第三方应用程序上拥有这个功能:) @androiddeveloper 如何设置代理选项,例如主机名和代理端口?和 IP 设置? 【参考方案1】:

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

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

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())

您可以通过ConnectivityManager.NetworkCallback() 接收大量活动。

【讨论】:

等等,这个 API 是什么?这和旧的一样吗?这是没有限制的吗?没有“建议”?它会永远添加网络吗?删除后还保留吗? 这是 Android Q (10) 中引入的 API。据我所知,此连接持续存在,而 NetworkCallback 未被删除。网络未保存在网络配置中。 所以它和我找到的 API 差不多,不是吗?删除应用程序时它会被删除吗?这和我发现的有什么区别?它是否要求用户添加它? 与 WiFi 建议 API 不同,上述 API 是为连接到不提供互联网连接的网络(例如 chromecast 或相机等外部设备)而创建的。使用上述 API,用户将收到一个带有所选 SSID 的弹出窗口,以便他确认连接到它。用户将连接到该网络,但该连接仅在应用程序内部可用(它在 Chrome 等外部浏览器中不起作用)。 @SebastianHelzer 您能否确认 Mohru 的评论,即互联网不适用于您通过 WifiNetworkSpecifier 方法建立的连接?我认为连接也仅限于您自己的应用程序,因此其他应用程序将无法使用它。【参考方案2】:

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

总结一下: 在应用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")
    

以下是步骤:

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

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

请注意以下几点:

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

不幸的是,这是Android系统添加的限制,如here所述:

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

    如果您在连接到建议的 WiFi 时卸载应用程序,系统将自动关闭连接。 如果您有多个建议,您可以使用WifiNetworkSuggestion.Builder().setPriority(&lt;Priority Integer&gt;) 对它们进行优先排序,如here 所述:

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

    如果您在通知提示中按“否”,您可以按照here 的说明从(Settings &gt; Apps &amp; notifications &gt; Special App access &gt; Wi-Fi Control &gt; App name) 更改它:

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

【讨论】:

感谢分享答案,它真的很有帮助。但是我陷入了一种方式,即 removeNetworkSuggestions 方法并没有真正断开我与使用 networkSuggestion 连接的 wifi 的连接。只有卸载该应用程序才能使我与 wifi 断开连接。还有其他方法可以断开连接吗?【参考方案3】:

@Sebastian Helzer 的回答对我有用。我在我的应用程序中使用 java。这可能对 java 用户有所帮助...

WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier.Builder()
                .setSsid(ssid)
                .setWpa2Passphrase(password)
                .build();
NetworkRequest networkRequest = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setNetworkSpecifier(wifiNetworkSpecifier)
                .build();
ConnectivityManager connectivityManager = (ConnectivityManager)this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback());

【讨论】:

您是否成功连接了所需的网络?互联网连接怎么样?有效吗? 成功连接到所需网络,但未建立互联网连接。 @AmanullahAsraf 使用您的方法建立互联网连接是否幸运,即使只是为您的应用程序?【参考方案4】:

看起来他们已经在 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)

对话框如下所示:

然后我们只需要像这样在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
        
    

但是,当我在安装了较旧 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) 

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

【讨论】:

谢谢。关于为什么它不适用于 API 29,这是因为 ACTION_WIFI_ADD_NETWORKS 来自 API 30:developer.android.com/reference/android/provider/…

以上是关于是否可以在 Android Q 上添加网络配置?的主要内容,如果未能解决你的问题,请参考以下文章

安卓模拟器连接网络了用不了网

IOS与Android弱网环境测试

为啥FTP不能正常连接?

安卓模拟器连接网络用不了网是怎么回事?

App弱网测试-QNET

在 Android 模拟器中激活网络位置提供程序?