Android获取手机运营商名称

前言

因为项目中经常会遇到要上传一系列设备信息的功能,为了方便使用,所以就拆分成以下系列文章来单独介绍如何获取各类设备信息

为了不产生歧义搞混淆,先提前说明下移动和中国移动是两码事,移动客户并不是指中国移动的客户。

1. 概念了解

MCC: 移动国家号码,由3位数字组成,唯一的识别移动客户所属的国家,我国为460;

扫描二维码关注公众号,回复: 13503246 查看本文章

MNC: 为网络id,由两位数字组成,用于识别移动客户所归属的移动网络, 中国移动系统使用00、02、04、07,中国联通GSM系统使用01、06、09,中国电信CDMA系统使用03、05、电信4G使用11,中国铁通系统使用20。

MSIN: 移动用户识别号码 ,是国际移动用户识别码(IMSI)组成部分

IMSI: 国际移动用户识别码,共有15位,储存在SIM卡中,由MCC、MNC,MSIN组成

所以想要知道运营商名称,我们主要是通过判断MNC来区别是哪种运营商

2. CDMA、GSM区别

CDMA和GSM简单点说其实就是使用了不同的通信技术,以下表格显示了各大运营商所使用的通信技术。

2G 3G 4G
中国移动 GSM TD-SCDMA TD-LTE
中国联通 GSM WCDMA TD-LTE/FDD-LTE
中国电信 CDMA1X
有时直接写CDMA
CDMA2000
EVDO是中国电信的CDMA2000的3G网络的无线上网模式
TD-LTE/FDD-LTE

3. 获取运营商方式

3.1 通过getSimOperator()、getSimOperatorName()

3.1.1 所需权限

不需要权限

3.1.2 方法解释

查看源码看以下方法的解释:

getSimOperator()

/**
* Returns the MCC+MNC (mobile country code + mobile network code) of the
* provider of the SIM. 5 or 6 decimal digits.
* <p>
* Availability: SIM state must be {@link #SIM_STATE_READY}
* @see #getSimState
*/

返回SIM卡提供商的MCC+MNC(移动国家代码+移动网络代码)。5或6位十进制数字。 
使用的前提是getSimState()方法得到的值为SIM_STATE_READY

getSimOperatorName()

/**
* Returns the Service Provider Name (SPN).
* <p>
* Availability: SIM state must be {@link #SIM_STATE_READY}
*
* @see #getSimState
*/

返回服务提供商名称 (SPN)。使用的前提是SIM卡的状态必须是 SIM_STATE_READY

3.1.3 实际使用

private fun getSimOperatorName() {
    
    
    var opeType = "OTHER"
    val tm =
    getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    val simOperator = tm.simOperator

    if (tm.simState != TelephonyManager.SIM_STATE_READY) {
    
    
        when (tm.simState) {
    
    
            TelephonyManager.SIM_STATE_ABSENT -> {
    
    //1
                Log.i(TAG, "没有Sim卡")
            }
            TelephonyManager.SIM_STATE_PIN_REQUIRED -> {
    
    //2
                Log.i(TAG, "Sim卡状态锁定,需要PIN解锁")
            }
            TelephonyManager.SIM_STATE_PUK_REQUIRED -> {
    
    //3
                Log.i(TAG, "Sim卡状态锁定,需要PUK解锁")
            }
            TelephonyManager.SIM_STATE_NETWORK_LOCKED -> {
    
    //4
                Log.i(TAG, "需要网络PIN码解锁")
            }
            //...
        }
        return
    }
    Log.i(TAG, "getSimOperator()获取的MCC+MNC为:$simOperator")
    Log.i(TAG, "getSimOperatorName()方法获取的运营商名称为:${
      
      tm.simOperatorName} ")
    opeType = if ("46001" == simOperator || "46006" == simOperator || "46009" == simOperator) {
    
    
        "中国联通"
    } else if ("46000" == simOperator || "46002" == simOperator || "46004" == simOperator || "46007" == simOperator) {
    
    
        "中国移动"
    } else if ("46003" == simOperator || "46005" == simOperator || "46011" == simOperator) {
    
    
        "中国电信"
    } else if ("46020" == simOperator) {
    
    
        "中国铁通"
    } else {
    
    
        "OHTER"
    }
    Log.i(TAG, "通过getSimOperator()人为判断的运营商名称是: $opeType")
}

