Де я? - Отримайте країну


126

Android-мобільний насправді дуже добре знає, де він знаходиться - але чи можна знайти країну чимось на зразок коду країни?

Не потрібно знати точну позицію GPS - країни достатньо

Я спершу подумав про використання часового поясу, але насправді мені потрібна додаткова інформація, ніж це, оскільки це має значення, якщо місце розташування - Нью-Йорк чи Ліма.

Передумови питання: у мене є програма, яка використовує значення температури, і я хотів би встановити за замовчуванням одиницю за Цельсієм або за Фаренгейтом, залежно від того, місце розташування знаходиться в США або за його межами.


14
-1: Ви напевне не хочете знати , де користувач знаходиться . Ви хочете знати налаштування місцевості користувача. Прийнята відповідь відповідає саме на це, але інакше тут абсолютно невідповідна, оскільки пошук вкаже тут людей, які насправді хочуть знати, де саме знаходиться користувач.
Ян Худек

Відповіді:


96

Тут буде встановлено код країни для телефону (мова телефонів, НЕ місцезнаходження користувача):

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

Ви також можете замінити getCountry () на getISO3Country (), щоб отримати 3- літерний ISO-код для країни. Це отримає назву країни :

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

Це здається простіше, ніж інші методи, і розраховувати на параметри локалізації на телефоні, тому, якщо американський користувач знаходиться за кордоном, вони, ймовірно, все ще хочуть Фаренгейта, і це спрацює :)

Примітка редакторів : Це рішення не має нічого спільного з розташуванням телефону. Це постійна. Під час подорожі до Німеччини місцевість НЕ зміниться. Якщо коротко: locale! = Розташування.


83
Це не працюватиме в країнах, для яких Android не має місцеположення. Наприклад, у Швейцарії мова, ймовірно, буде встановлена ​​на німецьку чи французьку. Цей метод дасть вам Німеччина чи Франція, а не Швейцарія. Краще використовувати підхід LocationManager або TelephonyManager.
MathewI

5
Не працює добре. Я маю розрізнити країну користувача для всіх країн Латинської Америки, усі тестуючі телефони повернулися до США, навіть коли телефон є англійською або іспанською мовою.
htafoya

