Android Wifi-API 在 Android 10+ 上真的那么坏吗?
Is the Android Wifi-API really so broken on Android 10+?
我正在研究 Wifi 自动连接功能,我很震惊 API 是多么糟糕。
我现在使用了 5 种不同的 API,但我仍然没有以用户期望的方式获得它。
我有一个设置可以在 Android 10+ 上启用 wifi 自动连接我会试试这个:
- 检查我是否持有
ACCESS_WIFI_STATE
权限:
appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
当我拥有权限时,我继续 2。如果没有,我继续 6。
- 当我获得许可后,我会检查 Android 11+ 是否保存了之前的 运行 我的 wifi 建议
wifiManager.networkSuggestions.isNotEmpty()
如果是,我会检查我使用的是哪个 Wifi ' 当前连接见第 x 步。在较低级别我跳过这个并转到步骤 3
- 我将 wifi 建议 API 与
WifiNetworkSuggestion.Builder()
一起使用,并建议用户使用我的 wifi
val status = wifiManager.addNetworkSuggestions(listOf(suggestion))
// Strage bug: On first usage the return value is always SUCCESS
val success = status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
- 当用户接受我的建议时,我到目前为止都很好。我无法在 Android 10 上验证我的建议是否被接受。在 Android 11 这是可能的(见步骤 2)。但是我仍然不知道设备是否真的连接了 wifi。所以我转到第 7 步
- 当用户拒绝了我的建议时,我就快退出游戏了,我再也不能问用户了(从技术上讲,有一个隐藏得很好的功能,您可以在其中切换权限,但没有用户会发现它) .在 Android 10 上,我可以检查我是否连接了正确的 wifi,至少在理论上是这样(请参阅第 7 步)。
- 在 Android 11+ 我可以回退到
Settings.ACTION_WIFI_ADD_NETWORKS
意图,它总是可以添加 Wifi(缺点是用户可以共享 wifi 密码)
- 我需要验证之前的步骤是否有效以及用户是否确实连接到所需的 wifi。为此,我已经拥有权限
ACCESS_WIFI_STATE
、ACCESS_NETWORK_STATE
、ACCESS_COARSE_LOCATION
和 ACCESS_FINE_LOCATION
。然而 ConnectivityManager
API 不 return 实际的 SSID
,这让我发疯。
- 如果用户没有连接到正确的 wifi 我会尝试使用
Settings.Panel.ACTION_WIFI
操作让用户连接到正确的 wifi
总结一下:
- 我用的是
WifiNetworkSuggestion
API
- 我尽可能回退到
Settings.ACTION_WIFI_ADD_NETWORKS
- 我尝试验证用户当前是否连接到正确的 wifi
- 我尝试通过
Settings.Panel.ACTION_WIFI
操作帮助用户连接到正确的 wifi(甚至打开 wifi)
真的这么乱还是有更简单的方法?
我目前正在这样访问 SSID:
private val currentSsid: String?
get() =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val wifiInfo = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.transportInfo as? WifiInfo
wifiInfo?.ssid
} else {
wifiManager.connectionInfo?.ssid
}
基于 Unable to get WIFI SSID using onCapabilitiesChanged in Android 12 我认为不支持我访问该值的方式。我目前得到的值是 "<unknown ssid>"
.
好吧,只回答了一半,但无论如何它可能会有帮助。下面是我获取用户当前SSID的方法(需要持有定位权限):
fun updateSsid(networkCapabilities: NetworkCapabilities) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
currentSsid = (networkCapabilities.transportInfo as? WifiInfo)?.ssid?.trim('"')
}
}
wifiCallback = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
object: ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
updateSsid(networkCapabilities)
}
}
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
object: ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
updateSsid(networkCapabilities)
}
}
}
else -> null
}
wifiCallback?.let {
fragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
connectivityManager.registerNetworkCallback(request, it)
}
override fun onPause(owner: LifecycleOwner) {
connectivityManager.unregisterNetworkCallback(it)
}
})
}
所以基本上,您的代码的某些方面需要检查 api 的级别 <10、10、11 和 12。真是一团糟。
如果您希望用户选择配置的 wifi,这可能非常方便:
fun showWifiDialog() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
try {
fragment.startActivity(Intent(android.provider.Settings.Panel.ACTION_WIFI))
} catch (e: Exception) {
// ignored
}
}
}
我正在研究 Wifi 自动连接功能,我很震惊 API 是多么糟糕。
我现在使用了 5 种不同的 API,但我仍然没有以用户期望的方式获得它。
我有一个设置可以在 Android 10+ 上启用 wifi 自动连接我会试试这个:
- 检查我是否持有
ACCESS_WIFI_STATE
权限:
当我拥有权限时,我继续 2。如果没有,我继续 6。appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
- 当我获得许可后,我会检查 Android 11+ 是否保存了之前的 运行 我的 wifi 建议
wifiManager.networkSuggestions.isNotEmpty()
如果是,我会检查我使用的是哪个 Wifi ' 当前连接见第 x 步。在较低级别我跳过这个并转到步骤 3 - 我将 wifi 建议 API 与
WifiNetworkSuggestion.Builder()
一起使用,并建议用户使用我的 wifival status = wifiManager.addNetworkSuggestions(listOf(suggestion)) // Strage bug: On first usage the return value is always SUCCESS val success = status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS
- 当用户接受我的建议时,我到目前为止都很好。我无法在 Android 10 上验证我的建议是否被接受。在 Android 11 这是可能的(见步骤 2)。但是我仍然不知道设备是否真的连接了 wifi。所以我转到第 7 步
- 当用户拒绝了我的建议时,我就快退出游戏了,我再也不能问用户了(从技术上讲,有一个隐藏得很好的功能,您可以在其中切换权限,但没有用户会发现它) .在 Android 10 上,我可以检查我是否连接了正确的 wifi,至少在理论上是这样(请参阅第 7 步)。
- 在 Android 11+ 我可以回退到
Settings.ACTION_WIFI_ADD_NETWORKS
意图,它总是可以添加 Wifi(缺点是用户可以共享 wifi 密码) - 我需要验证之前的步骤是否有效以及用户是否确实连接到所需的 wifi。为此,我已经拥有权限
ACCESS_WIFI_STATE
、ACCESS_NETWORK_STATE
、ACCESS_COARSE_LOCATION
和ACCESS_FINE_LOCATION
。然而ConnectivityManager
API 不 return 实际的SSID
,这让我发疯。 - 如果用户没有连接到正确的 wifi 我会尝试使用
Settings.Panel.ACTION_WIFI
操作让用户连接到正确的 wifi
总结一下:
- 我用的是
WifiNetworkSuggestion
API - 我尽可能回退到
Settings.ACTION_WIFI_ADD_NETWORKS
- 我尝试验证用户当前是否连接到正确的 wifi
- 我尝试通过
Settings.Panel.ACTION_WIFI
操作帮助用户连接到正确的 wifi(甚至打开 wifi)
真的这么乱还是有更简单的方法?
我目前正在这样访问 SSID:
private val currentSsid: String?
get() =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val wifiInfo = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.transportInfo as? WifiInfo
wifiInfo?.ssid
} else {
wifiManager.connectionInfo?.ssid
}
基于 Unable to get WIFI SSID using onCapabilitiesChanged in Android 12 我认为不支持我访问该值的方式。我目前得到的值是 "<unknown ssid>"
.
好吧,只回答了一半,但无论如何它可能会有帮助。下面是我获取用户当前SSID的方法(需要持有定位权限):
fun updateSsid(networkCapabilities: NetworkCapabilities) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
currentSsid = (networkCapabilities.transportInfo as? WifiInfo)?.ssid?.trim('"')
}
}
wifiCallback = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
object: ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
updateSsid(networkCapabilities)
}
}
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
object: ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
updateSsid(networkCapabilities)
}
}
}
else -> null
}
wifiCallback?.let {
fragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
connectivityManager.registerNetworkCallback(request, it)
}
override fun onPause(owner: LifecycleOwner) {
connectivityManager.unregisterNetworkCallback(it)
}
})
}
所以基本上,您的代码的某些方面需要检查 api 的级别 <10、10、11 和 12。真是一团糟。
如果您希望用户选择配置的 wifi,这可能非常方便:
fun showWifiDialog() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
try {
fragment.startActivity(Intent(android.provider.Settings.Panel.ACTION_WIFI))
} catch (e: Exception) {
// ignored
}
}
}