3.1.4 实验数据

实验设备是MI9手机,双卡双待,卡槽一是中国移动卡,卡槽二是中国联通卡,分别变换拨号卡和上网卡,通过测试,得到以下数据

拨号卡移动,上网卡移动

getSimOperator()获取的MCC+MNC为:46002
getSimOperatorName()方法获取的运营商名称为:中国移动 
通过getSimOperator()人为判断的运营商名称是: 中国移动

拨号卡移动,上网卡联通

getSimOperator()获取的MCC+MNC为:46001
getSimOperatorName()方法获取的运营商名称为:中国移动 
通过getSimOperator()人为判断的运营商名称是: 中国联通

拨号卡联通,上网卡移动

getSimOperator()获取的MCC+MNC为:46002
getSimOperatorName()方法获取的运营商名称为:中国联通 
通过getSimOperator()人为判断的运营商名称是: 中国移动

拨号卡联通,上网卡联通

getSimOperator()获取的MCC+MNC为:46001
getSimOperatorName()方法获取的运营商名称为:中国联通 
通过getSimOperator()人为判断的运营商名称是: 中国联通

拨号时选择Sim卡,上网卡移动

getSimOperator()获取的MCC+MNC为:46002
getSimOperatorName()方法获取的运营商名称为:中国移动 
通过getSimOperator()人为判断的运营商名称是: 中国移动

拨号时选择Sim卡,上网卡联通

getSimOperator()获取的MCC+MNC为:46001
getSimOperatorName()方法获取的运营商名称为:中国移动 
通过getSimOperator()人为判断的运营商名称是: 中国联通

3.1.5 结论⭐

  • getSimOperator()得到的是上网卡的运营商
  • getSimOperatorName()得到的是拨号卡的运营商
  • 拨号时选择Sim卡,getSimOperatorName()得到的是卡槽1的运营商

3.2 通过getNetworkOperator()、getNetworkOperatorName()

3.2.1 所需权限

不需要权限

3.2.2 方法解释

查看源码看以下方法的解释:

getNetworkOperator()

/**
* Returns the numeric name (MCC+MNC) of current registered operator.
* <p>
* Availability: Only when user is registered to a network. Result may be
* unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
* on a CDMA network).
*/

返回当前注册运营商的数字名称(MCC+MNC)

使用的前提是用户需注册到网络上。在CDMA网络上可能不可靠,需要用getPhoneType()方法确定是否在CDMA网络上

getNetworkOperatorName()

/**
* Returns the alphabetic name of current registered operator.
* <p>
* Availability: Only when user is registered to a network. Result may be
* unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
* on a CDMA network).
*/

返回当前注册运营商的字母名称

仅当用户注册到网络时才可以使用,如果当前网络在CDMA上,得到的结果可能不可靠

3.2.3 实际使用

private fun getNetWorkOperatorName() {
    
    
    var opeType = "OTHER"
    val tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    //用于判断拨号那张卡的运营商
    val networkOperator = tm.networkOperator
    Log.i(TAG, "getNetWorkOperator()获取的MCC+MNC为:$networkOperator")
    if (tm.phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
    
    
        Log.i(TAG, "getNetWorkOperatorNameTest: 在CDMA网络上,不可靠,所以不用这种方法")
        return
    }
    when(tm.phoneType){
    
    
        0->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:NO_PHONE")
        }
        1->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:GSM_PHONE")
        }
        2->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:CDMA_PHONE")
        }
        3->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:SIP_PHONE")
        }
        4->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:THIRD_PARTY_PHONE")
        }
        5->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:IMS_PHONE")
        }
        6->{
    
    
            Log.i(TAG, "getPhoneType()网络类型为:CDMA_LTE_PHONE")
        }
    }
    Log.i(TAG, "getNetworkOperatorName()方法获取的网络类型名称是: ${
      
      tm.networkOperatorName}")
    opeType =
    if ("46001" == networkOperator || "46006" == networkOperator || "46009" == networkOperator) {
    
    
        "中国联通"
    } else if ("46000" == networkOperator || "46002" == networkOperator || "46004" == networkOperator || "46007" == networkOperator) {
    
    
        "中国移动"
    } else if ("46003" == networkOperator || "46005" == networkOperator || "46011" == networkOperator) {
    
    
        "中国电信"
    } else {
    
    
        "OHTER"
    }
    Log.i(TAG, "通过getNetWorkOperator()人为判断的运营商名称是: $opeType")
}

