如何在不使用GPS的情况下获取我的Android设备国家/地区代码?


71

Android手机实际上确实知道它的位置-但是是否可以通过某种方式(例如国家/地区代码或国家/地区名称)来检索国家/地区?

无需知道确切的GPS位置-国家代码或名称就足够了,我正在使用以下代码:

 String locale = context.getResources().getConfiguration().locale.getCountry(Locale.getDefault());
 System.out.println("country = "+locale);

它给了我代码“美国”,但我的设备保存在印度。有没有一种方法可以在不使用GPS或网络提供商的情况下找到设备的当前国家/地区代码?

因为我正在使用平板电脑。

Answers:


93

您不应该将任何内容传递给getCountry()。移除Locale.getDefault()

String locale = context.getResources().getConfiguration().locale.getCountry();

98
这将返回用户配置的语言环境的国家。如果用户为印度配置了该设备,然后将其带上飞机飞往德国,您仍将获得印度的国家代码。只是以为我会澄清这一点。
David Wasser

1
我居住在比利时,并且我的设备使用的是英语/美国,因此我不确定该代码是否会提供给该国家;-)
Waza_Be 2014年

1
有没有机会,无论调用返回“”或null的宽度有多小?不是实际的国家/地区代码?
天蝎座

9
这已被弃用API等级24
EgemenHamutçu

1
@EgemenHamutçu,您可以使用Configuration#getLocales,或更实用的是ConfigurationCompat#getLocales
androidguy,2016年

88

您可以简单地使用此代码,

TelephonyManager tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String countryCodeValue = tm.getNetworkCountryIso();

如果您当前连接的网络在美国,则将返回“ US”。即使没有SIM卡也可以使用。


好答案。似乎比配置中的设置更可靠
Itai Hanski 2014年

手机应该有一些连接源。WiFi是否开启?
Kishath

5
对于没有SIM卡或平板电脑的设备(仅适用于Wifi网络)
不起作用


1
@ Ben.Slama.Jihed并非全部。根据您提到的文档:“请注意,访问某些电话信息受权限保护。” 而且我认为getNetworkCountryIso()不需要额外的许可。
Twisted Lullaby

52

使用链接http://ip-api.com/json。这将以JSON形式提供所有信息。通过此JSON内容,您可以轻松获取国家/地区。该站点使用您当前的IP地址工作。它会自动检测IP地址和发回详细信息。

文献资料

这就是我得到的:

{
"as": "AS55410 C48 Okhla Industrial Estate, New Delhi-110020",
"city": "Kochi",
"country": "India",
"countryCode": "IN",
"isp": "Vodafone India",
"lat": 9.9667,
"lon": 76.2333,
"org": "Vodafone India",
"query": "123.63.81.162",
"region": "KL",
"regionName": "Kerala",
"status": "success",
"timezone": "Asia/Kolkata",
"zip": ""
}

注意:由于这是第三方API,因此请勿将其用作主要解决方案。而且我不确定它是否免费。


@KhizarHayat使用简单的restfull api调用
Hamzeh Soboh

使用VPN时,这也会提供正确的国家/地区吗?
Vivek Mishra '18

1
啊哈!我躺在俄罗斯莫斯科的沙发上,它给了我{“ as”:“ AS15169 Google LLC”,“ city”:“ Ashburn”,“ country”:“美国”,“ countryCode”:“ US“,” isp“:” Google LLC“,” lat“:39.0438,” lon“:-77.4874,” org“:” Google LLC“,” query“:” 66.102.9.142“,” region“:” VA “,” regionName“:”弗吉尼亚“,”状态“:”成功“,”时区“:”美国/纽约州“,”邮编“:” 20149“}
尤金·卡尔托耶夫

11

检查的答案已弃用代码。您需要实现此:

String locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    locale = context.getResources().getConfiguration().getLocales().get(0).getCountry();
} else {
    locale = context.getResources().getConfiguration().locale.getCountry();
}

2
这总是返回美国
Krunal Shah

1
杰普,我住在南非,我的所有设备都默认为美国
皮埃尔·

7

这是一个完整的例子。它尝试从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 three characters (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;
}

另外一个想法是尝试像此答案中那样的API请求。

参考在这里这里


如果有人像我一样想知道全球CDMA网络的数据源,那就是WIkipedia en.wikipedia.org/wiki/List_of_CDMA2000_networks
androidguy,

7

对于某些设备,如果将默认语言设置为其他语言(印度人可以设置英语(美国)),则

context.getResources().getConfiguration().locale.getDisplayCountry();

会给出错误的值。因此这种方法不可靠。

另外,TelephonyManager的getNetworkCountryIso()方法将在没有SIM卡的设备(Wi-Fi平板电脑)上不起作用。

如果设备没有SIM卡,则可以使用时区获取国家/地区。对于像印度这样的国家,此方法将起作用。

用于检查国家/地区的示例代码是否为印度。

在常量文件中使用以下值

(Constants.INDIA_TIME_ZONE_ID:“ asia / calcutta”,Constants.NETWORK_INDIA_CODE:“ in”)

在您的活动中,添加以下代码:

