是否可以在 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(<Priority Integer>)
对它们进行优先排序,如here 所述:
在同一应用提供的其他网络建议中指定此网络的优先级(优先级对不同应用的建议没有影响)。数字越大,优先级越高(即值 0 = 最低优先级)。
-
如果您在通知提示中按“否”,您可以按照here 的说明从
(Settings > Apps & notifications > Special App access > Wi-Fi Control > 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 上添加网络配置?的主要内容,如果未能解决你的问题,请参考以下文章