当支持 Internet 的 WiFi 网络可用时,如何在没有 Internet 访问的情况下保持 Android 连接到 IoT WiFi AP?
How do I keep Android connected to an IoT WiFi AP with no internet access when an internet-enabled WiFi network is available?
我正在开发一个基于 Raspberry Pi 的物联网设备,该设备托管自己的 WiFi AP(无互联网)并且已成功遵循 this Android Developers blog post from 2016 to connect to it and route traffic to it from my Android app, even when mobile data is enabled (i.e. via Network#getSocketFactory
). (i.e. I'm NOT having the issue reported in this question: )
现在的问题是我的 Android 10 设备(一个 Google Pixel)在几分钟后自动断开网络连接并切换到我的家庭 WiFi 网络(有互联网)。这是在前台的应用程序,与 Pi 上的服务器端应用程序 运行 的活动网络套接字连接。
我 可以 通过侦听应用程序中的网络状态变化并通过 WifiManager#enableNetwork
强制重新连接到我的物联网网络来解决这个问题,但这似乎是一个 hacky解决方案,连接仍然会中断,导致用户体验不佳。
我的另一个想法是使用 WifiManager#disableNetwork
禁用所有其他已配置的 WiFi 网络,从而阻止 phone 连接到它们。但是文档指出不允许禁用其他应用程序创建的网络。
在没有网络访问权限的情况下保持与物联网 WiFi 网络的连接似乎是 Android 应用程序的合理用例,Google 已经(或曾经)知道,但我努力拼凑当前的最佳实践,以便在 2020 年做到这一点。我想知道是否可以通过更新的 WiFi suggestion APIs 来实现。然而,这些听起来对应用程序开发人员的限制更大,并且不对实际加入的 WiFi 网络提供任何保证。
您可以将 Android 绑定到它所连接的 WiFi 接入点。
这可以使用 ConnectivityManager
的 bindProcessToNetwork(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 切换到移动数据
追根究底。 Android 10 对我有用的解决方案是这个:https://whosebug.com/a/58770341/1405990
即使用 WifiNetworkSpecifier
和 ConnectivityManager#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)
}
这将显示一个系统对话框,用户可以从中(最终)select IoT wifi 网络连接到它。
Android 保持网络连接的关键是不要从 ConnectivityManager
注销网络回调。 Android 在您这样做之前,10 不会自动切换回可以访问互联网的设备。
用户体验不是很好,因为对话框标题不太清楚,而且在显示匹配的 WiFi 网络时出现莫名其妙的延迟(这在旧扫描结果中已经可见)。但至少现在可以与 Android 10 上的物联网设备建立持久连接。
我正在开发一个基于 Raspberry Pi 的物联网设备,该设备托管自己的 WiFi AP(无互联网)并且已成功遵循 this Android Developers blog post from 2016 to connect to it and route traffic to it from my Android app, even when mobile data is enabled (i.e. via Network#getSocketFactory
). (i.e. I'm NOT having the issue reported in this question:
现在的问题是我的 Android 10 设备(一个 Google Pixel)在几分钟后自动断开网络连接并切换到我的家庭 WiFi 网络(有互联网)。这是在前台的应用程序,与 Pi 上的服务器端应用程序 运行 的活动网络套接字连接。
我 可以 通过侦听应用程序中的网络状态变化并通过 WifiManager#enableNetwork
强制重新连接到我的物联网网络来解决这个问题,但这似乎是一个 hacky解决方案,连接仍然会中断,导致用户体验不佳。
我的另一个想法是使用 WifiManager#disableNetwork
禁用所有其他已配置的 WiFi 网络,从而阻止 phone 连接到它们。但是文档指出不允许禁用其他应用程序创建的网络。
在没有网络访问权限的情况下保持与物联网 WiFi 网络的连接似乎是 Android 应用程序的合理用例,Google 已经(或曾经)知道,但我努力拼凑当前的最佳实践,以便在 2020 年做到这一点。我想知道是否可以通过更新的 WiFi suggestion APIs 来实现。然而,这些听起来对应用程序开发人员的限制更大,并且不对实际加入的 WiFi 网络提供任何保证。
您可以将 Android 绑定到它所连接的 WiFi 接入点。
这可以使用 ConnectivityManager
的 bindProcessToNetwork(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 切换到移动数据
追根究底。 Android 10 对我有用的解决方案是这个:https://whosebug.com/a/58770341/1405990
即使用 WifiNetworkSpecifier
和 ConnectivityManager#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)
}
这将显示一个系统对话框,用户可以从中(最终)select IoT wifi 网络连接到它。
Android 保持网络连接的关键是不要从 ConnectivityManager
注销网络回调。 Android 在您这样做之前,10 不会自动切换回可以访问互联网的设备。
用户体验不是很好,因为对话框标题不太清楚,而且在显示匹配的 WiFi 网络时出现莫名其妙的延迟(这在旧扫描结果中已经可见)。但至少现在可以与 Android 10 上的物联网设备建立持久连接。