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