我注意到在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(列表)。
这是我当前的代码,适用于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网络详细信息),它说成功了,但是在OS的Wifi设置上什么也没有发生。使用我添加的密码,该网络不存在。所以我真的不知道它做了什么...
几秒钟后,我注意到一条通知,询问我是否可以连接到该应用程序建议的网络:
但是当我选择接受时,它还是没有做任何事情。
我尝试制作另一个POC,以为我可能做错了,但后来它甚至没有显示通知。由于我认为整个行为都是错误,因此我已经here对此进行了报道。
不仅如此,而且我发现,如果确实应该以一种或另一种方式添加网络,则它仍然存在一些严重的限制,例如最大添加的网络(here)以及已被删除卸载应用程序(here)
如何正确处理Android Q?真的没有API可以添加网络了吗?
如果WifiNetworkSuggestion
与添加网络无关,那么它到底是用来做什么的?
由于我对添加网络的窍门不熟悉,因此我的代码关于添加网络的所有可能方式是否正确?我之所以这样问,是因为有人写了here,人们应该启用Wifi并确保pingSupplicant
返回true。是真的吗还是仅致电addNetwork
就足够了?
如果现在无法使用常规API添加网络,那么是否有可能通过使用有根设备代替解决方案?也许一些adb命令?
答案 0 :(得分:5)
我坚持同样的问题,但是以某种方式达到了连接所需网络的可重现状态,并且我想分享我的发现可能会有所帮助。
摘要:
您必须先禁用所有自动连接,然后再应用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")
}
}
步骤如下:
6.当您按“是”时,系统将通过您的应用程序自动与其连接,并且互联网将正常工作。请参阅以下内容:
请注意以下几点:
wifiManager.removeNetworkSuggestions(listOf(it))
删除了建议的网络并添加了网络,您的网络也将被禁止自动连接24小时再次。而且,即使您再次卸载并安装了应用,也可以不幸的是,这是Android系统根据here所述添加的限制:
如果用户使用Wi-Fi选择器连接到其中一个网络建议时明确断开连接,则该网络将被列入黑名单24小时。在黑名单期间,即使该应用删除并重新添加了与该网络相对应的网络建议,该网络也不会被视为自动连接。
WifiNetworkSuggestion.Builder().setPriority(<Priority Integer>)
来优先处理它们:在同一应用程序提供的其他网络建议中指定此网络的优先级(优先级对不同应用程序的建议没有影响)。数字越大,优先级越高(即0值=最低优先级)。
(Settings > Apps & notifications > Special App access > Wi-Fi Control > App name)
进行更改:拒绝网络建议通知的用户会从应用中删除CHANGE_WIFI_STATE权限。用户可以稍后通过进入Wi-Fi控制菜单(设置>应用和通知>特殊应用访问> Wi-Fi控制>应用名称)来授予此批准。
答案 1 :(得分:2)
希望我能回答您所有的问题,因为我目前正努力解决类似的问题。
几个小时后,我终于可以使用这种方法连接到所需的网络:
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()
接收到很多事件。
答案 2 :(得分:1)
好像他们已经在Android 11(API 30)中添加了对添加网络配置的支持,该配置保留在应用程序范围之外,并保存为系统网络配置,就像使用不推荐使用的WiFiManager方法{{3} }。您需要做的就是使用addNetwork来显示一个系统对话框,询问用户是否要继续向系统添加新的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,我们有一些灰色区域,我尚无法找到好的解决方案。如果有人有其他想法,请与我分享。 ;)
答案 3 :(得分:0)
@ 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());