Où suis-je? - Obtenez le pays

126

Un mobile Android sait en fait assez bien où il se trouve - mais existe-t-il un moyen de récupérer le pays par quelque chose comme un code de pays?

Pas besoin de connaître la position GPS exacte - le pays suffit

J'ai d'abord pensé à utiliser le fuseau horaire, mais en fait j'ai besoin de plus d'informations car cela fait une différence si l'emplacement est New York ou Lima.

Le contexte de la question: j'ai une application qui utilise des valeurs de température, et j'aimerais définir l'unité par défaut sur Celsius ou Fahrenheit, selon que l'emplacement est aux États-Unis ou à l'extérieur

DonGru
la source
14
-1: Vous ne voulez pas savoir où l'utilisateur est . Vous souhaitez connaître les paramètres régionaux de l'utilisateur. La réponse acceptée répond juste à cela, mais elle est par ailleurs totalement inappropriée ici, car la recherche pointera ici les personnes qui veulent réellement savoir où se trouve réellement l'utilisateur.
Jan Hudec

Réponses:

96

Cela obtiendra le code de pays défini pour le téléphone (langue du téléphone, PAS l'emplacement de l'utilisateur):

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

peut également remplacer getCountry () par getISO3Country () pour obtenir un code ISO de 3 lettres pour le pays. Cela obtiendra le nom du pays :

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

Cela semble plus facile que les autres méthodes et repose sur les paramètres de localisation du téléphone, donc si un utilisateur américain est à l'étranger, il veut probablement toujours Fahrenheit et cela fonctionnera :)

Note des éditeurs : cette solution n'a rien à voir avec l'emplacement du téléphone. C'est constant. Lorsque vous voyagez en Allemagne, les paramètres régionaux ne changeront PAS. En bref: locale! = Emplacement.

furtif
la source
83
Cela ne fonctionnera pas dans les pays pour lesquels Android n'a pas de paramètres régionaux. Par exemple, en Suisse, la langue est probablement définie sur l'allemand ou le français. Cette méthode vous donnera l'Allemagne ou la France, pas la Suisse. Mieux vaut utiliser l'approche LocationManager ou TelephonyManager.
MathewI
5
Ça ne marche pas bien. Je dois différencier le pays utilisateur pour tous les pays d'Amérique latine, tous les téléphones de test sont retournés aux États-Unis même lorsque le téléphone est en anglais ou en espagnol.
htafoya
21
Cela ne répond pas au titre de la question. Je peux avoir l'ensemble de téléphone à l' anglais et être partout dans le monde (ma langue maternelle est pas anglais, mais je n'ai mon jeu de téléphone (britannique) anglais. Il a toutefois ne répondre à la question réelle , parce que l' utilisateur veut les unités américaines si il est américain, où qu'il se trouve en ce moment.
Jan Hudec
2
Pas la solution faisable pour obtenir le nom du pays
Aamirkhan
2
C'est une bonne réponse en général, mais elle ne renvoie que le pays du lieu, pas le pays réel.
dst
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;
}
croasser
la source
14
Fonctionne uniquement sur les téléphones ou autres appareils dotés d'une carte SIM. Lors de l'utilisation sur une tablette WIFI, vous obtiendrez null. Son utilité est donc limitée.
Bram
1
@Bram C'est tout ce que vous pouvez obtenir. Donc c'est en fait assez utile, le problème est seulement que vous n'avez pas d'autres sources de données fiables si vous avez une tablette Wi-Fi uniquement.
caw du
11
Notez que si un utilisateur des États-Unis est en vacances en France, getSimCountryIsoil dira uset getNetworkCountryIsodirafr
Tim
1
Vous voudrez peut-être changer l' toLowerCase()appel en toUpperCase().
toobsco42
J'ai besoin du code et non du nom du code; Comme pour les États
Shihab Uddin
67

Utilisez ce lien http://ip-api.com/json , cela fournira toutes les informations sous forme de json. De ce json, vous pouvez obtenir le pays facilement. Ce site fonctionne en utilisant votre adresse IP actuelle, il détecte automatiquement l'adresse IP et les détails de renvoi.

