Android,在连接到wifi且无法访问互联网的同时与移动数据进行通信

问题描述 投票:2回答:1

我有一个汽车伴侣应用程序,需要与wifi和移动数据网络进行通信。

我的车辆控制单元提供了一个无法访问互联网的wifi网络,该网络公开了我们可以从该应用调用的API服务。除此之外,我们还需要使用手机移动数据(3G / 4G)与可从互联网访问的另一个后端进行通信。

我立即注意到,某些android手机在没有互联网的情况下连接到wifi网络使用android设置菜单时,显示系统对话框,通知用户当前网络无法访问互联网。这里用户有两个选择:保持此wifi网络或断开连接并切换到另一个。

这里有一些例子:

Samsung J7 - Android 7.0

Motorola moto G7 power - Android 9.0

Xiaomi mi 9T - Android 10

Huawei p9 lite - Android 6.0

经过简短的分析,我了解到,如果用户单击“否”选项,则系统会与当前的wifi网络断开连接,并且如果有其他网络可用,请连接到该网络。

如果用户单击“是”选项,我们可以有两种不同的行为:

  1. 电话保持连接到wifi网络而无法访问Internet,并且所有应用程序都无法再与Internet通信,因为android尝试使用wifi接口。
  2. 电话保持连接到wifi网络而无法访问互联网,但android系统重新绑定了所有现有的套接字,以及将来将在moblie数据网络上打开的套接字(如果有sim卡,则为该套接字。)>
  3. 然后我尝试了同样的事情,但是使用程序化连接

。我的不同Android版本的示例代码:
fun connectToWifi(ssid: String, key: String) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        connectPost10(ssid, key)
    } else {
        connectPre10(ssid, key)
    }
}

@RequiresApi(Build.VERSION_CODES.O)
private fun connectPost10(ssid: String, wpa2Passphrase: String) {

    val specifier = WifiNetworkSpecifier.Builder()
            .setSsid(ssid)
            .setWpa2Passphrase(wpa2Passphrase)
            .build()

    val request = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .setNetworkSpecifier(specifier)
            .build()

    val networkCallback = object: ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            val networkSSID = wifiManager.connectionInfo.ssid
                .trim()
                .removeSurrounding("\"")

            if (networkSSID == "MY_NETWORK_WITHOUT_INTERNET_SSID") {
                // i'm connected here
            }
        }
    }

    connectivityManager.requestNetwork(request, networkCallback)
}

private fun connectPre10(ssid: String, key: String) {

    // setup wifi configuration
    val config = WifiConfiguration().apply {
        SSID = "\"$ssid\""
        preSharedKey = "\"$key\""
    }

    val networkId = wifiManager.addNetwork(config)

    wifiManager.disconnect() // disconnect from current (if connected)
    wifiManager.enableNetwork(networkId, true) // enable next attempt
    wifiManager.reconnect()
}

请注意,为了读取网络ssid android,需要ACCESS_FINE_LOCATION权限,并且GPS必须处于活动状态。

[我立即注意到,使用程序化连接后,本机弹出窗口不再显示,但是在许多设备上,连接后,Android禁用了移动数据连接。

我想系统会希望这种行为,并且由以下事实决定:Android比计量连接更喜欢wifi。我可以,但是在无线网络无法访问互联网的情况下会怎样?需要连接的其他应用程序停止工作,因为它们无法访问Internet。

我需要一种解决方案,允许我的应用程序通过wifi和4g进行通信,而又不会阻止其他应用程序正常工作。

我的最小SDK API级别为23(棉花糖),定位为29(Android 10)。

我设法通过保存来自连接管理器上注册的回调的网络来解决问题。

val connectivityManager by lazy {
    MyApplication.context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}

private val wifiNetworkCallback = object : ConnectivityManager.NetworkCallback() {
    // Called when the framework connects and has declared a new network ready for use.
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        listener?.onWifiConnected(network)
    }
    // Called when a network disconnects or otherwise no longer satisfies this request or callback.
    override fun onLost(network: Network) {
        super.onLost(network)
        listener?.onWifiDisconnected()
    }
}

