睿诚科技协会

Android如何准确判断当前是否为4G网络?

核心概念:网络类型判断的关键

无论使用哪种方法,核心都是获取到当前活动的 Network 对象,然后通过 NetworkCapabilities 来查询该网络的能力(Capabilities),其中就包括网络类型(传输类型)。

Android如何准确判断当前是否为4G网络?-图1
(图片来源网络,侵删)
  • NetworkCapabilities.NET_TRANSPORT_CELLULAR: 表示这是一个蜂窝网络(移动数据,如 2G, 3G, 4G, 5G)。
  • NetworkCapabilities.TRANSPORT_TYPE_LTE: 表示这是一个 LTE 网络(即我们常说的 4G)。注意:这个常量在 Android 9.0 (API 28) 才被引入。

使用 ConnectivityManager (推荐,现代方式)

这是从 Android 6.0 (API 23) 开始引入的、官方推荐的现代网络管理方式,它更准确、更安全,并且是处理所有网络相关操作的首选。

实现步骤:

  1. 获取 ConnectivityManager 实例。
  2. 获取当前活动的网络,这需要 ACCESS_NETWORK_STATE 权限。
  3. 获取该网络的 NetworkCapabilities
  4. 检查 NetworkCapabilities 是否同时满足两个条件:
    • 传输类型是 CELLULAR(蜂窝网络)。
    • 具体子类型是 LTE(4G)。

代码示例 (Kotlin)

这是最简洁和推荐的写法。

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import androidx.core.app.ActivityCompat
/**
 * 检查当前网络是否为4G (LTE)
 * @param Context 上下文
 * @return 如果是4G网络返回true,否则返回false
 */
fun is4GNetwork(context: Context): Boolean {
    // 1. 获取ConnectivityManager
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
        ?: return false
    // 2. 获取当前活动的网络
    // 注意:从Android 10 (API 29)开始,getActiveNetwork()需要声明NETWORK_STACK权限,
    // 对于普通应用,推荐使用getNetworks()来遍历所有网络,然后找到满足条件的网络。
    // 但为了简化示例,这里使用getActiveNetwork(),并处理权限问题。
    val activeNetwork = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        connectivityManager.activeNetwork
    } else {
        // 对于旧版本,使用旧方法
        @Suppress("DEPRECATION")
        connectivityManager.activeNetworkInfo
    } ?: return false // 如果没有活动网络,直接返回false
    // 3. 获取NetworkCapabilities
    val networkCapabilities = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        connectivityManager.getNetworkCapabilities(activeNetwork)
    } else {
        // 旧版本没有NetworkCapabilities,无法精确判断,此方法不适用
        return false
    } ?: return false // 如果无法获取能力,返回false
    // 4. 检查网络类型
    // 网络必须是蜂窝网络,并且具体类型是LTE
    return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
           networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_TYPE_LTE)
}

Java 版本代码示例

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Build;
import androidx.core.app.ActivityCompat;
public class NetworkUtils {
    public static boolean is4GNetwork(Context context) {
        // 1. 获取ConnectivityManager
        ConnectivityManager connectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager == null) {
            return false;
        }
        // 2. 获取当前活动的网络
        Network activeNetwork;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            activeNetwork = connectivityManager.getActiveNetwork();
            if (activeNetwork == null) {
                return false;
            }
        } else {
            // 旧版本处理
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo == null || !networkInfo.isConnected()) {
                return false;
            }
            // 注意:旧版API无法直接使用Network对象,此方法主要针对新版本
            return false; // 简化处理,实际中需要更复杂的兼容逻辑
        }
        // 3. 获取NetworkCapabilities
        NetworkCapabilities networkCapabilities = connectivityManager
                .getNetworkCapabilities(activeNetwork);
        if (networkCapabilities == null) {
            return false;
        }
        // 4. 检查网络类型
        // 网络必须是蜂窝网络,并且具体类型是LTE
        return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
               networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_TYPE_LTE);
    }
}

使用 TelephonyManager (传统方式)

在 Android 9.0 之前,判断网络类型主要依赖 TelephonyManager,它可以直接获取到网络的具体制式(如 GPRS, EDGE, UMTS, LTE 等)。

注意事项:

  • 权限要求: 需要危险权限 READ_PHONE_STATE,从 Android 6.0 开始,需要动态申请。
  • API 版本限制: getNetworkType() 方法在 Android 9.0 (API 28) 时被标记为 @Deprecated,因为它无法区分 Wi-Fi 和蜂窝网络的具体类型,在 Android 10 (API 29) 及以上,它只返回 NETWORK_TYPE_UNKNOWN此方法仅适用于 Android 9.0 以下的版本。

