一篇關於 Android 獲取運營商的全面筆記

內容總覽

本文會給出在 Android 上獲取運營商的方法,幾個相近方法結果的差異,以及在多卡情況下有效的獲取方式。最後額外提一下一種不需要請求設備識別碼獲取運營商信息的方法。提供可運行的 demo 源碼。

MCC 和 MNC

首先介紹一下這兩個碼,也是獲取運營商所必須的。

MCC,Mobile Country Code,移動設備國家代碼。MNC,Mobile Network Code,移動設備網絡代碼。MCC 和 MNC 串在一起後,可以用來表示唯一的移動設備運營商。我國的 MCC 是 460,MNC 則會出現一個運營商擁有多個的情況,比如聯通有 01、06、09。

於是可以先根據碼錶來構建這麼一個類:

enum class NetworkOperator(val opName: String) {

    Mobile("移動"),
    Unicom("聯通"),
    Telecom("電信"),
    Tietong("鐵通"),
    Other("其他");

    companion object {
        /**
         * 根據 [code](MCC+MNC) 返回運營商
         */
        fun from(code: Int) = when (code) {
            46000, 46002, 46004, 46007, 46008 -> Mobile
            46001, 46006, 46009 -> Unicom
            46003, 46005, 46011 -> Telecom
            46020 -> Tietong
            else -> Other
        }

        fun fromOpName(name: String) = when (name) {
            "移動" -> Mobile
            "聯通" -> Unicom
            "電信" -> Telecom
            "鐵通" -> Tietong
            else -> Other
        }
    }
}

你很可能也知道存在一個叫做 IMSI 的識別碼(注意並不是 IMEI 哦)。國際移動用戶識別碼(International Mobile Subscriber Identity)可以在蜂窩網絡中區分不同用戶,它是由 MCC、MNC 和 MSIN(移動訂戶識別碼,Mobile Subscription Identification Number)組成的。即 IMSI = MCC + MNC + MSIN。

如何獲取

在 Android 上首先需要請求 READ_PHONE_STATE 權限,然後通過 TelephonyManager 相關方法來獲取信息。TelephonyManager 有若干相近的方法,也讓人挺困惑的。Demo 裏會列出各個方法的結果,有興趣的可以自行嘗試一下。

val tm = getSystemService<TelephonyManager>()
val text = """
    TelephonyManager.getSimOperator(): ${tm.simOperator}
    TelephonyManager.getSimOperatorName(): ${tm.simOperatorName}
    TelephonyManager.getNetworkOperator(): ${tm.networkOperator}
    TelephonyManager.getNetworkOperatorName(): ${tm.networkOperatorName}
    TelephonyManager.getSubscriberId(): ${tm.subscriberId}
    Operator name: ${NetworkOperator.from(Integer.valueOf(tm.simOperator)).opName}
""".trimIndent()

在我的設備上得到的結果如下:

TelephonyManager.getSimOperator(): 46009				// 當前流量卡,聯通
TelephonyManager.getSimOperatorName(): CMCC				// 聯通
TelephonyManager.getNetworkOperator(): 46000			// 移動,卡一
TelephonyManager.getNetworkOperatorName(): CHINA MOBILE  // 移動
TelephonyManager.getSubscriberId(): 46002326951xxxx    	 // 移動,這就是 IMSI,xxxx 部分是由我隱去的
Operator name: 聯通

那麼得到了 MCC+MNC,就可以判斷出運營商了。

雙卡情況

如果設備有雙卡,該怎麼樣呢?切換流量卡後再來看一下結果:

TelephonyManager.getSimOperator(): 46002				// 當前流量卡,移動
TelephonyManager.getSimOperatorName(): CMCC				// 聯通,跟 getSimOperator() 結果不符
TelephonyManager.getNetworkOperator(): 46000			// 移動
TelephonyManager.getNetworkOperatorName(): CHINA MOBILE  // 移動
TelephonyManager.getSubscriberId(): 46002326951xxxx		 // 移動
Operator name: 移動

通過嘗試可以發現,TelephonyManager.getSimOperator() 方法獲得的結果是根據當前設置的流量卡變化的。而其他的方法結果都沒有變化,甚至得到的信息也是不統一的,可以說沒什麼用處。

不過我還無法確定這些方法的結果在不同設備不同 ROM 上的效果,僅供參考。可以下載 demo 來查看在自己設備上的結果。

不需要權限的方法

我們都知道 Android 會根據設備設置的不同,去加載不同的資源文件夾。最典型的,會根據系統的語言去加載不同語言的字符串資源。而 Android 也可以根據 MCC 和 MNC 加載不同的資源。

於是我靈光一閃,給 values 文件夾加上 -mcc460-mnc00 後綴,然後在裏面放上對應運營商的名字字符串,就可以繞開權限獲取到運營商了。

不過等等,這麼一來要給每個 MNC 都寫一個文件夾,還挺麻煩的,還是用代碼來獲取吧:

val mcc = resources.configuration.mcc
val mnc = resources.configuration.mnc
val operator = NetworkOperator.from(mcc * 100 + mnc)

這個方法也是有缺點的,不然我就把這個方法寫在前了——無法獲取到當前流量卡的信息,獲取到的信息是固定的。

Demo 源代碼

運行以下命令來獲得 demo 的源代碼:

git clone -b sim-operator https://github.com/Loong-T/demo.git

最後

如果你看到了這裏,覺得文章寫得不錯就給個讚唄!歡迎大家評論討論!如果你覺得那裏值得改進的,請給我留言。一定會認真查詢,修正不足,定期免費分享技術乾貨。感興趣的小夥伴可以點一下關注哦。謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章