private void checkCountry() {

    TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (telMgr == null)
        return;

    int simState = telMgr.getSimState();

    switch (simState) {

        // If a SIM card is not available then the
        // country is found using the timezone ID
        case TelephonyManager.SIM_STATE_ABSENT:
            TimeZone tz = TimeZone.getDefault();
            String timeZoneId = tz.getID();
            if (timeZoneId.equalsIgnoreCase(Constants.INDIA_TIME_ZONE_ID)) {
               // Do something
            }
            else {
               // Do something
            }
            break;

        // If a SIM card is available then the telephony
        // manager network country information is used
        case TelephonyManager.SIM_STATE_READY:

            if (telMgr != null) {
                String countryCodeValue = tm.getNetworkCountryIso();

                // Check if the network country code is "in"
                if (countryCodeValue.equalsIgnoreCase(Constants.NETWORK_INDIA_CODE)) {
                   // Do something
                }
                else {
                   // Do something
                }
            }
            break;
    }
}

常量需要导入什么?导入所有可用的常量后,我没有得到NETWORK_INDIA_CODE。
Prantik Mondal

1
@PrantikMondal实际上是我创建的一个类,NETWORK_INDIA_CODE不是android默认常量。您可以直接使用值“ in”
MarGin '19

为什么您两次获得TelephonyManager?一次就足够了
Pierre

6

我创建了一个实用程序功能(在根据语言环境获取不正确的国家/地区代码的设备上进行了一次测试)。

参考CountryCodePicker.java

fun getDetectedCountry(context: Context, defaultCountryIsoCode: String): String {

    detectSIMCountry(context)?.let {
        return it
    }

    detectNetworkCountry(context)?.let {
        return it
    }

    detectLocaleCountry(context)?.let {
        return it
    }

    return defaultCountryIsoCode
}

private fun detectSIMCountry(context: Context): String? {
    try {
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        Log.d(TAG, "detectSIMCountry: ${telephonyManager.simCountryIso}")
        return telephonyManager.simCountryIso
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

private fun detectNetworkCountry(context: Context): String? {
    try {
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        Log.d(TAG, "detectNetworkCountry: ${telephonyManager.simCountryIso}")
        return telephonyManager.networkCountryIso
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

private fun detectLocaleCountry(context: Context): String? {
    try {
        val localeCountryISO = context.getResources().getConfiguration().locale.getCountry()
        Log.d(TAG, "detectNetworkCountry: $localeCountryISO")
        return localeCountryISO
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

4

如果您希望获得国家代码而不征求任何许可,则可以选择一种棘手的方法。

该方法仅使用API​​来获取国家/地区代码,并且没有任何依赖的第三方库。我们可以为我们创造一个。

在这里我使用了Google Cloud Functions编写了一个API,它非常轻松。

第1步:创建一个Google Cloud帐户,然后设置结算(免费套餐就足够了)

步骤2:建立云端功能以取得地理位置

将此基本功能复制到index.js的代码编辑器中:

const cors = require('cors')

function _geolocation(req, res) {
  const data = {
    country_code: req.headers["x-appengine-country"],
    region: req.headers["x-appengine-region"],
    city: req.headers["x-appengine-city"],
    cityLatLong: req.headers["x-appengine-citylatlong"],
    userIP: req.headers["x-appengine-user-ip"]
  }

  res.json(data)
};

exports.geolocation = (req, res) => {
  const corsHandler = cors({ origin: true })

  return corsHandler(req, res, function() {
    return _geolocation(req, res);
  });
};

另外,我们需要复制package.json定义:

{
  "name": "gfc-geolocation",
  "version": "0.0.1",
  "dependencies": {
    "cors": "^2.8.4"
  }
}

步骤3:完成操作,然后获取类似于以下内容的URL: "https://us-central1-geolocation-mods-sdde.cloudfunctions.net/geolocation"

步骤4:解析JSON响应并获取国家/地区代码

响应如下所示:

{
   "country": "IN",
   "region": "kl",
   "city": "kochi",
   "cityLatLong": "9.9312,76.2673",
   "userIP": "xx.xx.xx.xx"
}

感谢和感谢,进入“中型”文章:具有Google Cloud Functions的基于IP的免费地理定位


2

无需调用任何API。您可以从设备所在的国家/地区获取国家/地区代码。只需使用此功能:

 fun getUserCountry(context: Context): String? {
    try {
        val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        val simCountry = tm.simCountryIso
        if (simCountry != null && simCountry.length == 2) { // SIM country code is available
            return simCountry.toLowerCase(Locale.US)
        } 
        else if (tm.phoneType != TelephonyManager.PHONE_TYPE_CDMA) { // Device is not 3G (would be unreliable)
            val networkCountry = tm.networkCountryIso
            if (networkCountry != null && networkCountry.length == 2) { // network country code is available
                return networkCountry.toLowerCase(Locale.US)
            }
        }
    }
    catch (e: Exception) {
    }
    return null
}

这总是有效吗?是否有某些情况甚至失败了?例如,“ networkCountryIso”返回什么?
Android开发人员

@Blue_Alien ya
帕维尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.