我在哪里?-去乡村

Android 手机确实很清楚它的位置——但是有没有一种方法可以通过类似国家代码的东西来检索这个国家呢?

不需要知道确切的 GPS 位置-国家就足够了

我首先想到的是使用时区,但实际上我需要更多的信息,因为它使不同的位置是纽约还是利马。

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

130280 次浏览

首先,找到位置管理器。然后,拨打 LocationManager.getLastKnownPosition。然后创建一个 GeoCoder 并调用 GeoCoder.getFromLocation。这样做是在一个单独的线程! !这将为您提供 Address对象的列表。打电话给 Address.getCountryName就行了。

请记住,最后一个已知位置可能有点过时,所以如果用户刚刚越过边界,您可能在一段时间内不知道它。

您可以使用 ABC1呼叫 getNetworkCountryIso()来获得该手机目前所在的国家(尽管显然这在 CDMA 网络上是不可靠的)。

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

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

也可以将 getCountry ()替换为 GetISO3Country (),以获得该国家的3个字母的 ISO 代码。这将获得 国家名称:

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

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

编辑注释 : 此解决方案与手机的位置无关。它是恒定的。当你去德国旅行时,地点不会改变。简而言之: 地点!= 地点。

实际上,我刚刚发现还有一种获取国家代码的方法,那就是使用 TelephoneManager的 getSimCountryIso ()方法:

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

因为是 SIM 卡,所以在去其他国家旅行时也不应该更改。

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

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

注意 : 由于这是第三方解决方案,所以只有在其他人不工作时才使用。

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

注意: 代码包含 PreferencesManager,这是一个从 SharedPrefrances 保存和加载数据的助手类。我用它来拯救国家到 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;
}
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;
}

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

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;


}
}

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

TZ 数据库名称示例:

Europe/Zurich显示用户在瑞士,而 Asia/Seoul显示用户在韩国。
(用户可能分别不在苏黎世或首尔,也许在其他州/省)
下面是所有可用的 TZ 数据库时区的列表: < a href = “ https://en.wikipedia.org/wiki/List _ of _ TZ _ Database _ Time _ zone”rel = “ nofollow noReferrer”> https://en.wikipedia.org/wiki/list_of_tz_database_time_zones

因此,您可以使用以下方法获得 TZ 数据库名称:

public String usersCountryByTzDbName() {
return ZoneId.systemDefault().getId();
}

您可以将它们映射到您选择的国家。 这种方法的优点是:

  • 不像其他人所建议的 context.getResources().getConfiguration().locale.getCountry(),这种方法不管用户的区域设置如何都可以工作。想象一下,如果用户住在日本并将语言设置为 en_US,您将检测到用户在美国而不是日本。
  • 只能在 Wi-Fi 设备上工作(如果使用电话管理器 API 就无法工作)

参考资料: Java8-tz 数据库时区
请注意,根据这个 SO 答案,TZ 数据库时区可能会不时更改,因此您应该预期会遇到以前没有遇到过的新时区。此外,如果用户恰好前往另一个国家,那么这种方法将反映另一个国家。

谢谢!

如果你想知道用户位置的国家代码,如果你把他们的 IP 地址传递给 https://api.ipstack.com/134.201.250.155?access_key = YOUR _ ACCESS _ KEY,你会得到如下的响应:

{“ IP”: “134.201.250.155”,“类型”: “ ipv4”,“ Continental _ code”: “ NA”,“大陆代码”“大陆 _ 名称”: “北美”,“国家 _ 代码”: “美国”,“国家 _ 名称”: “美国”,“区域 _ 代码”: “纽约”,“Region _ name”: “ New York”,“ city”: “ New York”,“ zip”: “10013”,“纬度”: 40.7149,“经度”: -74.0052,“位置”: {“ geoname _ id”: 5128581,“资本”: “华盛顿特区。“语言”: [{“代码”: “ en”,“名称”: “英语”,“本地”: “英语”} ,{“代码”: “是”,“名字”: “西班牙”,“本地”: “西班牙语”} ,{。. } ],...} }

您首先需要从 ipstack.com 获得一个 API 密钥,他们为您提供了一个免费的 API 密钥,不需要信用卡详细信息就可以尝试使用。