You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android应用如何在WiFi环境下强制使用移动数据发起网络请求?

这个需求确实挺棘手的,我之前帮朋友处理过类似场景,不同厂商的系统对网络接口的管控差异很大,咱们一步步来拆解可行的解决办法:

先搞定必要的权限

首先得在AndroidManifest.xml里加上这些权限,不然后续操作全白搭:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- Android 10+ 后台保持网络连接可能需要这个 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
方法一:系统层面绑定移动数据网络(推荐普通应用用)

Android 7.0(API 24)及以上提供了bindProcessToNetwork方法,可以把整个应用的网络请求绑定到指定的移动数据网络上,无视当前WiFi连接。

用Kotlin实现的代码大概是这样:

val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

// 构建只匹配移动数据的网络请求
val cellularNetworkRequest = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .build()

// 注册网络回调,拿到可用的移动数据网络后绑定
val networkCallback = object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        // 把当前应用进程绑定到这个移动数据网络
        connectivityManager.bindProcessToNetwork(network)
        // 现在发起的所有请求都会走移动数据了
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        // 移动数据断开时解绑,避免影响后续网络请求
        connectivityManager.bindProcessToNetwork(null)
    }
}

// 开始监听符合条件的网络
connectivityManager.requestNetwork(cellularNetworkRequest, networkCallback)

注意点:

  • 低于API 24的设备只能用废弃的setProcessDefaultNetwork,效果类似但不推荐
  • 有些厂商(比如三星)在WiFi连接时会彻底隐藏移动数据接口,这时候需要引导用户手动开启系统里的「WiFi与移动数据同时使用」选项(不同厂商位置不同,一般在移动网络的高级设置里)
  • 一加设备的接口未启用的情况,绑定网络后系统会自动尝试启用接口,大部分时候能解决问题
方法二:强制开启移动数据(仅系统/ROOT应用可用)

如果是系统级应用或者有ROOT权限的应用,可以强制开启移动数据,哪怕WiFi连接着。普通应用拿不到MODIFY_PHONE_STATE这个系统权限,所以这条路走不通。

ROOT环境下可以用Kotlin执行命令:

fun enableMobileData() {
    try {
        Runtime.getRuntime().exec(arrayOf("su", "-c", "settings put global mobile_data 1"))
    } catch (e: IOException) {
        e.printStackTrace()
    }
}
方法三:单独给OkHttp请求指定网络

如果不想全局绑定,只是特定请求走移动数据,可以给OkHttpClient指定移动数据的SocketFactory:

// 假设已经通过NetworkCallback拿到了移动数据的network对象
val okHttpClient = OkHttpClient.Builder()
    .socketFactory(network.socketFactory)
    .build()

// 用这个client发起的请求都会走移动数据
val request = Request.Builder().url("https://your-api-url.com").build()
okHttpClient.newCall(request).enqueue(object : Callback {
    // 回调逻辑...
})
最后提醒

这个需求其实有点违背Android默认的网络策略,很多厂商的定制系统(比如MIUI、ColorOS)会有额外的限制,比如省电模式下会强制关闭移动数据。所以最好在应用里加个引导,告诉用户需要开启「WiFi与移动数据同时使用」以及关闭对应的省电优化。

内容的提问来源于stack exchange,提问作者maj

火山引擎 最新活动