Dove sono? - Prendi il paese


126

Un cellulare Android in realtà sa abbastanza bene dove si trova - ma c'è un modo per recuperare il paese con qualcosa come un codice paese?

Non c'è bisogno di conoscere l'esatta posizione GPS: il paese è sufficiente

Ho pensato per la prima volta di utilizzare il fuso orario, ma in realtà ho bisogno di più informazioni rispetto a ciò poiché fa la differenza se la posizione è New York o Lima.

Lo sfondo della domanda: ho un'applicazione che utilizza i valori di temperatura e vorrei impostare l'unità predefinita su Celsius o Fahrenheit, a seconda che la posizione sia statunitense o esterna


14
-1: Sicuramente non si vuole sapere dove l'utente è . Vuoi conoscere le impostazioni locali dell'utente. La risposta accettata risponde proprio a questo, ma per il resto è del tutto inappropriata qui, perché la ricerca punterà le persone qui che vogliono effettivamente sapere dove si trova l'utente.
Jan Hudec,

Risposte:


96

Verrà impostato il prefisso del paese per il telefono (lingua dei telefoni, NON posizione dell'utente):

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

può anche sostituire getCountry () con getISO3Country () per ottenere un codice ISO di 3 lettere per il paese. Questo otterrà il nome del paese :

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

Questo sembra più facile degli altri metodi e si basa sulle impostazioni di localizzazione sul telefono, quindi se un utente americano è all'estero probabilmente vorrebbe comunque Fahrenheit e questo funzionerà :)

Nota dell'editore: questa soluzione non ha nulla a che fare con la posizione del telefono. È costante. Quando viaggi in Germania, le impostazioni internazionali NON cambieranno. In breve: locale! = Location.


83
Questo non funzionerà nei paesi in cui Android non ha impostazioni locali. Ad esempio, in Svizzera è probabile che la lingua sia impostata su tedesco o francese. Questo metodo ti darà Germania o Francia, non Svizzera. Meglio usare l'approccio LocationManager o TelephonyManager.
Matteo

5
Non funziona bene Devo differenziare il paese dell'utente per tutti i paesi dell'America Latina, tutti i telefoni di prova sono tornati negli Stati Uniti anche quando il telefono è in lingua inglese o spagnola.
htafoya,

21
Questo non risponde al titolo della domanda. Forse ho il set telefono a inglese ed essere ovunque nel mondo (la mia lingua madre è non inglese, ma io fare il mio insieme di telefono a (britannico) inglese. E tuttavia non rispondere alla domanda effettiva , in quanto l'utente vuole unità degli Stati Uniti se è americano, ovunque si trovi effettivamente al momento.
Jan Hudec,

2
Non è la soluzione fattibile per ottenere il nome del Paese
Aamirkhan,

2
È una buona risposta in generale, ma restituisce solo il paese della locale, non il paese reale.
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;
}

14
Funziona solo su telefoni o altri dispositivi con una scheda SIM. Quando si utilizza su un tablet WIFI, si ottiene null. Quindi la sua utilità è limitata.
Bram,

1
@Bram Questo è tutto ciò che puoi ottenere. Quindi in realtà è abbastanza utile, il problema è solo che non hai altre fonti di dati affidabili se hai un tablet solo WiFi.
caw

11
Se un utente dagli Stati Uniti è in vacanza in Francia, getSimCountryIsodirà use getNetworkCountryIsodiràfr
Tim

1
Potresti voler cambiare la toLowerCase()chiamata a toUpperCase().
toobsco42

Ho bisogno del codice, non del nome del codice; Come per gli Stati Uniti +1 non gli Stati Uniti
Shihab Uddin

67

Usa questo link http://ip-api.com/json , questo fornirà tutte le informazioni come json. Da questo json puoi ottenere facilmente il paese. Questo sito funziona utilizzando il tuo IP attuale, rileva automaticamente l'IP e i dettagli di invio.

Documenti http://ip-api.com/docs/api:json Spero che sia d'aiuto.

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

nota : poiché si tratta di una soluzione di terze parti, utilizzare solo se gli altri non hanno funzionato.


1
Non sono sicuro che questo fosse esattamente ciò che l'OP voleva, ma mi piace molto comunque la risposta.
JohnnyLambada,

1
Come la risposta, poiché funzionerebbe anche su tablet (senza sim). La soluzione di telefonia funziona solo su telefoni con sim attive. I telefoni con doppia SIM sono un altro scenario problematico in quanto potrebbero provenire da paesi diversi. Quindi probabilmente ha più senso fare affidamento sulla soluzione IP menzionata sopra.
Manish Kataria,

1
Anche se, come hai sottolineato, questo potrebbe non essere l'approccio migliore al problema, in realtà fornisce una soluzione valida. +1 da parte mia e grazie!
Matteo,

1
È sempre male usare terze parti, non puoi mai sapere quanto siano stabili. per esempio - Parse.
Nativ,

1
ma ha dei limiti. il loro sistema bandirà automaticamente tutti gli indirizzi IP che fanno oltre 150 richieste al minuto.
Ram Mandal,

62

In realtà ho appena scoperto che esiste anche un altro modo per ottenere un codice paese, usando il metodo getSimCountryIso () di TelephoneManager:

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

Dal momento che è il codice sim non dovrebbe cambiare anche quando si viaggia in altri paesi.


43
Questo potrebbe non funzionare quando il dispositivo non ha una scheda SIM, ad esempio tablet
thomasdao

38

Innanzitutto, procurati il ​​LocationManager. Quindi chiama LocationManager.getLastKnownPosition. Quindi creare un GeoCoder e chiamare GeoCoder.getFromLocation. Fare questo è in un thread separato !! Questo ti darà un elenco di Addressoggetti. Chiama Address.getCountryNamee hai capito.

Tieni presente che l'ultima posizione nota può essere un po 'stantia, quindi se l'utente ha appena attraversato il bordo, potresti non conoscerlo per un po'.


Per questa applicazione non sarebbe desiderabile cambiare l'unità predefinita quando si spostano i paesi poiché le preferenze dell'utente in gradi Celsius o Fahrenheit non cambieranno mentre si avventura in nuove terre.
stealthcopter

Devo sapere in quale paese è il mio utente per una chiamata API. La chiamata restituisce posizioni nell'area circostante. Pertanto sono interessato solo al codice paese reale in cui si trova l'utente in questo momento. Giusto per dare un'idea di cosa potrebbe essere necessario l'approccio di cui sopra.
Vinzenzweber

Questo è molto sottovalutato, ma il fatto è che questa è la soluzione più affidabile. La maggior parte delle risposte precedenti non funziona per la rete wifi. Quello fornito da @shine_joseph sembra buono ma l'API fornito non è per uso commerciale.
Gemma

Usare con cautela. Il tuo dispositivo ti darà una posizione anche se non in rete, ma il Geocoder restituirà normalmente un valore nullo per l'array di indirizzi se il wifi è disattivato, sollevando un'eccezione che dovrai provare / catturare.
Mike Critchley l'

17

Ecco una soluzione completa basata sul LocationManager e come fallback del TelephonyManager e delle posizioni del provider di rete. Ho usato la risposta sopra di @Marco W. per la parte di fallback (ottima risposta come se stessa!).

Nota: il codice contiene PreferencesManager, questa è una classe di supporto che salva e carica i dati da SharedPrefrences. Lo sto usando per salvare il paese in S "P, sto ottenendo il paese solo se è vuoto. Per il mio prodotto non mi importa davvero di tutti i casi limite (l'utente viaggia all'estero e così via).

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
Ci dispiace, ma la tua risposta deve davvero essere riscritta. Il codice contiene molti codici inutilizzabili.
ichalos,

@ichalos o non hai capito la logica. Per favore, dammi 1 esempio di codice inutilizzato in questo frammento
Nativ,

2
Ovviamente non capisco la logica e per favore non prenderla nel modo sbagliato. Cito che PipplApp, PrefernecesManager ecc. Potrebbero essere stati rimossi e la soluzione offerta potrebbe essere un po 'più chiara per i lettori.
ichalos,

@ichalos a proposito di PiplApp Sono d'accordo al 100% con te, lo rimuovo e basta
Nativ

C'è country = addresses.get(0).getCountryName();nel tuo codice, che metterà il nome completo del paese in variabile country. Allo stesso tempo, nel metodo getCountryBasedOnSimCardOrNetwork(Context context)stai restituendo il codice ISO del paese. Credo che tu abbia voluto scrivere country = addresses.get(0).getCountryCode();:-)
Firzen

15

Si potrebbe utilizzare getNetworkCountryIso()daTelephonyManager raggiungere il paese il telefono è attualmente in (anche se a quanto pare questo non è affidabile su reti CDMA).


sembra piuttosto semplice e ha funzionato bene all'emulatore in prima istanza - potresti semplicemente spiegare perché non è affidabile sulle reti CDMA?
DonGru,

ah va bene, l'ho capito - perché la documentazione dice così :)
DonGru

A causa dell'applicazione, questa non sarebbe la soluzione migliore poiché quando un utente viaggia all'estero la sua unità predefinita cambierebbe. Avrebbe più senso disporre di un'unità statica predefinita basata sulle impostazioni locali del telefono, che ovviamente può essere modificata in un'impostazione da qualche parte.
stealthcopter

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

È deprecato. Usa questo invece:

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
Richiede l'autorizzazione e quale paese mostra?
CoolMind

4

Per alcuni dispositivi, se la lingua predefinita è impostata diversamente (un indiano può impostare l'inglese (USA))

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

darà un valore errato. Quindi questo metodo non è affidabile

Inoltre, il metodo getNetworkCountryIso () di TelephonyManager non funziona su dispositivi che non dispongono di una scheda SIM (tablet WIFI).

Se un dispositivo non ha una SIM, possiamo usare il fuso orario per ottenere il Paese. Per paesi come l'India, questo metodo funzionerà

codice di esempio utilizzato per verificare che il Paese sia l'India o meno (ID fuso orario: 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
bella idea ma il fuso orario non è una funzionalità specifica per paese, lo sai vero? Per ogni 15 gradi di meridiani esiste un altro fuso orario ecc.
Gunhan,

3

Usando il GPS con latitudine e longitudine, possiamo ottenere il codice Paese.

Se utilizziamo la telefonia, non funzionerà se non stiamo utilizzando la scheda SIM e nelle impostazioni locali, in base alla lingua, mostra il codice paese in modo errato.

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

}

log:

E / countryCode: IN

Modifica: utilizzare il fornitore di posizione fuso per ottenere l'aggiornamento di latitudine e longitudine per un risultato migliore.


Che cos'è gpsParty ()? Non è definito
Nikola C,

-2

Ho usato GEOIP db e ho creato una funzione. Puoi utilizzare questo link direttamente 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"}]}

puoi scaricare autoload.php e il file .mmdb da 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
?>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.