我在哪里?-获取国家


126

安卓手机实际上确实知道它在哪里-但是有没有办法通过国家代码检索国家?

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

我最初想到使用时区,但实际上我需要的信息更多,因为如果位置在纽约或利马,这会有所不同。

问题的背景:我有一个使用温度值的应用程序,并且我想将默认单位设置为摄氏还是华氏度,具体取决于位置是美国还是国外。


14
-1:你肯定不想知道用户。您想知道用户的语言环境设置。接受的答案只能回答这个问题,但是在这里否则是完全不合适的,因为搜索将把真正想要知道用户实际位置的人指向此处。
2013年

Answers:


96

这将为电话设置国家代码(电话语言,而不是用户位置):

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

也可以将getCountry()替换为getISO3Country()以获取该国家/地区的3个字母的ISO代码。这将获得国家名称

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

这似乎比其他方法更容易,并且依赖于电话上的本地化设置,因此,如果美国用户在国外,他们可能仍需要华氏温度,这样就可以了:)

编者注:此解决方案与手机的位置无关。它是恒定的。当您旅行到德国时,语言环境不会改变。简而言之:locale!= location。


83
这在Android没有语言环境的国家/地区无法使用。例如,在瑞士,语言可能设置为德语或法语。这种方法会给您德国或法国,而不是瑞士。最好使用LocationManager或TelephonyManager方法。
MathewI

5
运作不正常。我必须区分所有拉丁美洲国家/地区的用户国家/地区,即使测试电话是英语或西班牙语,所有测试电话都已返回美国。
htafoya 2012年

