Android 14+中如何准确区分4G(LTE)与5G NR(NSA)网络
解决Android 14+下4G LTE与5G NR(NSA)网络识别误判问题
问题背景
在Android 14+设备上,非系统APP仅持有READ_PHONE_STATE权限时,原网络识别逻辑会将实际的4G LTE网络误判为5G NR(NSA),核心原因包括:
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA在4G LTE和5G NR(NSA)场景下均会返回- 误判场景中无NR小区可供验证(
cellInfos中不存在CellInfoNr) serviceState的nrStates被掩码,无法获取准确状态- ##4636#*#*菜单显示NR_NSA但状态栏无5G标识,实际网络为4G LTE
修正后的代码
@SuppressLint("MissingPermission") suspend fun getNetworkType_2(context: Context, telephonyManager: TelephonyManager): String = suspendCancellableCoroutine { cont -> if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { cont.resume("Permission Required") return@suspendCancellableCoroutine } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { CoroutineScope(Dispatchers.Main).launch { val listener = object : PhoneStateListener() { override fun onDisplayInfoChanged(displayInfo: TelephonyDisplayInfo) { val networkType = telephonyManager.dataNetworkType val voiceType = telephonyManager.voiceNetworkType val overrideType = displayInfo.overrideNetworkType val cellInfos = telephonyManager.allCellInfo ?: emptyList() val nrRegistered = cellInfos.any { it is CellInfoNr && it.isRegistered } val lteRegistered = cellInfos.any { it is CellInfoLte && it.isRegistered } val bands = cellInfos.mapNotNull { when (it) { is CellInfoLte -> (it.cellIdentity as? CellIdentityLte)?.earfcn?.let { earfcn -> "L$earfcn" } is CellInfoNr -> (it.cellIdentity as? CellIdentityNr)?.nrarfcn?.let { nrarfcn -> "N$nrarfcn" } else -> null } } val hasNrBand = bands.any { it.startsWith("N") } telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE) Log.d("GeneralMetrics","Logs for identify 5G NR (NSA)") Log.d("GeneralMetrics","===========================") Log.d("GeneralMetrics","networkType: $networkType") Log.d("GeneralMetrics","voiceType: $voiceType") Log.d("GeneralMetrics","overrideType: $overrideType") Log.d("GeneralMetrics","cellInfos: $cellInfos") Log.d("GeneralMetrics","nrRegistered: $nrRegistered") Log.d("GeneralMetrics","lteRegistered: $lteRegistered") Log.d("GeneralMetrics","bands: $bands") Log.d("GeneralMetrics","hasNrBand: $hasNrBand") Log.d("GeneralMetrics","===========================") val finalNetworkType = when { // 5G NR (SA): 仅注册NR小区 nrRegistered && !lteRegistered -> "5G NR (SA)" // 5G NR (NSA): 注册LTE小区,override为NSA,且存在已注册的NR小区或NR频段,语音网络非NR lteRegistered && overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA && voiceType != TelephonyManager.NETWORK_TYPE_NR && (nrRegistered || hasNrBand) -> "5G NR (NSA)" // 4G (LTE): 注册LTE小区,数据和语音网络均为LTE,或override为NSA但无NR小区 lteRegistered && ((networkType == TelephonyManager.NETWORK_TYPE_LTE && voiceType == TelephonyManager.NETWORK_TYPE_LTE) || (overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA && !nrRegistered && !hasNrBand)) -> "4G (LTE)" // NR fallback networkType == TelephonyManager.NETWORK_TYPE_NR -> "5G NR (Unclassified)" // SA override fallback overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED && nrRegistered -> "5G NR (SA)" else -> getNetworkDescription(networkType, overrideType) } Log.d("NetworkType", "Final Network Type: $finalNetworkType, dataNetworkType=$networkType, overrideType=$overrideType, lteRegistered=$lteRegistered, nrRegistered=$nrRegistered, voiceType=$voiceType") if (cont.isActive) { cont.resume(finalNetworkType) } } } telephonyManager.listen(listener, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_CELL_INFO or PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) cont.invokeOnCancellation { telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE) } } } else { val networkType = telephonyManager.dataNetworkType cont.resume(getNetworkDescription(networkType, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) } } fun getNetworkDescription(networkType: Int, overrideType: Int): String { return when (overrideType) { TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> "4G (LTE+ Carrier Aggregation)" TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> "4G (LTE Advanced Pro)" else -> when (networkType) { TelephonyManager.NETWORK_TYPE_GSM -> "2G (GSM)" TelephonyManager.NETWORK_TYPE_EDGE -> "2G (EDGE)" TelephonyManager.NETWORK_TYPE_CDMA -> "2G (CDMA)" TelephonyManager.NETWORK_TYPE_1xRTT -> "2G (1xRTT)" TelephonyManager.NETWORK_TYPE_IDEN -> "2G (iDEN)" TelephonyManager.NETWORK_TYPE_UMTS -> "3G (UMTS)" TelephonyManager.NETWORK_TYPE_EVDO_0 -> "3G (EVDO Rev. 0)" TelephonyManager.NETWORK_TYPE_EVDO_A -> "3G (EVDO Rev. A)" TelephonyManager.NETWORK_TYPE_EVDO_B -> "3G (EVDO Rev. B)" TelephonyManager.NETWORK_TYPE_HSDPA -> "3G (HSDPA)" TelephonyManager.NETWORK_TYPE_HSUPA -> "3G (HSUPA)" TelephonyManager.NETWORK_TYPE_HSPA -> "3G (HSPA)" TelephonyManager.NETWORK_TYPE_EHRPD -> "3G (eHRPD)" TelephonyManager.NETWORK_TYPE_HSPAP -> "3G (HSPA+)" TelephonyManager.NETWORK_TYPE_LTE -> "4G (LTE)" TelephonyManager.NETWORK_TYPE_NR -> "5G NR (Unclassified)" TelephonyManager.NETWORK_TYPE_UNKNOWN -> "Unknown" else -> "Other ($networkType)" } } }
关键修改说明
- 强化NSA判断条件:在原NSA识别逻辑中新增
(nrRegistered || hasNrBand)限制,确保只有存在已注册的NR小区或检测到NR频段时,才判定为5G NR(NSA),直接排除overrideType误报的情况 - 覆盖4G特殊场景:新增
(overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA && !nrRegistered && !hasNrBand)分支,专门处理overrideType显示NSA但实际无NR小区的4G LTE场景 - 保持逻辑兼容:其余网络类型的识别逻辑不变,确保对5G SA、NR fallback等场景的准确性
内容的提问来源于stack exchange,提问作者Chris P
相关产品推荐
相关产品推荐