21
Це не відповідає на назву питання. Я можу мати набір телефону англійською мовою і бути де завгодно в світі (моя рідна мова НЕ англійська, але я зробити у мене телефон встановлений в (British) на англійській мові. Це , однак , має відповідь на актуальне питання , тому що користувач хоче одиниць з нами , якщо він є американцем, де б він не був на даний момент.
Ян Худек


2
Загалом, це хороша відповідь, але вона лише повертає країну місцевості, а не фактичну країну.
ДСТ

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 ви отримаєте недійсне значення. Тож його корисність обмежена.
Брам

1
@Bram Це все, що можна отримати. Тож насправді це досить корисно. Проблема полягає лише в тому, що у вас немає інших надійних джерел даних, якщо у вас є планшет, лише WiFi.
каре

11
Зауважте, що якщо користувач із США відпочиває у Франції, getSimCountryIsoскаже usі getNetworkCountryIsoскажеfr
Тім

1
Ви можете змінити toLowerCase()дзвінок на toUpperCase().
toobsco42

Мені потрібен код не код Ім'я; Як і для США +1, а не для США
Shihab Uddin

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
Я не впевнений, що саме цього хотіла ОП, але мені все одно подобається відповідь.
JohnnyLambada

1
Як і відповідь, оскільки це також буде працювати на планшетах (без sim). Рішення телефонії працює лише на телефонах з активними сим-комами. Подвійні симфони - це ще один проблемний сценарій, оскільки вони можуть бути з різних країн. Тож, напевно, є більш сенс покладатися на рішення, згадане вище IP.
Маніш Катарія

1
Незважаючи на те, що, як ви вказали, це може бути не найкращим підходом до проблеми, воно фактично забезпечує правильне рішення. +1 від мене і дякую!
Маттео

1
Завжди погано користуватися сторонніми сторонами, ви ніколи не можете знати, наскільки стабільні вони. наприклад - Розбір.
Nativ

1
але це має обмеження. їх система автоматично забороняє будь-які IP-адреси, роблячи понад 150 запитів в хвилину.
Рам Мандал

62

Насправді я лише з’ясував, що існує ще один спосіб отримання коду країни, використовуючи метод getSimCountryIso () TelephoneManager:

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

Оскільки це сим-код, він також не повинен змінюватися під час подорожі до інших країн.


43
Це може не спрацювати, якщо на пристрої немає SIM-карти, наприклад планшетний ПК
thomasdao

38

По-перше, придбайте LocationManager. Потім, дзвоніть LocationManager.getLastKnownPosition. Потім створіть GeoCoder і зателефонуйте GeoCoder.getFromLocation. Зробіть це в окремій нитці !! Це дасть вам список Addressоб’єктів. Подзвони, Address.getCountryNameі ти його отримав.

Майте на увазі, що остання відома позиція може бути трохи несвіжою, тому якщо користувач щойно перейшов кордон, ви, можливо, про це не знаєте деякий час.


Для цієї програми зміна блоку за замовчуванням не буде бажаною при переміщенні країн, оскільки переваги користувача Цельсія або Фаренгейта не змінюватимуться, коли він вирушає до нових земель.
stealthcopter

Мені потрібно знати, в якій країні перебуває мій користувач для дзвінка API. Виклик повертає місця в околицях. Тому мене цікавить лише справжній код країни, у якого зараз знаходиться користувач. Просто, щоб зрозуміти, для чого може знадобитися вищевказаний підхід.
vinzenzweber

Це дуже низько оцінено анс, але факт у тому, що це найбільш надійне рішення. Більшість з вищезгаданих анс не працюють для Wi-Fi мережі. Той, який надає @shine_joseph, виглядає добре, але наданий файл не для комерційного використання.
Джем

Використовуйте обережно. Ваш пристрій надасть вам місцеположення, навіть якщо воно не є мережевим, але Geocoder зазвичай повертає нуль для масиву адрес, якщо Wi-Fi вимкнено, створюючи виняток, який вам потрібно буде спробувати / виловити.
Майк Крічлі

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

2
Звичайно, я зрозумів логіку, і, будь ласка, не сприймати її неправильно. Я маю на увазі, що PipplApp, PrefernecesManager тощо можна було б видалити, а пропоноване рішення може бути трохи зрозумілішим для читачів.
ichalos

@ichalos про PiplApp Я згоден на 100% з тобою, я просто видаляю його
Nativ

Є country = addresses.get(0).getCountryName();у вашому коді, що дозволить перевести повну назву країни в змінну country. Одночасно в методі getCountryBasedOnSimCardOrNetwork(Context context)ви повертаєте код ISO країни. Я вважаю, що ви хотіли написати country = addresses.get(0).getCountryCode();:-)
Фірцен

15

Ви можете використовувати getNetworkCountryIso()зTelephonyManager , щоб отримати країну телефон в даний час в (хоча , по- видимому , це ненадійно в мережах CDMA).


це звучить досить прямо вперед і добре працює на емуляторі спочатку - ви могли б просто пояснити, чому це ненадійно в мережах CDMA?
DonGru

ах гаразд, я це зрозумів - бо документація так говорить :)
DonGru

Через додаток це було б не найкращим рішенням, оскільки, коли користувач подорожує за кордон, його за замовчуванням зміниться. Було б більше сенсу мати статичний блок за замовчуванням, заснований на налаштуваннях місцевості телефонів, які потім, звичайно, можна десь змінити в налаштуваннях.
stealthcopter

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();

дасть неправильне значення. Тому цей метод не є надійним

Також метод getNetworkCountryIso () TelephonyManager не працюватиме на пристроях, на яких немає SIM-карти (WIFI-планшети).

Якщо на пристрої немає SIM-карти, ми можемо використовувати Time Zone, щоб отримати країну. Для таких країн, як Індія, цей метод буде працювати

зразок коду, який використовується для перевірки країни - це Індія чи ні (ідентифікатор часового поясу: 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 градусів меридіанів існує інший часовий пояс і т. Д.
Гунхань

3

Використовуючи GPS із широтою та довготою, ми можемо отримати код країни.

Якщо ми використовуємо телефонію, вона не спрацює, якщо ми не використовуємо сім-карту, а в локальній мові, виходячи з мови, вона показуватиме код країни неправильним чином.

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

}

Журнал:

E / countryCode: 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"}]}

ви можете завантажити файл autoload.php та .mmdb з https://dev.maxmind.com/geoip/geoip2/geolite2/

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
?>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.