当有可用的互联网WiFi网络时,我如何让Android设备连接到没有互联网访问权限的物联网WiFi接入点?

3
我正在开发一个基于Raspberry Pi的物联网设备,它托管自己的WiFi AP(没有互联网),并已成功地遵循2016年的这篇Android开发者博客文章,从我的Android应用程序连接到它并路由流量到它,即使移动数据已启用(即通过Network#getSocketFactory)。 (即,我没有遇到在这个问题中报告的问题:在Android M上,即使移动数据已连接,也可以通过WiFi发送请求(无连接)
现在的问题是,我的Android 10设备(Google Pixel)在几分钟后会自动断开与网络的连接并切换到我的家庭WiFi网络(有互联网)。 这是在应用程序前台时,与运行在Pi上的服务器端应用程序保持活动Web套接字连接。
可以通过在应用程序中侦听网络状态更改并通过WifiManager#enableNetwork强制重新连接到我的IoT网络来解决问题,但这似乎是一个hacky的解决方案,连接仍然会中断,导致用户体验差。
我另一个想法是使用WifiManager#disableNetwork禁用所有其他配置的WiFi网络,从而防止手机连接到它们。 但是文档指出,禁用其他应用程序创建的网络是不允许的。
在没有网络访问的IoT WiFi网络上保持连接似乎是Android应用程序的合理用例,Google已经意识到这一点,但我正在努力整合2020年如何做到这一点的最佳实践。 我想知道是否可以通过较新的WiFi建议API来实现。 但是,这些听起来对应用程序开发人员更加限制,并且不提供有关实际加入的WiFi网络的任何保证。
2个回答

0
找到了答案。对于Android 10,对我有效的解决方案是这个:https://dev59.com/r1MH5IYBdhLWcg3wqg9V#58770341 即使用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设备的持久连接。


0

你可以将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());
}

这样做还可以防止安卓系统在当前连接的WiFi热点没有互联网时自动切换到移动数据网络。

我改用了调用bindProcessToNetwork而不是使用网络的socket工厂,正如建议的那样。不幸的是,结果还是一样的 - 即使在移动数据开启的情况下,它仍然可以连接成功,但安卓系统仍会在不到一分钟后切换回家庭WiFi网络。 - user1405990
嗯,你根据使用bindProcessToNetwork()发布了一个答案,所以我猜我的解决方案对你有帮助? - matdev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接