Wie kann ich den Ländercode meines Android-Geräts ohne GPS abrufen?

71

Ein Android-Handy weiß eigentlich ganz genau, wo es sich befindet - aber gibt es eine Möglichkeit, das Land anhand eines Ländercodes oder eines Ländernamens abzurufen?

Es ist nicht erforderlich, die genaue GPS-Position zu kennen - der Ländercode oder Name ist ausreichend, und ich verwende diesen Code:

 String locale = context.getResources().getConfiguration().locale.getCountry(Locale.getDefault());
 System.out.println("country = "+locale);

Es gibt mir den Code "US", aber mein Gerät wird in Indien aufbewahrt. Gibt es eine Möglichkeit, den aktuellen Ländercode des Geräts zu finden, ohne GPS oder einen Netzwerkanbieter zu verwenden?

Weil ich ein Tablet benutze.

Vikas Goyal
quelle

Antworten:

93

Sie sollten nichts weitergeben getCountry(). Entfernen Locale.getDefault():

String locale = context.getResources().getConfiguration().locale.getCountry();
Rawkode
quelle
98
Dadurch wird das Land des Gebietsschemas zurückgegeben, das der Benutzer konfiguriert hat. Wenn der Benutzer das Gerät für Indien konfiguriert und es dann in einem Flugzeug nach Deutschland nimmt, erhalten Sie weiterhin die Landesvorwahl für Indien. Ich dachte nur, ich würde das klarstellen.
David Wasser
1
Ich lebe in Belgien und mein Gerät ist in Englisch / USA, ich bin nicht sicher, ob dieser Code das Land geben wird
;-)
1
Gibt es eine Chance, egal wie schlank dieser Aufruf "" oder null zurückgibt? Keine tatsächliche Landesvorwahl?
Skorpion
9
Dies wurde in API Level 24 veraltet.
Egemen Hamutçu
1
@ EgemenHamutçu können Sie Configuration # getLocales oder praktischer ConfigurationCompat # getLocales
androidguy
88

Sie können einfach diesen Code verwenden,

TelephonyManager tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String countryCodeValue = tm.getNetworkCountryIso();

Dies gibt "US" zurück, wenn sich Ihr derzeit verbundenes Netzwerk in den USA befindet. Dies funktioniert auch ohne SIM-Karte.

Kishath
quelle
Gute Antwort. Scheint zuverlässiger zu sein als in der Konfiguration festgelegt
Itai Hanski
Das Telefon sollte eine Verbindungsquelle haben. Ist WiFi eingeschaltet?
Kishath
5
Es funktioniert nicht für Geräte ohne SIM-Karten oder Tablet, die nur in Wifi funktionieren
Alberto Anderick Jr
6
Alle TelephonyManager erforderlichen Berechtigungen developer.android.com/reference/android/telephony/…
Ben.Slama.Jihed
1
@ Ben.Slama.Jihed Nicht alle. In dem von Ihnen genannten Dokument heißt es: "Beachten Sie, dass der Zugriff auf einige Telefonieinformationen durch Berechtigungen geschützt ist." Und ich denke, getNetworkCountryIso()erfordert keine zusätzliche Erlaubnis.
Twisted Lullaby
52

Verwenden Sie den Link http://ip-api.com/json . Dadurch werden alle Informationen als JSON bereitgestellt. Mit diesem JSON-Inhalt können Sie das Land leicht abrufen. Diese Seite funktioniert mit Ihrer aktuellen IP-Adresse. Es erkennt automatisch die IP-Adresse und die Sendback-Details.

Dokumentation

Das habe ich bekommen:

{
"as": "AS55410 C48 Okhla Industrial Estate, New Delhi-110020",
"city": "Kochi",
"country": "India",
"countryCode": "IN",
"isp": "Vodafone India",
"lat": 9.9667,
"lon": 76.2333,
"org": "Vodafone India",
"query": "123.63.81.162",
"region": "KL",
"regionName": "Kerala",
"status": "success",
"timezone": "Asia/Kolkata",
"zip": ""
}

Hinweis: Da es sich um eine Drittanbieter-API handelt, verwenden Sie sie nicht als primäre Lösung. Und ich bin mir auch nicht sicher, ob es kostenlos ist oder nicht.

schein_joseph
quelle
@ KhizarHayat mit einem einfachen Restfull API-Aufruf
Hamzeh Soboh
Wird dies auch bei Verwendung von VPN das richtige Land liefern?
Vivek Mishra
1
Aha! Ich liege hier auf meinem Sofa in Moskau, Russland, und es gibt mir {"as": "AS15169 Google LLC", "city": "Ashburn", "country": "United States", "countryCode": " US "," isp ":" Google LLC "," lat ": 39.0438," lon ": - 77.4874," org ":" Google LLC "," query ":" 66.102.9.142 "," region ":" VA "," regionName ":" Virginia "," status ":" success "," timezone ":" America / New_York "," zip ":" 20149 "}
Eugene Kartoyev
11