Docs http://ip-api.com/docs/api:json J'espère que cela aide.

Exemple 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"
}

Remarque : comme il s'agit d'une solution tierce, utilisez uniquement si les autres ne fonctionnent pas.

shine_joseph
la source
1
Je ne suis pas sûr que ce soit exactement ce que voulait l'OP, mais j'aime vraiment la réponse de toute façon.
JohnnyLambada
1
Comme la réponse car cela fonctionnerait également sur les tablettes (sans sim). La solution de téléphonie fonctionne uniquement sur les téléphones dotés de sims actifs. Les téléphones à double carte SIM sont un autre scénario de problème car ils peuvent provenir de différents pays. Il est donc probablement plus logique de s'appuyer sur la solution IP mentionnée ci-dessus.
Manish Kataria du
1
Même si, comme vous l'avez souligné, ce n'est peut-être pas la meilleure approche du problème, elle fournit en fait une solution valable. +1 de moi et merci!
Matteo
1
Il est toujours mauvais de faire appel à des tiers, on ne peut jamais savoir à quel point ils sont stables. par exemple - Parse.
Nativ
1
mais il a des limites. leur système interdira automatiquement toute adresse IP faisant plus de 150 requêtes par minute.
Ram Mandal
62

En fait, je viens de découvrir qu'il existe encore un moyen d'obtenir un code de pays, en utilisant la méthode getSimCountryIso () de TelephoneManager:

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

Comme il s'agit du code SIM, il ne devrait pas non plus changer lors d'un voyage dans d'autres pays.

DonGru
la source
43
Cela peut ne pas fonctionner lorsque l'appareil n'a pas de carte SIM, par exemple une tablette
Thomasdao
38

Tout d'abord, récupérez le LocationManager. Ensuite, appelez LocationManager.getLastKnownPosition. Créez ensuite un GeoCoder et appelez GeoCoder.getFromLocation. Faites cela dans un fil séparé !! Cela vous donnera une liste d' Addressobjets. Appelez Address.getCountryNameet vous l'avez.

Gardez à l'esprit que la dernière position connue peut être un peu obsolète, donc si l'utilisateur vient de traverser la frontière, vous ne le saurez peut-être pas pendant un certain temps.

EboMike
la source
Pour cette application, il ne serait pas souhaitable de changer l'unité par défaut lors du déplacement de pays car la préférence de l'utilisateur de Celsius ou Fahrenheit ne changera pas à mesure qu'il s'aventure vers de nouvelles terres.
stealthcopter
J'ai besoin de savoir dans quel pays mon utilisateur se trouve pour un appel API. L'appel renvoie des emplacements dans les environs. Par conséquent, je ne suis intéressé que par le vrai code du pays dans lequel l'utilisateur se trouve actuellement. Juste pour donner un aperçu de ce pour quoi l'approche ci-dessus pourrait être nécessaire.
vinzenzweber
Ceci est très sous-évalué, mais le fait est que c'est la solution la plus fiable. La plupart des ans ci-dessus ne fonctionnent pas pour le réseau wifi. Celui fourni par @shine_joseph a l'air bien mais l'API fournie n'est pas à usage commercial.
Gem
Utiliser avec précaution. Votre appareil vous donnera un emplacement même s'il n'est pas en réseau, mais le géocodeur renverra généralement une valeur nulle pour le tableau d'adresses si le wifi est désactivé, soulevant une exception que vous devrez essayer / attraper.
Mike Critchley
17

Voici une solution complète basée sur le LocationManager et en tant que solutions de secours, le TelephonyManager et les emplacements du fournisseur de réseau. J'ai utilisé la réponse ci-dessus de @Marco W. pour la partie de secours (excellente réponse en soi!).