代码示例 (Kotlin)

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.telephony.TelephonyManager
import androidx.core.app.ActivityCompat
/**
 * 使用TelephonyManager检查是否为4G网络
 * 注意:此方法在Android 9.0 (API 28)及以上已废弃,仅适用于旧版本
 * @param Context 上下文
 * @return 如果是4G网络返回true,否则返回false
 */
fun is4GNetworkLegacy(context: Context): Boolean {
    // 1. 检查权限
    if (ActivityCompat.checkSelfPermission(
            context,
            Manifest.permission.READ_PHONE_STATE
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // 如果没有权限,无法判断
        return false
    }
    // 2. 获取TelephonyManager
    val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
        ?: return false
    // 3. 获取网络类型
    val networkType = telephonyManager.networkType
    // 4. 判断是否为LTE (4G)
    // 注意:这些常量在TelephonyManager中定义
    return networkType == TelephonyManager.NETWORK_TYPE_LTE ||
           networkType == TelephonyManager.NETWORK_TYPE_LTE_CA // LTE Carrier Aggregation
}

完整集成示例 (在 Activity/Fragment 中使用)

下面展示如何在 Activity 中结合权限请求,使用推荐的方法来判断网络。

Android如何准确判断当前是否为4G网络?-图2
(图片来源网络,侵删)

添加权限到 AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 如果使用TelephonyManager,还需要这个权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Activity 代码 (Kotlin)

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
    // 现代方式:注册权限请求回调
    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
            if (isGranted) {
                // 权限被授予,可以执行检查
                checkAndShowNetworkStatus()
            } else {
                // 权限被拒绝
                Toast.makeText(this, "需要网络状态权限才能判断", Toast.LENGTH_SHORT).show()
            }
        }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val checkButton: Button = findViewById(R.id.check_button)
        checkButton.setOnClickListener {
            // 检查权限
            when {
                ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.ACCESS_NETWORK_STATE
                ) == PackageManager.PERMISSION_GRANTED -> {
                    // 已有权限,直接检查
                    checkAndShowNetworkStatus()
                }
                shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_NETWORK_STATE) -> {
                    // 用户之前拒绝过,可以在这里解释为什么需要这个权限
                    Toast.makeText(this, "需要此权限来检查网络类型", Toast.LENGTH_LONG).show()
                    // 再次请求
                    requestPermissionLauncher.launch(Manifest.permission.ACCESS_NETWORK_STATE)
                }
                else -> {
                    // 首次请求
                    requestPermissionLauncher.launch(Manifest.permission.ACCESS_NETWORK_STATE)
                }
            }
        }
    }
    private fun checkAndShowNetworkStatus() {
        // 使用现代方法进行判断
        if (is4GNetwork(this)) {
            Toast.makeText(this, "当前网络是 4G (LTE)", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(this, "当前网络不是 4G (LTE)", Toast.LENGTH_SHORT).show()
        }
    }
    // 这里粘贴上面提供的 is4GNetwork() 函数
    fun is4GNetwork(context: Context): Boolean {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            ?: return false
        val activeNetwork = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            connectivityManager.activeNetwork
        } else {
            @Suppress("DEPRECATION")
            connectivityManager.activeNetworkInfo
        } ?: return false
        val networkCapabilities = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            connectivityManager.getNetworkCapabilities(activeNetwork)
        } else {
            return false
        } ?: return false
        return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
               networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_TYPE_LTE)
    }
}

总结与建议

方法 优点 缺点 推荐场景
ConnectivityManager 官方推荐,现代,准确,能区分不同类型的网络(Wi-Fi, 蜂窝等),是未来趋势。 代码稍复杂,需要处理不同 API 版本的兼容性。 所有新项目,特别是需要兼容 Android 6.0 及以上版本的应用。
TelephonyManager 实现简单,直接获取网络制式。 已废弃,在 Android 9.0+ 上无效;需要 READ_PHONE_STATE 权限,用户可能敏感。 维护旧项目,且目标 API 低于 28。

最终建议:

  • 对于任何新的开发,请优先使用 ConnectivityManager 的方法。
  • 如果你的应用需要兼容非常古老的 Android 版本(低于 6.0),你可能需要结合两种方法,并使用 Build.VERSION.SDK_INT 进行判断。
  • 务必处理好运行时权限的申请,特别是 READ_PHONE_STATE(如果使用旧方法)和 ACCESS_NETWORK_STATE(虽然普通权限,但最佳实践是声明)。
Android如何准确判断当前是否为4G网络?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