21
不能回答问题标题。我可能有电话设置为英语,并约在世界任何地方(我的母语是不是英语,但我做的有我的手机设置为(英国)英语。但是,由于它不回答实际问题,因为用户希望美国单位如果他现在是美国人,无论他现在碰巧在哪儿
Jan Hudec

2
不是获得国家名称的可行解决方案
Aamirkhan 2014年

2
通常,这是一个很好的答案,但它只会返回语言环境的国家/地区,而不是实际的国家/地区。
dst 2014年

138
/**
 * 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;
}

14
仅适用于带有SIM卡的电话或其他设备。在WIFI平板电脑上使用时,您将得到null。因此其用途是有限的。
布拉姆(Bram)2015年

1
@Bram这就是您所能获得的。因此,它实际上非常有用,问题仅在于如果您拥有仅WiFi平板电脑,那么您就没有其他可靠的数据源。
caw 2015年

11
请注意,如果来自美国的用户正在法国度假,他getSimCountryIso会说,us并且getNetworkCountryIso会说fr
Tim

1
您可能需要将toLowerCase()呼叫更改为toUpperCase()
toobsco42

我需要代码而不是代码名称;像美国+1不是美国
谢哈布·乌丁

67

使用此链接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"
}

注意:由于这是第三方解决方案,因此仅在其他人无法使用时才使用。


1
我不确定这是否是OP想要的,但是无论如何,我真的很喜欢这个答案。
JohnnyLambada 2015年

1
像答案一样,因为这也适用于平板电脑(没有sim)。电话解决方案仅适用于具有有效SIM卡的电话。双SIM卡手机是另一个问题,因为它们可能来自不同的国家。因此,依靠上述IP解决方案可能更有意义。
Manish Kataria 2015年

1
即使您已经指出,这可能不是解决问题的最佳方法,但实际上它提供了有效的解决方案。向我+1,谢谢!
Matteo

1
使用第三方总是不好的,您永远不知道那里有多稳定。例如-解析。
Nativ

1
但它有局限性。他们的系统将自动禁止每分钟执行超过150个请求的任何IP地址。
Ram Mandal

62

实际上,我刚刚发现,使用以下方法的getSimCountryIso()方法可以获得国家代码的另一种方法TelephoneManager

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String countryCode = tm.getSimCountryIso();

由于它是SIM卡代码,因此到其他国家旅行时也不应更改。


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

38

首先,获取LocationManager。然后,致电LocationManager.getLastKnownPosition。然后创建一个GeoCoder并调用GeoCoder.getFromLocation。这样做是在单独的线程中!这将为您提供Address对象列表。打电话Address.getCountryName就知道了。

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


对于此应用程序,在移动国家/地区时不需要更改默认单位,因为用户冒险进入新土地时,摄氏或华氏度的用户偏好不会改变。
隐身直升机

我需要知道我的用户在哪个国家/地区进行API调用。呼叫返回周围区域的位置。因此,我只对用户当前所在的真实国家/地区代码感兴趣。只是为了了解上述方法可能需要做什么。
vinzenzweber 2011年

这是远远低于额定的ans,但事实是这是最可靠的解决方案。上面的大多数ans不适用于wifi网络。@shine_joseph提供的一个看起来不错,但是提供的api不能用于商业用途。
宝石

请谨慎使用。即使未联网,您的设备也会为您提供一个位置,但是如果wifi处于关闭状态,则Geocoder通常会为地址数组返回null,从而引发异常,您需要尝试/捕获。
Mike Critchley

17

这是一个基于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;
}

4
抱歉,您的答案确实需要重写。该代码包含许多无法使用的代码。
ichalos

@ichalos或您不了解其逻辑。请在此代码段中给我1个未使用代码的示例
Nativ,2017年

2
当然,我并没有弄清楚逻辑,请不要误解。我注意到PipplApp,PrefernecesManager等可能已被删除,并且所提供的解决方案对于读者来说可能更清楚。
ichalos

关于PiplApp的@ichalos我同意您的100%,我只是删除了它
Nativ

country = addresses.get(0).getCountryName();在你的代码,这将对全名国门,走向变量country。同时在方法中,getCountryBasedOnSimCardOrNetwork(Context context)您将返回国家的ISO代码。我相信您想写country = addresses.get(0).getCountryCode();:-)
菲尔岑(Firzen)

15

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


这听起来很简单,并且在一开始就可以在仿真器上很好地工作-您能解释一下为什么它在CDMA网络上不可靠吗?
DonGru 2010年

嗯,知道了-因为文档中是这样的:)
DonGru 2010年

由于应用程序的原因,这并不是最佳解决方案,因为当用户出国旅行时,其默认单位会发生变化。基于电话的语言环境设置具有静态默认单位会更有意义,然后可以在某个地方的设置中对其进行更改。
secretthcopter

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

已弃用。使用此代替:

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

1
是否需要许可?显示在哪个国家?
CoolMind

4

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

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

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

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

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

用于检查国家/地区是否为印度的示例代码(时区标识: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;

    }
}

1
不错,但是时区不是特定于国家/地区的功能,您知道吗?每15度子午线就有一个时区,等等
。– Gunhan

3

使用具有经度和纬度的GPS,我们可以获得国家代码。

如果我们使用电话,如果我们不使用SIM卡,并且在语言环境中使用语言,则会显示错误的国家/地区代码,则该电话将无法正常工作。

MainActivity.java:

    GPSTracker gpsTrack;
    public static double latitude = 0;
    public static double longitude = 0;

    gpsTrack = new GPSTracker(TabHomeActivity.this);

        if (gpsTrack.canGetLocation()) {
            latitude = gpsParty.getLatitude();
            longitude = gpsParty.getLongitude();

            Log.e("GPSLat", "" + latitude);
            Log.e("GPSLong", "" + longitude);

        } else {
            gpsTrack.showSettingsAlert();

            Log.e("ShowAlert", "ShowAlert");

        }

        countryCode = getAddress(TabHomeActivity.this, latitude, longitude);

        Log.e("countryCode", ""+countryCode);

   public String getAddress(Context ctx, double latitude, double longitude) {
    String region_code = null;
    try {
        Geocoder geocoder = new Geocoder(ctx, Locale.getDefault());
        List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
        if (addresses.size() > 0) {
            Address address = addresses.get(0);


            region_code = address.getCountryCode();


        }
    } catch (IOException e) {
        Log.e("tag", e.getMessage());
    }

    return region_code;
}

GPSTracker.java:

import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;

public class GPSTracker extends Service implements LocationListener {

    private final Context mContext;

    // flag for GPS status
    boolean isGPSEnabled = false;

    // flag for network status
    boolean isNetworkEnabled = false;

    // flag for GPS status
    boolean canGetLocation = false;

    Location location; // location
    double latitude; // latitude
    double longitude; // longitude

    // The minimum distance to change Updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters

    // The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute

    // Declaring a Location Manager
    protected LocationManager locationManager;

    public GPSTracker(Context context) {
        this.mContext = context;
        getLocation();
    }

    public Location getLocation() {
        try {
            locationManager = (LocationManager) mContext
                    .getSystemService(LOCATION_SERVICE);

            // getting GPS status
            isGPSEnabled = locationManager
                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

            // getting network status
            isNetworkEnabled = locationManager
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {
                // no network provider is enabled
            } else {
                this.canGetLocation = true;
                // First get location from Network Provider
                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    Log.d("Network", "Network");
                    if (locationManager != null) {
                        location = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                        }
                    }
                }
                // if GPS Enabled get lat/long using GPS Services
                if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        Log.d("GPS Enabled", "GPS Enabled");
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }

    /**
     * Stop using GPS listener
     * Calling this function will stop using GPS in your app
     * */
    public void stopUsingGPS(){
        if(locationManager != null){
            locationManager.removeUpdates(GPSTracker.this);
        }
    }

    /**
     * Function to get latitude
     * */
    public double getLatitude(){
        if(location != null){
            latitude = location.getLatitude();
        }

        // return latitude
        return latitude;
    }

    /**
     * Function to get longitude
     * */
    public double getLongitude(){
        if(location != null){
            longitude = location.getLongitude();
        }

        // return longitude
        return longitude;
    }

    /**
     * Function to check GPS/wifi enabled
     * @return boolean
     * */
    public boolean canGetLocation() {
        return this.canGetLocation;
    }



    public void showSettingsAlert() {
        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
                .setCancelable(false)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
                        mContext.startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                    }
                })
                .setNegativeButton("No", new DialogInterface.OnClickListener() {
                    public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
                        dialog.cancel();
                    }
                });
        final AlertDialog alert = builder.create();
        alert.show();
    }

    @Override
    public void onLocationChanged(Location location) {
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

}

