I am trying to get country of device (Android) in Flutter. I used this tutorial, but I think it is the wrong approach for my problem.

Locale myLocale = Localizations.localeOf(context);
print(myLocale.languageCode.toString() + ' ' + myLocale.countryCode.toString());

Based on this, I have couple of questions/issues:

  • I am always getting en US even though I have set device language to Urdu - Pakistan. So what am I missing?
  • I want to display certain app items based on the country the device is in, not based on language as people living in Pakistan with language set to English (US) will get items actually intended for USA based users. So, should I use geoLocation and get longitude and latitude and decide based on that data? Or is there any other simpler approach just to get country of user?

Thanking in anticipation.


Solution 1: chunhunghan

please use package https://pub.dev/packages/devicelocale
I have tested with real device, it works fine

code snippet

String locale = await Devicelocale.currentLocale;

full code

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:devicelocale/devicelocale.dart';

void main() => runApp(MyApp());

/// Demo getting a device locale
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List _languages = List();
  String _locale;

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    List languages;
    String currentLocale;

    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      languages = await Devicelocale.preferredLanguages;
      print(languages);
    } on PlatformException {
      print("Error obtaining preferred languages");
    }
    try {
      currentLocale = await Devicelocale.currentLocale;
      print(currentLocale);
    } on PlatformException {
      print("Error obtaining current locale");
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _languages = languages;
      _locale = currentLocale;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              Text("Current locale: "),
              Text('$_locale'),
              Text("Preferred Languages: "),
              Text(_languages.toString()),

            ],
          )
        ),
      ),
    );
  }
}


Solution 2: Loïc Fonkam

Use the flutter_sim_country_code, with this package you can get a user localizations variables and country code directly from the user sim and network provider. For example;

networkCountryIso,
simCountryIso,

these variable always holds the country code,


Solution 3: Cenk YAGMUR

try this

import 'dart:io' show Platform;

String localeName = Platform.localeName;


Solution 4: Ravi Kumar

Try this. Don't forget to provide necessary permissions in android manifest and ios as well.

import 'package:geolocator/geolocator.dart';
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;

geolocator
    .getCurrentPosition(desiredAccuracy: LocationAccuracy.best)
    .then((Position position) {
  setState(() {
    _currentPosition = position;
  });
}).catchError((e) {
  print(e);
});


Solution 5: Rahul sharma

Add this 2 library in pubspec.yaml

geolocator: ^5.1.1
geocoder: ^0.2.1

Then Add permission for Location access. Check here

At last call this method where you want.

Future<String> getCountryName() async {
    Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    debugPrint('location: ${position.latitude}');
    final coordinates = new Coordinates(position.latitude, position.longitude);
    var addresses = await Geocoder.local.findAddressesFromCoordinates(coordinates);
    var first = addresses.first;
    return first.countryName; // this will return country name
}


Solution 6: moshfiqur

Building on @chunhunghan's answer, you can use the plugin https://pub.dev/packages/devicelocale. To get the country code, you have to use:

Locale l = await Devicelocale.currentAsLocale;
String countryCode = l.countryCode;

For the full code, check: https://pub.dev/packages/devicelocale#-example-tab-


Solution 7: ravish.hacker

I had the same problem working on an app with country specific functionality. All these methods mentioned here are good, having gone through them all myself I realised none will cover all possible scenarios.

So, I changed the approach to the problem. Instead of making decision programmatically, which country user is in and going ahead with it. I thought it is better to identify the user's country using one of the methods that suits your app most and then present it to the user. If they wish they can change it, otherwise in most cases auto detection is valid.

For my app I presented users with country when logging in and a flat button at bottom to change it if it is not correct.


Solution 8: Malek Tubaisaht

if you are looking to get the device country without using "geolocator" so you don't need to get the device permission, you can use the below code:

  Future<String> getCountry() async{
  Network n = new Network("http://ip-api.com/json");
  locationSTR = (await n.getData());
  locationx = jsonDecode(locationSTR);
  return locationx["country"];
}

The Network class code is below:

import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;

class Network {
  final String url;

  Network(this.url);

  Future<String> apiRequest(Map jsonMap) async {
    HttpClient httpClient = new HttpClient();
    HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
    request.headers.set('content-type', 'application/x-www-form-urlencoded');
    request.add(utf8.encode(json.encode(jsonMap)));
    HttpClientResponse response = await request.close();
    // todo - you should check the response.statusCode
    String reply = await response.transform(utf8.decoder).join();
    httpClient.close();
    return reply;
  }

  Future<String> sendData(Map data) async {
    http.Response response = await http.post(url,
        headers: {'Content-Type': 'application/json; charset=UTF-8'},
        body: jsonEncode(data));
    if (response.statusCode == 200)
      return (response.body);
    else
      return 'No Data';
  }

  Future<String> getData() async {
    http.Response response = await http.post(url,
        headers: {'Content-Type': 'application/x-www-form-urlencoded'});
    if (response.statusCode == 200)
      return (response.body);
    else
      return 'No Data';
  }
}

you can get the city and countrycode and internet provider as well.


Solution 9: Clement Joseph

This solution requires location service to be enabled.
Add these two dependencies in your pubspec.yaml file

geolocator: ^7.0.3 geocoding: ^2.0.0

Future<String> getCountryCodeName() async {
Position position = await Geolocator.getCurrentPosition(
    desiredAccuracy: LocationAccuracy.high);
List<Placemark> address =
    await placemarkFromCoordinates(position.latitude, position.longitude);
Placemark placeMark = address.first;
String country = placeMark.country;
return country; // this will return country }


Solution 10: vitralyoz

var code = WidgetsBinding.instance.window.locale.countryCode;


Solution 11: Shailandra Rajput

You have to use a geolocator and geocode plugin. then create this method use below code. In Android Manifest.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Function

Future<String> getCountryName() async {
    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        await Geolocator.requestPermission();
      }
      if (permission == LocationPermission.deniedForever) {
        return Future.error(
            'Location permissions are permanently denied, we cannot request permissions.');
      }
    }
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    debugPrint('location: ${position.latitude}');
    final coordinates = new Coordinates(position.latitude, position.longitude);
    var addresses =
        await Geocoder.local.findAddressesFromCoordinates(coordinates);
    var first = addresses.first;
    print(first.countryName);
    return first.countryName;
  }