【问题标题】:How do I keep Android connected to an IoT WiFi AP with no internet access when an internet-enabled WiFi network is available?当支持 Internet 的 WiFi 网络可用时,如何让 Android 连接到无法访问 Internet 的 IoT WiFi AP?
【发布时间】:2020-06-09 07:12:56
【问题描述】:

我正在开发一个基于 Raspberry Pi 的物联网设备,该设备拥有自己的 WiFi AP(无互联网),并已成功按照this Android Developers blog post from 2016 连接到它,并将流量从我的 Android 应用程序路由到它,即使移动数据是启用(即通过Network#getSocketFactory)。 (即我没有在这个问题中报告问题:Send request over WiFi (without connection) even if Mobile data is ON (with connection) on Android M

现在的问题是,我的 Android 10 设备(Google Pixel)会在几分钟后自动断开网络连接并切换到我的家庭 WiFi 网络(有互联网)。这是在前台应用程序,通过一个活动的 Web 套接字连接到在 Pi 上运行的服务器端应用程序。

可以通过侦听应用程序中的网络状态变化并通过WifiManager#enableNetwork 强制重新连接到我的 IoT 网络来解决此问题,但这似乎是一个 hacky 解决方案,连接仍然是中断,导致用户体验不佳。

我的另一个想法是使用WifiManager#disableNetwork 禁用所有其他配置的 WiFi 网络,从而阻止手机连接到它们。但是文档声明不允许禁用由其他应用创建的网络。

在没有网络访问的情况下保持与物联网 WiFi 网络的连接似乎是 Google 已经(或曾经)知道的 Android 应用的合理用例,但我正在努力拼凑当前的最佳实践,以了解如何在 2020 年做到这一点。我想知道是否可以通过较新的 WiFi suggestion APIs 来实现。然而,这些听起来对应用程序开发人员来说更加严格,并且不提供任何关于实际加入的 WiFi 网络的保证。

【问题讨论】:

    标签: android raspberry-pi wifi iot


    【解决方案1】:

    您可以将 Android 绑定到它所连接的 WiFi 接入点。

    这可以使用ConnectivityManagerbindProcessToNetwork(network)来完成:

    final ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    
    NetworkRequest.Builder builder = new NetworkRequest.Builder();
    
    //set the transport type to WIFI
    builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
    
    try {
        manager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
    
                    @Override
                    public void onAvailable(Network network) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            manager.bindProcessToNetwork(network);
                        } else {
                            ConnectivityManager.setProcessDefaultNetwork(network);
                        }
                        manager.unregisterNetworkCallback(this);
                    }
                });
    
    } catch (SecurityException e) {
        Log.e(TAG, e.getMessage());
    }
    

    这也将阻止 Android 将当前连接从没有互联网的 WiFi AP 切换到移动数据

    【讨论】:

    • 我转而调用bindProcessToNetwork,而不是按照建议使用网络的套接字工厂。不幸的是,结果是一样的 - 即使打开移动数据,它也可以正常连接,但 Android 仍然会在不到一分钟后关闭它并返回家庭 wifi 网络
    • 您已经发布了基于使用 bindProcessToNetwork() 的答案,所以我想我的解决方案对您有所帮助?
    【解决方案2】:

    找到它的底部。适用于 Android 10 的解决方案是:https://stackoverflow.com/a/58770341/1405990

    即使用WifiNetworkSpecifierConnectivityManager#requestNetwork

            val builder: NetworkRequest.Builder = NetworkRequest.Builder()
            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            builder.setNetworkSpecifier(
                WifiNetworkSpecifier.Builder().apply {
                    setSsid("IOTWifi")
                    setWpa2Passphrase("iotwifipassword")
                }.build()
            )
    
            try {
                connectivityManager.requestNetwork(builder.build(), object : NetworkCallback() {
                    override fun onAvailable(network: Network) {
                        connectivityManager.bindProcessToNetwork(network)
                    }
                })
            } catch (e: SecurityException) {
                Timber.e(e)
            }
    

    这将显示一个系统对话框,用户可以(最终)从中选择要连接的 IoT wifi 网络。

    让 Android 保持与网络的连接的关键是不要取消注册来自 ConnectivityManager 的网络回调。在您这样做之前,Android 10 不会自动切换回具有互联网访问权限的版本。

    用户体验不是很好,因为对话框标题不太清楚,而且显示匹配的 WiFi 网络时出现莫名其妙的延迟(在旧扫描结果中已经可见)。但至少现在可以与 Android 10 上的 IoT 设备建立持久连接。

    【讨论】:

      猜你喜欢
      • 2019-06-09
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 2015-05-20
      • 2014-04-19
      • 2015-12-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多