我在哪里? - 获得国家

Don*_*Gru 122 android geolocation

Android移动实际上并一清二楚,它在哪里 - 但有通过类似的国家代码检索国家的一种方式?

无需了解确切的GPS位置 - 这个国家就足够了

我首先考虑使用时区,但实际上我需要更多的信息,因为如果位置是纽约或利马它会有所不同.

问题的背景:我有一个使用温度值的应用程序,我想将默认单位设置为Celsius或Fahrenheit,具体取决于位置是美国还是外部

caw*_*caw 131

/**
 * Get ISO 3166-1 alpha-2 country code for this device (or null if not available)
 * @param context Context reference to get the TelephonyManager instance from
 * @return country code or null
 */
public static String getUserCountry(Context context) {
    try {
        final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        final String simCountry = tm.getSimCountryIso();
        if (simCountry != null && simCountry.length() == 2) { // SIM country code is available
            return simCountry.toLowerCase(Locale.US);
        }
        else if (tm.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { // device is not 3G (would be unreliable)
            String networkCountry = tm.getNetworkCountryIso();
            if (networkCountry != null && networkCountry.length() == 2) { // network country code is available
                return networkCountry.toLowerCase(Locale.US);
            }
        }
    }
    catch (Exception e) { }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

  • 仅适用于带有SIM卡的手机或其他设备.在WIFI平板电脑上使用时,您将获得null.所以它的用处是有限的. (14认同)
  • 请注意,如果来自美国的用户在法国度假,`getSimCountryIso`会说'us`而`getNetworkCountryIso`会说`fr` (11认同)
  • 您可能想将“toLowerCase()”调用更改为“toUpperCase()”。 (2认同)

ste*_*ter 91

这将获得国家代码:

 String locale = context.getResources().getConfiguration().locale.getCountry(); 
Run Code Online (Sandbox Code Playgroud)

也可以用getISO3Country()替换getCountry()以获得该国家的3字母ISO代码.这将获得国家名称:

 String locale = context.getResources().getConfiguration().locale.getDisplayCountry();
Run Code Online (Sandbox Code Playgroud)

这似乎比其他方法更容易,并依赖于手机上的本地化设置,所以如果美国用户在国外,他们可能仍然需要华氏温度,这将工作:)

  • 这在Android没有Locale的国家/地区不起作用.例如,在瑞士,语言可能设置为德语或法语.这种方法会给你德国或法国,而不是瑞士.最好使用LocationManager或TelephonyManager方法. (78认同)
  • 这**不回答**问题的**标题**.我可能将手机设置为英语并且可以在世界的任何地方(我的母语是_not_英语,但是我的手机设置为(英国)英语.但是**确实回答了实际的问题**,因为用户如果他是美国人,他想要美国单位,无论他究竟在哪里. (19认同)
  • 效果不好.我必须区分所有拉丁美洲国家的用户所在国家,所有测试手机都已返回美国,即使手机是英语或西班牙语. (3认同)
  • 一般来说,这是一个很好的答案,但它只返回语言环境的国家,而不是实际的国家。 (3认同)
  • 不是获取国家名称的可行解决方案 (2认同)

Don*_*Gru 60

实际上我只是发现使用getSimCountryIso()方法获得国家代码还有一种方法TelephoneManager:

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String countryCode = tm.getSimCountryIso();
Run Code Online (Sandbox Code Playgroud)

因为它是sim代码,所以在去其他国家旅行时也不应该改变.

  • 当设备没有SIM卡(例如平板电脑)时,这可能不起作用 (40认同)

shi*_*eph 60

使用此链接http://ip-api.com/json ,这将提供所有信息为json.从这个json你可以很容易地到达这个国家.此站点使用您当前的IP工作,它会自动检测IP和发送回复的详细信息.

文档http://ip-api.com/docs/api:json 希望它有所帮助.

示例json

{
  "status": "success",
  "country": "United States",
  "countryCode": "US",
  "region": "CA",
  "regionName": "California",
  "city": "San Francisco",
  "zip": "94105",
  "lat": "37.7898",
  "lon": "-122.3942",
  "timezone": "America/Los_Angeles",
  "isp": "Wikimedia Foundation",
  "org": "Wikimedia Foundation",
  "as": "AS14907 Wikimedia US network",
  "query": "208.80.152.201"
}
Run Code Online (Sandbox Code Playgroud)

注意:由于这是第三方解决方案,因此只有在其他人无效的情况下才能使用.

  • 使用第三方总是不好的,你永远不知道第三方有多稳定。例如 - 解析。 (2认同)
  • 但它有局限性。他们的系统会自动禁止任何每分钟发出超过 150 个请求的 IP 地址。 (2认同)

Ebo*_*ike 35

首先,获取LocationManager.然后,打电话LocationManager.getLastKnownPosition.然后创建一个GeoCoder并调用GeoCoder.getFromLocation.这是一个单独的线程!! 这将为您提供一个Address对象列表.打电话Address.getCountryName,你明白了.

请记住,最后一个已知位置可能有点陈旧,因此如果用户刚刚越过边界,您可能暂时不知道它.

  • 但有一个问题是我们需要请求运行时权限才能访问 COARSE_LOCATION,对吧? (2认同)

Nat*_*tiv 14

这是一个基于LocationManager的完整解决方案,也是TelephonyManager和网络提供商位置的后备.我使用@Marco W.的上述答案作为后备部分(很好的答案本身!).

注意:代码包含PreferencesManager,这是一个帮助类,用于保存和加载SharedPrefrences中的数据.我正在使用它将国家保存到S"P,如果它是空的,我只会得到这个国家.对于我的产品,我并不真正关心所有边缘情况(用户出国旅行等等).

public static String getCountry(Context context) {
    String country = PreferencesManager.getInstance(context).getString(COUNTRY);
    if (country != null) {
        return country;
    }

    LocationManager locationManager = (LocationManager) PiplApp.getInstance().getSystemService(Context.LOCATION_SERVICE);
    if (locationManager != null) {
        Location location = locationManager
                .getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location == null) {
            location = locationManager
                    .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        }
        if (location == null) {
            log.w("Couldn't get location from network and gps providers")
            return
        }
        Geocoder gcd = new Geocoder(context, Locale.getDefault());
        List<Address> addresses;
        try {
            addresses = gcd.getFromLocation(location.getLatitude(),
                    location.getLongitude(), 1);

            if (addresses != null && !addresses.isEmpty()) {
                country = addresses.get(0).getCountryName();
                if (country != null) {
                    PreferencesManager.getInstance(context).putString(COUNTRY, country);
                    return country;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    country = getCountryBasedOnSimCardOrNetwork(context);
    if (country != null) {
        PreferencesManager.getInstance(context).putString(COUNTRY, country);
        return country;
    }
    return null;
}


/**
 * Get ISO 3166-1 alpha-2 country code for this device (or null if not available)
 *
 * @param context Context reference to get the TelephonyManager instance from
 * @return country code or null
 */
private static String getCountryBasedOnSimCardOrNetwork(Context context) {
    try {
        final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        final String simCountry = tm.getSimCountryIso();
        if (simCountry != null && simCountry.length() == 2) { // SIM country code is available
            return simCountry.toLowerCase(Locale.US);
        } else if (tm.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { // device is not 3G (would be unreliable)
            String networkCountry = tm.getNetworkCountryIso();
            if (networkCountry != null && networkCountry.length() == 2) { // network country code is available
                return networkCountry.toLowerCase(Locale.US);
            }
        }
    } catch (Exception e) {
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

  • 抱歉,您的答案确实需要重写.该代码包含许多无法使用的代码. (3认同)
  • 当然,我理解了逻辑,请不要误会。我注意到 PipplApp、PrefernecesManager 等可能已被删除,并且提供的解决方案对读者来说可能会更清楚一些。 (2认同)

Dav*_*ebb 13

您可以使用getNetworkCountryIso()fromTelephonyManager来获取手机当前所在的国家/地区(尽管这显然在CDMA网络上不可靠).


LCZ*_*LCZ 6

Java(Android 使用的)允许检索当前的 TZ(时区)数据库名称。尽管您的问题提到时区可能不够具体,但使用此方法,您可以获取用户的国家/地区(在某些情况下甚至是城市),而无需位置权限。

TZ 数据库名称示例:

Europe/Zurich显示用户在瑞士,同时Asia/Seoul显示用户在韩国。
(用户可能不在苏黎世或首尔,可能在其他州/省)
以下是所有可用 TZ 数据库时区的列表:https ://en.wikipedia.org/wiki/List_of_tz_database_time_zones

因此,您可以使用以下命令获取 TZ 数据库名称:

public String usersCountryByTzDbName() {
    return ZoneId.systemDefault().getId();
}
Run Code Online (Sandbox Code Playgroud)

您可以将这些映射到您选择的国家/地区。这种方法的优点:

  • 与其他人建议的不同context.getResources().getConfiguration().locale.getCountry(),无论用户的区域设置如何,这都可以工作。想象一下,如果用户居住在日本并将语言设置为en_US,您会检测到该用户位于美国而不是日本。
  • 适用于仅 Wi-Fi 的设备(如果您使用电话管理器 API,则该设备将不起作用)

参考:Java 8 - tz 数据库时区
请注意,根据此 SO 答案,TZ 数据库时区可能会不时发生变化,因此您应该期待以前未遇到过的新时区。此外,如果用户碰巧去另一个国家/地区旅行,则另一个国家/地区将反映在该方法中。

谢谢!


4gu*_*71n 5

String locale = context.getResources().getConfiguration().locale.getCountry(); 
Run Code Online (Sandbox Code Playgroud)

已弃用。改用这个:

Locale locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    locale = context.getResources().getConfiguration().getLocales().get(0);
} else {
    locale = context.getResources().getConfiguration().locale;
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*Gin 5

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

context.getResources().getConfiguration().locale.getDisplayCountry();
Run Code Online (Sandbox Code Playgroud)

会给出错误的值。所以这种方法是不可靠的

此外,TelephonyManager 的 getNetworkCountryIso() 方法不适用于没有 SIM 卡的设备(WIFI 平板电脑)。

如果设备没有 SIM 卡,那么我们可以使用时区来获取国家/地区。对于像印度这样的国家,这种方法会奏效

用于检查国家是否为印度的示例代码(时区 ID:asia/calcutta)

private void checkCountry() {


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

    int simState = telMgr.getSimState();

    switch (simState) {
        //if sim is not available then country is find out using 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 sim is available then telephony manager network country info is used
        case TelephonyManager.SIM_STATE_READY:

           TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
            if (tm != 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;

    }
}
Run Code Online (Sandbox Code Playgroud)