Die überprüfte Antwort hat veralteten Code. Sie müssen dies implementieren:

String locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    locale = context.getResources().getConfiguration().getLocales().get(0).getCountry();
} else {
    locale = context.getResources().getConfiguration().locale.getCountry();
}
Egemen Hamutçu
quelle
2
Dies gibt immer US
Krunal Shah
1
Jip, ich lebe in Südafrika, alle meine Geräte sind standardmäßig auf US eingestellt
Pierre
7

Hier ist ein vollständiges Beispiel. Es wird versucht, den Ländercode von TelephonyManager (von SIM- oder CDMA-Geräten) abzurufen. Wenn er nicht verfügbar ist, wird versucht, ihn von der lokalen Konfiguration abzurufen.

private static String getDeviceCountryCode(Context context) {
    String countryCode;

    // Try to get country code from TelephonyManager service
    TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    if(tm != null) {
        // Query first getSimCountryIso()
        countryCode = tm.getSimCountryIso();
        if (countryCode != null && countryCode.length() == 2)
            return countryCode.toLowerCase();

        if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
            // Special case for CDMA Devices
            countryCode = getCDMACountryIso();
        }
        else {
            // For 3G devices (with SIM) query getNetworkCountryIso()
            countryCode = tm.getNetworkCountryIso();
        }

        if (countryCode != null && countryCode.length() == 2)
            return countryCode.toLowerCase();
    }

    // If network country not available (tablets maybe), get country code from Locale class
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        countryCode = context.getResources().getConfiguration().getLocales().get(0).getCountry();
    }
    else {
        countryCode = context.getResources().getConfiguration().locale.getCountry();
    }

    if (countryCode != null && countryCode.length() == 2)
        return  countryCode.toLowerCase();

    // General fallback to "us"
    return "us";
}

@SuppressLint("PrivateApi")
private static String getCDMACountryIso() {
    try {
        // Try to get country code from SystemProperties private class
        Class<?> systemProperties = Class.forName("android.os.SystemProperties");
        Method get = systemProperties.getMethod("get", String.class);

        // Get homeOperator that contain MCC + MNC
        String homeOperator = ((String) get.invoke(systemProperties,
                "ro.cdma.home.operator.numeric"));

        // First three characters (MCC) from homeOperator represents the country code
        int mcc = Integer.parseInt(homeOperator.substring(0, 3));

        // Mapping just countries that actually use CDMA networks
        switch (mcc) {
            case 330: return "PR";
            case 310: return "US";
            case 311: return "US";
            case 312: return "US";
            case 316: return "US";
            case 283: return "AM";
            case 460: return "CN";
            case 455: return "MO";
            case 414: return "MM";
            case 619: return "SL";
            case 450: return "KR";
            case 634: return "SD";
            case 434: return "UZ";
            case 232: return "AT";
            case 204: return "NL";
            case 262: return "DE";
            case 247: return "LV";
            case 255: return "UA";
        }
    }
    catch (ClassNotFoundException ignored) {
    }
    catch (NoSuchMethodException ignored) {
    }
    catch (IllegalAccessException ignored) {
    }
    catch (InvocationTargetException ignored) {
    }
    catch (NullPointerException ignored) {
    }

    return null;
}

Eine andere Idee ist es, eine API-Anfrage wie in dieser Antwort zu versuchen .

Referenzen sind hier und hier .

radu_paun
quelle
Falls sich jemand wie ich die Datenquelle der weltweiten CDMA-Netzwerke fragte, war es WIkipedia en.wikipedia.org/wiki/List_of_CDMA2000_networks
androidguy
7

Wenn für einige Geräte die Standardsprache anders eingestellt ist (ein Inder kann dann Englisch (US) einstellen)

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

wird den falschen Wert geben. Diese Methode ist also nicht zuverlässig.

Die Methode getNetworkCountryIso () von TelephonyManager funktioniert auch nicht auf Geräten ohne SIM-Karte (Wi-Fi-Tablets).

Wenn ein Gerät keine SIM-Karte hat, können wir die Zeitzone verwenden, um das Land zu erhalten. Für Länder wie Indien wird diese Methode funktionieren.

Beispielcode zur Überprüfung des Landes ist Indien oder nicht.

Verwenden Sie die folgenden Werte in Ihrer Konstantendatei

(Constants.INDIA_TIME_ZONE_ID: "asia / calcutta", Constants.NETWORK_INDIA_CODE: "in")

Fügen Sie in Ihrer Aktivität den folgenden Code hinzu:

