我正在创建一个应用程序,具体取决于您的移动网络提供商所在的国家/地区,显示来自同一国家/地区的所有其他移动网络提供商的列表。为此,我使用telephonyManager.getSimCountryIso()检索国家/地区代码。
官方Android开发人员文档说:“返回SIM提供商的国家代码等同的ISO国家代码”,因此我希望国家代码始终与设备位置无关。但那不是它的实际效果!例如,我最近经历过这种情况:我有一个来自西班牙的SIM卡的Android设备属于西班牙语网络提供商。因此,如果我在西班牙,telephonyManager.getSimCountryIso()将返回“es”。到目前为止一切正常。问题是当我前往法国时,例如我调试应用程序并找出telephonyManager.getSimCountryIso()返回国家代码:“nl”(来自荷兰!?我在法国漫游,但使用相同的西班牙语SIM卡!)。我使用与西班牙相同的设备和相同的SIM卡,所以国家代码ISO应该仍然是“es”。
我的问题是这种方法实际上如何运作?如果我使用西班牙语SIM卡,为什么我会收到国家代码“nl”(荷兰)?
在此先感谢您的帮助
您可以使用MCC MNC获取SIM卡国家/地区,它是SIM配置的,与您所在的网络无关。
Configuration config = getResources().getConfiguration();
int countryCode = config.mcc;
你可以在这里找到MCC列表MccTable.java
例如,西班牙是214,法国是208
MCC应该适用于所有带有SIM卡的GSM设备,但在CDMA网络上不可靠
对于CDMA设备,我找到了following solution
if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
// Gives MCC + MNC
String homeOperator = ((String) get.invoke(c, "ro.cdma.home.operator.numeric"));
String country = homeOperator.substring(0, 3); // the last three digits is MNC
} else {
Configuration config = getResources().getConfiguration();
int countryCode = config.mcc;
}
您可以尝试从TelephonyManager(来自SIM或CDMA设备)获取国家/地区代码,如果不可用,请尝试从本地配置获取。这是一个完整的例子。
private static String getDeviceCountryCode(Context context) {
String countryCode;
// try to get country code from TelephonyManager service
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(tm != null) {
// query first getSimCountryIso()
countryCode = tm.getSimCountryIso();
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
// special case for CDMA Devices
countryCode = getCDMACountryIso();
} else {
// for 3G devices (with SIM) query getNetworkCountryIso()
countryCode = tm.getNetworkCountryIso();
}
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
}
// if network country not available (tablets maybe), get country code from Locale class
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
countryCode = context.getResources().getConfiguration().getLocales().get(0).getCountry();
} else {
countryCode = context.getResources().getConfiguration().locale.getCountry();
}
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
// general fallback to "us"
return "us";
}
@SuppressLint("PrivateApi")
private static String getCDMACountryIso() {
try {
// try to get country code from SystemProperties private class
Class<?> systemProperties = Class.forName("android.os.SystemProperties");
Method get = systemProperties.getMethod("get", String.class);
// get homeOperator that contain MCC + MNC
String homeOperator = ((String) get.invoke(systemProperties,
"ro.cdma.home.operator.numeric"));
// first 3 chars (MCC) from homeOperator represents the country code
int mcc = Integer.parseInt(homeOperator.substring(0, 3));
// mapping just countries that actually use CDMA networks
switch (mcc) {
case 330: return "PR";
case 310: return "US";
case 311: return "US";
case 312: return "US";
case 316: return "US";
case 283: return "AM";
case 460: return "CN";
case 455: return "MO";
case 414: return "MM";
case 619: return "SL";
case 450: return "KR";
case 634: return "SD";
case 434: return "UZ";
case 232: return "AT";
case 204: return "NL";
case 262: return "DE";
case 247: return "LV";
case 255: return "UA";
}
} catch (ClassNotFoundException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (IllegalAccessException ignored) {
} catch (InvocationTargetException ignored) {
} catch (NullPointerException ignored) {
}
return null;
}
另一个想法是尝试像这个answer中的API请求,或使用fine location。