Android Wifi-API 在 Android 10+ 上真的如此糟糕吗?

rek*_*ire 5 android wifi

我正在开发 Wifi 自动连接功能,但令我震惊的是该 API 的损坏程度。

我现在正在使用 5 个不同的 API,但我仍然没有以用户期望的方式得到它。

我有一个设置可以在 Android 10+ 上启用 wifi 自动连接,我将尝试以下操作:

  1. 检查我是否持有以下ACCESS_WIFI_STATE权限:
    appOpsManager.unsafeCheckOp("android:change_wifi_state", Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED
    
    Run Code Online (Sandbox Code Playgroud) 当我拥有许可时,我会继续执行 2。如果没有,我会继续执行 6。
  2. 当我持有权限时,我将检查 Android 11+ 上一次运行时是否保存了我的 wifi 建议(wifiManager.networkSuggestions.isNotEmpty()如果是这样的话)我检查我当前连接的 Wifi,请参阅步骤 x。在较低级别我会跳过此步骤并转到步骤 3
  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
    
    Run Code Online (Sandbox Code Playgroud)
  4. 当用户接受我的建议时,到目前为止我还不错。我无法在 Android 10 上验证我的建议是否被接受。在 Android 11 上这是可能的(请参阅步骤 2)。但我仍然不知道设备是否真的连接了wifi。所以我转到第 7 步
  5. 当用户拒绝我的建议时,我几乎退出游戏,我再也不能询问用户了(从技术上讲,有一个很好的隐藏功能,您可以在其中切换权限,但没有用户会找到它)。在 Android 10 上,我可以检查是否连接了正确的 wifi,至少理论上如此(请参阅步骤 7)。
  6. 在 Android 11+ 上,我可以回退到Settings.ACTION_WIFI_ADD_NETWORKS始终可以添加 Wifi 的意图(缺点是用户可以共享 wifi 密码)
  7. 我需要验证之前的步骤是否有效以及用户是否确实连接到所需的 wifi。为此,我已经拥有ACCESS_WIFI_STATEACCESS_NETWORK_STATEACCESS_COARSE_LOCATION的权限ACCESS_FINE_LOCATION。然而ConnectivityManagerAPI 并没有返回实际的SSID,这让我发疯。
  8. 如果用户没有连接到正确的 wifi,我会尝试使用该Settings.Panel.ACTION_WIFI操作让用户连接到正确的 wifi

总结一下:

  • 我使用WifiNetworkSuggestionAPI
  • 我回退到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
        }
Run Code Online (Sandbox Code Playgroud)

基于在 Android 12 中无法使用 onCapativityChanged 获取 WIFI SSID,我认为不支持我访问该值的方式。我目前得到的值"<unknown ssid>"

rek*_*ire 4

嗯,只是一半的答案,但无论如何它可能会有所帮助。以下是我获取用户当前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)
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

所以基本上你的代码的各个方面都需要检查 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)