意外的telephonyManager.getSimCountryIso()行为

问题描述 投票:5回答:2

我正在创建一个应用程序,具体取决于您的移动网络提供商所在的国家/地区,显示来自同一国家/地区的所有其他移动网络提供商的列表。为此,我使用telephonyManager.getSimCountryIso()检索国家/地区代码。

官方Android开发人员文档说:“返回SIM提供商的国家代码等同的ISO国家代码”,因此我希望国家代码始终与设备位置无关。但那不是它的实际效果!例如,我最近经历过这种情况:我有一个来自西班牙的SIM卡的Android设备属于西班牙语网络提供商。因此,如果我在西班牙,telephonyManager.getSimCountryIso()将返回“es”。到目前为止一切正常。问题是当我前往法国时,例如我调试应用程序并找出telephonyManager.getSimCountryIso()返回国家代码:“nl”(来自荷兰!?我在法国漫游,但使用相同的西班牙语SIM卡!)。我使用与西班牙相同的设备和相同的SIM卡,所以国家代码ISO应该仍然是“es”。

我的问题是这种方法实际上如何运作?如果我使用西班牙语SIM卡,为什么我会收到国家代码“nl”(荷兰)?

在此先感谢您的帮助

android localization
2个回答
3
投票

您可以使用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;
}

1
投票

您可以尝试从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

引用herehere

© www.soinside.com 2019 - 2024. All rights reserved.