Remarque: le code contient PreferencesManager, il s'agit d'une classe d'assistance qui enregistre et charge les données de SharedPrefrences. Je l'utilise pour enregistrer le pays en S "P, je ne reçois le pays que s'il est vide. Pour mon produit, je ne me soucie pas vraiment de tous les cas marginaux (l'utilisateur voyage à l'étranger, etc.).

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;
}
Nativ
la source
4
Désolé, mais votre réponse doit vraiment être réécrite. Le code contient beaucoup de code inutilisable.
ichalos
@ichalos ou vous n'avez pas compris la logique. Veuillez me donner 1 exemple de code inutilisé dans cet extrait
Nativ
2
Bien sûr, j'ai compris la logique et je vous en prie, ne la prenez pas mal. Je mentionne que PipplApp, PrefernecesManager, etc. auraient pu être supprimés et que la solution proposée pourrait être un peu plus claire pour les lecteurs.
ichalos
@ichalos à propos de PiplApp Je suis d'accord à 100% avec vous, je viens de le supprimer
Nativ
Il y a country = addresses.get(0).getCountryName();dans votre code, qui mettra le nom complet du pays dans la variable country. Dans le même temps, getCountryBasedOnSimCardOrNetwork(Context context)vous renvoyez le code ISO du pays. Je crois que tu voulais écrire country = addresses.get(0).getCountryCode();:-)
Firzen
15

Vous pouvez utiliser getNetworkCountryIso()fromTelephonyManager pour obtenir le pays dans lequel se trouve actuellement le téléphone (bien que cela ne soit apparemment pas fiable sur les réseaux CDMA).

Dave Webb
la source
cela semble assez simple et a bien fonctionné à l'émulateur en premier lieu - pourriez-vous simplement expliquer pourquoi il n'est pas fiable sur les réseaux CDMA?
DonGru
ah ok, je l'ai - parce que la documentation le dit :)
DonGru
En raison de l'application, ce ne serait pas la meilleure solution, car lorsqu'un utilisateur voyage à l'étranger, son unité par défaut changerait. Il serait plus judicieux d'avoir une unité statique par défaut basée sur les paramètres régionaux du téléphone, qui peuvent alors bien sûr être modifiés dans un paramètre quelque part.
stealthcopter
5
String locale = context.getResources().getConfiguration().locale.getCountry(); 

Est obsolète. Utilisez plutôt ceci:

Locale locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    locale = context.getResources().getConfiguration().getLocales().get(0);
} else {
    locale = context.getResources().getConfiguration().locale;
}
4gus71n
la source
1
Nécessite-t-il une autorisation et quel pays est-il indiqué?
CoolMind
4

Pour certains appareils, si la langue par défaut est différente (un Indien peut définir l'anglais (US)), alors

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

donnera une valeur erronée .Cette méthode n'est donc pas fiable

De plus, la méthode getNetworkCountryIso () de TelephonyManager ne fonctionnera pas sur les appareils qui n'ont pas de carte SIM (tablettes WIFI).

Si un appareil n'a pas de carte SIM, nous pouvons utiliser le fuseau horaire pour obtenir le pays. Pour des pays comme l'Inde, cette méthode fonctionnera

exemple de code utilisé pour vérifier si le pays est l'Inde ou non (ID de fuseau horaire: 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;

    }
}
Marge
la source
1
belle idée mais le fuseau horaire n'est pas une fonction spécifique au pays, vous le savez, non? Pour chaque 15 degrés de méridiens, il y a un autre fuseau horaire, etc.
Gunhan
3

En utilisant le GPS avec latitude et longitude, nous pouvons obtenir le code du pays.

Si nous utilisons la téléphonie, cela ne fonctionnera pas si nous n'utilisons pas de carte SIM et dans les paramètres régionaux, en fonction de la langue, il affiche le code du pays de manière incorrecte.

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

}

Journal:

E / countryCode: IN

Modifier: utilisez le fournisseur d'emplacement fusionné pour obtenir la mise à jour de la latitude et de la longitude pour un meilleur résultat

Steve
la source
Qu'est-ce que gpsParty ()? Il n'est pas défini
Nikola C
-2

J'ai utilisé GEOIP db et créé une fonction. Vous pouvez utiliser ce lien directement 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"}]}

vous pouvez télécharger le fichier autoload.php et .mmdb à partir de 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
?>
arun-r
la source