3.2.4 实验数据

拨号卡移动,上网卡移动

getNetWorkOperator()获取的MCC+MNC为:46000
getPhoneType()网络类型为:GSM_PHONE
getNetworkOperatorName()方法获取的网络类型名称是: 中国移动
通过networkOperator人为判断的运营商名称是: 中国移动

拨号卡移动,上网卡联通

getNetWorkOperator()获取的MCC+MNC为:46000
getPhoneType()网络类型为:GSM_PHONE
getNetworkOperatorName()方法获取的网络类型名称是: 中国移动
通过networkOperator人为判断的运营商名称是: 中国移动

拨号卡联通,上网卡移动

getNetWorkOperator()获取的MCC+MNC为:46001
getPhoneType()网络类型为:GSM_PHONE
getNetworkOperatorName()方法获取的网络类型名称是: 中国联通
通过networkOperator人为判断的运营商名称是: OHTER

拨号卡联通,上网卡联通

getNetWorkOperator()获取的MCC+MNC为:46001
getPhoneType()网络类型为:GSM_PHONE
getNetworkOperatorName()方法获取的网络类型名称是: 中国联通
通过networkOperator人为判断的运营商名称是: OHTER

拨号时选择Sim卡,上网卡移动

getNetWorkOperator()获取的MCC+MNC为:46000
getPhoneType()网络类型为:GSM_PHONE
getNetworkOperatorName()方法获取的网络类型名称是: 中国移动
通过networkOperator人为判断的运营商名称是: 中国移动

拨号时选择Sim卡,上网卡联通

getNetWorkOperator()获取的MCC+MNC为:46000
getPhoneType()网络类型为:GSM_PHONE
getNetworkOperatorName()方法获取的网络类型名称是: 中国移动
通过networkOperator人为判断的运营商名称是: 中国移动

3.2.5 结论⭐

  • getNetWorkOperator()得到的是拨号卡的运营商
  • getNetworkOperatorName()得到的是拨号卡的运营商
  • 拨号时选择Sim卡,getNetWorkOperator()getNetworkOperatorName()得到的都是卡槽1的运营商

3.3 通过getMcc()、getMnc()

3.3.1 所需权限

READ_PHONE_STATE权限

注意:小米手机申请后得到的可能是空白通行证,会导致获取不到信息

3.3.2 方法解析

getMcc()

/**
* @return the MCC.
* @deprecated Use {@link #getMccString()} instead.
*/

getMnc()

/**
* @return the MNC.
* @deprecated Use {@link #getMncString()} instead.
*/

3.3.3 实际使用

private fun getMNCAndMCC() {
    
    
    //5.1及以上版本才可使用
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
    
    
        val permissionList = mutableListOf<String>()
        permissionList.add(android.Manifest.permission.READ_PHONE_STATE)
        //权限申请及判断
        if (requestPermission(1, permissionList)) {
    
    
            Log.i(TAG, "getMNCAndMCC: 已获取READ_PHONE_STATE权限")
            val subscriptionManager: SubscriptionManager =
            getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
            //22需要版本5.1及以上才行
            val list = mutableListOf<SubscriptionInfo>()
            //上面的requestPermission()方法已经进行了判断
            if (subscriptionManager.activeSubscriptionInfoList != null) {
    
    
                list.addAll(subscriptionManager.activeSubscriptionInfoList)
                if (list.size > 0) {
    
    
                    for (s in list) {
    
    
                        //10.0以上用下面的方法获取,10.0以下用上面的方法获取
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    
    
                            Log.i(TAG, "卡槽${
      
      s.simSlotIndex}:mcc = " + s.mccString + " mnc = " + s.mncString)
                        } else {
    
    
                            Log.i(TAG, "卡槽${
      
      s.simSlotIndex}:mcc = " + s.mcc + " mnc = " + s.mnc)
                        }
                    }
                } else {
    
    
                    Log.i(TAG, "getMNCAndMCC: 获取到的信息为空")
                }
            } else {
    
    
                Log.i(TAG, "getMNCAndMCC: 获取到的信息为空")
            }
        }
    }
}