private val mobileNetworkCallback = object : ConnectivityManager.NetworkCallback() {
    // Called when the framework connects and has declared a new network ready for use.
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        connectivityManager.bindProcessToNetwork(network)
        listener?.onMobileConnected(network)
    }

    // Called when a network disconnects or otherwise no longer satisfies this request or callback.
    override fun onLost(network: Network) {
        super.onLost(network)
        connectivityManager.bindProcessToNetwork(null)
        listener?.onMobileDisconnected()
    }
}

private fun setUpWifiNetworkCallback() {

    val request = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .build()

    try {
        connectivityManager.unregisterNetworkCallback(wifiNetworkCallback)
    } catch (e: Exception) {
        Log.d(TAG, "WiFi Network Callback was not registered or already unregistered")
    }

    connectivityManager.requestNetwork(request, wifiNetworkCallback)
}

private fun setUpMobileNetworkCallback() {

    val request = NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
        .build()

    try {
        connectivityManager.unregisterNetworkCallback(mobileNetworkCallback)
    } catch (e: Exception) {
        Log.d(TAG, "Mobile Data Network Callback was not registered or already unregistered")
    }

    connectivityManager.requestNetwork(request, mobileNetworkCallback)
}

标记此“ connectivityManager.bindProcessToNetwork()”,我们将在后面讨论。

随后我创建了两个不同的改造服务:

  1. 私有改造:绑定到我从wifi回调中收到的网络对象上,公开api以与本地网络中的车辆进行通信。
  2. 公共改造:绑定到我从移动数据回调接收到的网络对象上,公开api以与我的后端以及需要Internet的所有其他设备进行通信。
  3. 目前,在我的应用程序中,我可以重定向经过改造的流量,但是我包含在项目中的库如何理解它们应该使用哪个网络?答:他们不了解,实际上他们尝试使用wifi网络收到超时错误。

当我将google maps添加到我的应用程序时,我注意到了这一行为,画布仅显示一个空网格。由于无法通过我之前创建的公共改造服务来重定向Google地图流量,因此我不得不寻找另一种解决方案来解决此问题。

这里是您之前看到的ConnectivityManager.bindProcessToNetwork()!https://developer.android.com/reference/android/net/ConnectivityManager#bindProcessToNetwork(android.net.Network)

通过这种方法,我可以告诉我的应用程序,将来创建的所有套接字都必须使用来自移动数据回调的网络。

使用此技巧,谷歌地图和我无法控制其连接的所有其他图书馆,他们将使用数据连接与互联网通信,因此它们将正常工作。

[在某些手机中,尤其是旧版android,仍然存在其他应用程序无法连接的问题,因为它们尝试使用wifi而不是使用移动数据。作为用户,如果使用一个应用程序,其他所有应用程序都无法使用,我会感到非常沮丧。

因此,我想了解是否有一种方法可以满足我的所有要求,无论我的应用程序是哪个版本,无论Android版本和手机供应商如何,其他应用程序都可以正常工作。

总而言之,我的问题是:

  1. 如果以编程方式进行连接,为什么没有出现“无法访问Internet的网络”弹出窗口?
  2. 如果Android知道我的WiFi无法访问互联网,为什么其他应用程序不将移动数据网络自动用作后备?
  3. 是否可以告诉android其他应用程序必须使用某个网络才能打开将来的套接字?
  4. 每个供应商都有自定义的WiFi设置,以提供增强的Internet体验(Huawei WiFi+Samsung Adaptive WiFiOppo WiFi Assistant等)。我注意到在某些激活它的电话中解决了其他应用程序问题,这些功能似乎具有在特定网络接口上重新绑定整个应用程序生态系统的权限。这些功能如何帮助/阻碍我?是否可以编写一些功能与这些功能相同的代码?

我有一个汽车伴侣应用程序,需要与wifi和移动数据网络进行通信。我的车辆控制单元提供了一个无法访问Internet的wifi网络,该网络公开了API ...

android networking mobile wifi iot
1个回答
0
投票

首先,关于您的问题:

© www.soinside.com 2019 - 2024. All rights reserved.