日志:

电子/国家/地区代码: IN

编辑:使用融合位置提供程序获取经度和纬度更新以获得更好的结果。


什么是gpsParty()?未定义
Nikola C

-2

我使用了GEOIP db并创建了一个函数。您可以直接使用此链接 http://jamhubsoftware.com/geoip/getcountry.php

{"country":["India"],"isoCode":["IN"],"names":[{"de":"Indien","en":"India","es":"India","fr":"Inde","ja":"\u30a4\u30f3\u30c9","pt-BR":"\u00cdndia","ru":"\u0418\u043d\u0434\u0438\u044f","zh-CN":"\u5370\u5ea6"}]}

您可以从https://dev.maxmind.com/geoip/geoip2/geolite2/下载autoload.php和.mmdb文件

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$ip_address = $_SERVER['REMOTE_ADDR'];
//$ip_address = '3.255.255.255';

require_once 'vendor/autoload.php';

use GeoIp2\Database\Reader;

// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader('/var/www/html/geoip/GeoLite2-City.mmdb');

// Replace "city" with the appropriate method for your database, e.g.,
// "country".
$record = $reader->city($ip_address);

//print($record->country->isoCode . "\n"); // 'US'
//print($record->country->name . "\n"); // 'United States'
$rows['country'][] = $record->country->name;
$rows['isoCode'][] = $record->country->isoCode;
$rows['names'][] = $record->country->names;
print json_encode($rows);
//print($record->country->names['zh-CN'] . "\n"); // '美国'
//
//print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
//print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
//
//print($record->city->name . "\n"); // 'Minneapolis'
//
//print($record->postal->code . "\n"); // '55455'
//
//print($record->location->latitude . "\n"); // 44.9733
//print($record->location->longitude . "\n"); // -93.2323
?>
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.