private void checkCountry() {

    TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (telMgr == null)
        return;

    int simState = telMgr.getSimState();

    switch (simState) {

        // If a SIM card is not available then the
        // country is found using the 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 a SIM card is available then the telephony
        // manager network country information is used
        case TelephonyManager.SIM_STATE_READY:

            if (telMgr != 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;
    }
}
Spanne
quelle
Was muss für Konstanten importiert werden? Ich erhalte NETWORK_INDIA_CODE nicht, nachdem alle verfügbaren Konstanten importiert wurden.
Prantik Mondal
1
@PrantikMondal, das ist eine von mir erstellte Klasse. NETWORK_INDIA_CODE ist keine Android-Standardkonstante. Sie können den Wert "in" direkt verwenden
MarGin
Warum bekommst du zweimal TelephonyManager? Einmal sollte reichen
Pierre
6

Ich habe eine Dienstprogrammfunktion erstellt (einmal auf einem Gerät getestet, auf dem ich einen falschen Ländercode basierend auf dem Gebietsschema erhalten habe).

Referenz : CountryCodePicker.java

fun getDetectedCountry(context: Context, defaultCountryIsoCode: String): String {

    detectSIMCountry(context)?.let {
        return it
    }

    detectNetworkCountry(context)?.let {
        return it
    }

    detectLocaleCountry(context)?.let {
        return it
    }

    return defaultCountryIsoCode
}

private fun detectSIMCountry(context: Context): String? {
    try {
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        Log.d(TAG, "detectSIMCountry: ${telephonyManager.simCountryIso}")
        return telephonyManager.simCountryIso
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

private fun detectNetworkCountry(context: Context): String? {
    try {
        val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        Log.d(TAG, "detectNetworkCountry: ${telephonyManager.simCountryIso}")
        return telephonyManager.networkCountryIso
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

private fun detectLocaleCountry(context: Context): String? {
    try {
        val localeCountryISO = context.getResources().getConfiguration().locale.getCountry()
        Log.d(TAG, "detectNetworkCountry: $localeCountryISO")
        return localeCountryISO
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}
Mörder
quelle
4

Wenn Sie die Landesvorwahl erhalten möchten, ohne um Erlaubnis zu bitten, können Sie einen schwierigen Weg wählen.

Die Methode verwendet einfach eine API, um den Ländercode abzurufen, und es gibt keine Bibliotheken von Drittanbietern, auf die Sie sich verlassen können. Wir können eine für uns erstellen.

Hier habe ich Google Cloud-Funktionen verwendet , um eine API zu schreiben, und es ist so mühelos.

Schritt 1: Erstellen Sie ein Google Cloud-Konto und richten Sie die Abrechnung ein (die kostenlose Stufe reicht aus).

Schritt 2: Erstellen Sie eine Cloud-Funktion, um den geografischen Standort abzurufen

Kopieren Sie diese Grundfunktion in den Code-Editor von index.js :

const cors = require('cors')

function _geolocation(req, res) {
  const data = {
    country_code: req.headers["x-appengine-country"],
    region: req.headers["x-appengine-region"],
    city: req.headers["x-appengine-city"],
    cityLatLong: req.headers["x-appengine-citylatlong"],
    userIP: req.headers["x-appengine-user-ip"]
  }

  res.json(data)
};

exports.geolocation = (req, res) => {
  const corsHandler = cors({ origin: true })

  return corsHandler(req, res, function() {
    return _geolocation(req, res);
  });
};

Außerdem müssen wir die package.json- Definition kopieren :

{
  "name": "gfc-geolocation",
  "version": "0.0.1",
  "dependencies": {
    "cors": "^2.8.4"
  }
}

Schritt 3: Beenden Sie und erhalten Sie die URL ähnlich wie: "https://us-central1-geolocation-mods-sdde.cloudfunctions.net/geolocation"

Schritt 4: Analysieren Sie die JSON-Antwort und rufen Sie den Ländercode ab

Die Antwort sieht folgendermaßen aus:

{
   "country": "IN",
   "region": "kl",
   "city": "kochi",
   "cityLatLong": "9.9312,76.2673",
   "userIP": "xx.xx.xx.xx"
}

Dank und Dank geht an den Artikel " Mittel ": Kostenlose IP-basierte Geolokalisierung mit Google Cloud-Funktionen

Blue_Alien
quelle
2

Es ist nicht erforderlich, eine API aufzurufen. Sie können den Ländercode von Ihrem Gerät abrufen, auf dem er sich befindet. Verwenden Sie einfach diese Funktion:

 fun getUserCountry(context: Context): String? {
    try {
        val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        val simCountry = tm.simCountryIso
        if (simCountry != null && simCountry.length == 2) { // SIM country code is available
            return simCountry.toLowerCase(Locale.US)
        } 
        else if (tm.phoneType != TelephonyManager.PHONE_TYPE_CDMA) { // Device is not 3G (would be unreliable)
            val networkCountry = tm.networkCountryIso
            if (networkCountry != null && networkCountry.length == 2) { // network country code is available
                return networkCountry.toLowerCase(Locale.US)
            }
        }
    }
    catch (e: Exception) {
    }
    return null
}
pavel
quelle
Funktioniert das immer Gibt es Fälle, in denen auch dies fehlschlägt? Was gibt beispielsweise "networkCountryIso" zurück?
Android-Entwickler
@ Blue_Alien ya wahrscheinlich
pavel