ここはどこ?-国を取得


126

Androidモバイルは実際にはどこにあるかをよく知っていますが、国コードのようなもので国を取得する方法はありますか?

GPSの正確な位置を知る必要はありません- で十分です

最初はタイムゾーンを使用することを考えましたが、実際には場所がニューヨークかリマかによって違いが生じるため、それよりも多くの情報が必要です。

質問の背景:温度値を使用するアプリケーションがあり、デフォルトの単位を摂氏または華氏に設定したい(場所が米国か外かによって異なる)。


14
-1:ユーザーどこにいるかを知りたくありません。ユーザーのロケール設定を知りたい。受け入れられた答えはそれだけに答えますが、それ以外の場合は完全に不適切です。検索によって、ユーザーが実際にどこにいるかを知りたい人がここに表示されるからです。
Jan Hudec 2013

回答:


96

これにより、電話に設定された国コードが取得されます(電話の言語、ユーザーの場所ではありません)。

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

getCountry()をgetISO3Country()に置き換えて、国の3文字のISOコードを取得することもできます。これは国名を取得します

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

これは他の方法よりも簡単で、電話のローカリゼーション設定に依存しているため、米国のユーザーが海外にいる場合でも華氏を望んでおり、これは機能します:)

編集者注:このソリューションは、電話の場所とは関係ありません。一定です。ドイツに旅行するとき、ロケールは変更されません。つまり、ロケール!=の場所です。


83
これは、Androidにロケールがない国では機能しません。たとえば、スイスでは、言語はドイツ語またはフランス語に設定される可能性があります。この方法では、スイスではなくドイツまたはフランスが提供されます。LocationManagerまたはTelephonyManagerのアプローチを使用する方が良いでしょう。
MathewI、2011年

5
うまくいきません。私はすべてのラテンアメリカの国でユーザーの国を区別する必要があります。電話が英語またはスペイン語の言語であっても、すべてのテスト用電話は米国に戻ってきました。
htafoya

21
これは質問タイトルには答えません。私は英語に電話機を持っており、世界でどこでも程度でよい(私の母国語があるではない英語、しかし、私がやる(英国)英語に自分の携帯電話のセットを持っている。それは、しかし、実際の質問に答えてないユーザーがいる場合、米国の単位を望んでいるので、彼はアメリカ人であり、実際にどこにいても
Jan Hudec 2013

2
国名を取得するための現実的な解決策ではない
アーミルハン2014年

2
一般的には良い答えですが、実際の国ではなく、ロケールの国のみを返します。
2014年

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タブレットで使用する場合、nullになります。そのため、その有用性は限られています。
Bram

1
@Bramこれはあなたが得ることができるすべてです。したがって、実際には非常に便利です。問題は、WiFiのみのタブレットを使用している場合、他に信頼できるデータソースがないことだけです。
2015年

11
米国のユーザーがフランスで休暇中の場合、次のgetSimCountryIsoように発言usgetNetworkCountryIsoますfr
Tim

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
これが正確にOPが望んだものかどうかはわかりませんが、とにかく答えが好きです。
JohnnyLambada 2015年

1
これはタブレット(simなし)でも機能するため、答えと同様です。テレフォニーソリューションは、アクティブなシムを備えた電話でのみ機能します。デュアルsim電話は、国が異なる可能性があるため、別の問題シナリオです。したがって、おそらく上記のIPソリューションに依存する方が理にかなっています。
Manish Kataria

1
ご指摘のとおり、これは問題に対する最善のアプローチではないかもしれませんが、実際には有効なソリューションを提供します。私からの+1とありがとうございます。
Matteo

1
サードパーティを使用することは常に悪いことであり、どれほど安定しているかを知ることはできません。たとえば-解析。
Nativ 2016年

1
ただし、制限があります。彼らのシステムは、1分あたり150を超えるリクエストを行うIPアドレスを自動的に禁止します。
Ram Mandal

62

実際、私はgetSimCountryIso()メソッドを使用して国コードを取得する方法が1つ以上あることを知りましたTelephoneManager

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

これはsimコードなので、他の国に旅行するときにも変更してはなりません。


43
デバイスにSIMカードがない場合(タブレットなど)、これは機能しない可能性があります
thomasdao

38

まず、LocationManagerを取得します。次に、を呼び出しますLocationManager.getLastKnownPosition。次に、GeoCoderを作成してを呼び出しますGeoCoder.getFromLocation。これは別のスレッドで行います!! これにより、Addressオブジェクトのリストが表示されます。電話Address.getCountryNameしてください。

最後の既知の位置は少し古くなっている可能性があるので、ユーザーが国境を越えただけではしばらくの間、その位置を知らない可能性があることに注意してください。


このアプリケーションの場合、国を移動するときにデフォルトの単位を変更することは望ましくありません。ユーザーが摂氏または華氏の好みを変更しても、新しい土地に移動しても変更されないからです。
ステルスコプター

ユーザーがAPI呼び出しを利用している国を知る必要があります。呼び出しは、周辺地域の場所を返します。したがって、私はユーザーが現在使用している実際の国コードのみに関心があります。上記のアプローチが何のために必要であるかについて洞察を与えるためだけに。
vinzenzweber 2011年

これはansの評価が非常に低いですが、実際にはこれが最も信頼できるソリューションです。上記のansのほとんどはwifiネットワークでは機能しません。@shine_josephが提供するAPIは見栄えは良いですが、提供されるAPIは商用目的ではありません。
Gem

注意して使用してください。デバイスはネットワークに接続されていなくても場所を提供しますが、Wifiがオフの場合、Geocoderは通常、アドレス配列にnullを返すため、試行/キャッチする必要があるという例外が発生します。
Mike Critchley

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
申し訳ありませんが、あなたの答えは本当に書き換える必要があります。コードには、使用できないコードがたくさん含まれています。
イハロ2016

@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();:-)
Firzen

15

getNetworkCountryIso()fromTelephonyManagerを使用て、電話が現在ある国を取得できます(明らかに、これは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()メソッドは、SIMカードを持たないデバイス(WIFIタブレット)では機能しません。

デバイスにSIMがない場合は、タイムゾーンを使用して国を取得できます。インドのような国では、この方法が機能します

国のチェックに使用されるサンプルコードはインドかどうか(タイムゾーンID: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度のために別の時間帯等がある
Gunhan

3

緯度と経度でGPSを使用して、国コードを取得できます。

電話を使用する場合、SIMカードを使用しておらず、言語に基づいたロケールでは、国コードが誤った方法で表示されると機能しません。

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()とは何ですか?定義されていません
ニコラ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
?>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.