3.3.4 实验数据

无论如何变换拨号卡和上网卡,得到的均为以下数据

卡槽0:mcc = 460 mnc = 02
卡槽1:mcc = 460 mnc = 01

3.3.5 结论⭐

  • 通过getMnc()可以判断是何种运营商,但是前提需要申请READ_PHONE_STATE权限,且可能遇到有些手机即使有权限获取到的仍为null的情况
  • getMcc()getMnc()方法得到的标识不跟随你拨号卡和上网卡的选择切换而改变,获取的是对应卡槽的内容。

3.4 getSubscriberId()

   /**
     * Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
     * Return null if it is unavailable.
     *
     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
     * restrictions, and apps are recommended to use resettable identifiers (see <a
     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
     * the following requirements is met:
     * <ul>
     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
     *     is a privileged permission that can only be granted to apps preloaded on the device.
     *     <li>If the calling app is the device or profile owner and has been granted the
     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
     *     owns a managed profile on the device; for more details see <a
     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
     *     Profile owner access is deprecated and will be removed in a future release.
     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
     *     <li>If the calling app is the default SMS role holder (see {@link
     *     RoleManager#isRoleHeld(String)}).
     * </ul>
     *
     * <p>If the calling app does not meet one of these requirements then this method will behave
     * as follows:
     *
     * <ul>
     *     <li>If the calling app's target SDK is API level 28 or lower and the app has the
     *     READ_PHONE_STATE permission then null is returned.</li>
     *     <li>If the calling app's target SDK is API level 28 or lower and the app does not have
     *     the READ_PHONE_STATE permission, or if the calling app is targeting API level 29 or
     *     higher, then a SecurityException is thrown.</li>
     * </ul>
     */
     
     
     
返回唯一的用户 ID,例如,GSM 电话的 IMSI。
如果不可用则返回 null。
如果安卓版本号是29及以上,即Android 10.0及以上,则需要READ_PRIVILEGED_PHONE_STATE权限才可调用
如果是28及以下,则需要申请READ_PHONE_STATE权限,且得到的是null,如果没有申请该权限,则会抛出异常

有人说可以通过getSubscribeId()方法获取到IMSI后人为的判断,但是因为该方法需要READ_PRIVILEGED_PHONE_STATE权限,这个权限只有系统应用才可以获取,所以我们不使用此方法。

3.5 方法比较

由3.1.5、3.2.5、3.3.5可以得知,

  • getSimOperator()得到上网卡运营商

  • getSimOperatorName()getNetworkOperator()getNetworkOperatorName()得到拨号卡运营商

如果想得到运营商名称,有人会说那我们直接用getSimOperatorName()或者getNetworkOperatorName()就能直接获取到,为什么还要用getNetworkOperator()通过MNC号来人为的判断呢,因为在有些手机上,获取到的名称是CMCC、CUCC、CTCC,而不是中国移动、中国联通、中国电信,所以需要我们人为的判断下。

综上,以后我们要获取运营商名称,直接使用getSimOperator()getNetworkOperator()方法即可。

至于getMNC()方法,因为要动态申请READ_PHONE_STATE权限,而且有可能有权限却得到的是空白通行证,所以要谨慎使用。

4. 总结

综上,以后想要获取拨号卡运营商名称,直接通过getNetworkOperator()方法,获取上网卡运营商,直接通过getSimOperator()方法。
且要注意, getSimOperator()得到的是上网卡运营商名称,而getNetworkOperatorName()得到的却是拨号卡的运营商名称,千万不要被名字给诱导错了!!!

项目地址

如果本文对你有帮助,请别忘记点赞start,如果有不恰当的地方也请提出来,下篇文章见。

5. 参考文章

android 获取sim卡运营商信息(转) - qiangzhu - 博客园 (cnblogs.com)

MNC(移动网络号码)_百度百科 (baidu.com)

MSIN_百度百科 (baidu.com)

手机网络制式_百度百科 (baidu.com)

Android双卡设备 如何正确获取上网卡运营商类型_ReadyShowShow的博客-CSDN博客_android 获取双卡运营商名称

一篇关于 Android 获取运营商的全面笔记 - SegmentFault 思否

猜你喜欢

转载自blog.csdn.net/Myfittinglife/article/details/118685804