This is the 28th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Here is nut front-end small classroom, if you like, you can follow my public number “nut front-end,” or add my friends, for more wonderful content

Gain location in Flutter

Today, discovering a user’s location is a very common and powerful use case for mobile applications. If you’ve ever tried to implement location in Android, you know how complex and confusing sample code can get.

But this is different from Flutter — it has amazing packages that abstract away boilerplate code for you and make geolocation a dream. The other nice thing is that you can get these features on Android and iOS.

Let’s take a quick look at what we’re building today to collect location data:

This article takes you through two of the most popular and easy-to-use Flutter geolocation packages.

Let’s start with Location, which is Flutter’s favorite package. That’s easy. In three simple steps, you can get the current user location and process location permissions.

A prerequisite for

Before moving on, let’s have a quick check of what we need:

  • The FlutterSDK
  • The editor; You can use Visual Code or Android Studio
  • Have at least a rudimentary understanding of Flutter

That’s about it!

Use the Flutter locator pack

Set up the

Add the dependency to your file: pubspec.yaml

    location: ^4.3. 0
Copy the code

Since Android and iOS handle permissions differently, we had to add them separately on each platform.

The android version

Add the following location permissions to: androidmanifest.xml

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Copy the code

If you also want to access the user’s location in the background, use the API before accessing the background location and add the background permission to the manifest file: enableBackgroundMode({bool enable})

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Copy the code

For iOS

Add the following location permissions to: info.plist

< key > NSLocationWhenInUseUsageDescription < / key > < string > the application needs to access your location < / string >Copy the code

The only license NSLocationWhenInUseUsageDescription is you need. This also allows you to access the background location, the only thing to note is that the status bar displays a blue badge when the application accesses the location in the background. Unlike Android, we have added separate permissions to access the user’s location in the background.

Location permissions

We need to check the location service status and permission status before requesting the user location, which can be easily done with the following lines:

Location location = new Location();

bool _serviceEnabled;
PermissionStatus _permissionGranted;

_serviceEnabled = await location.serviceEnabled();
if(! _serviceEnabled) { _serviceEnabled =await location.requestService();
 if(! _serviceEnabled) {return null;
 }
}

_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
 _permissionGranted = await location.requestPermission();
 if(_permissionGranted ! = PermissionStatus.granted) {return null; }}Copy the code

First, we create an object provided by the Location() package, which in turn provides us with two useful methods. Check whether the device location is enabled or whether the user has manually disabled it. “serviceEnabled()

For the latter, we display a native prompt that allows the user to quickly enable the location by calling, and then we check again if they enabled it from the prompt. requestService()

Once we determine that the location service is enabled, the next step is to check whether our application has the necessary permissions to use it by calling it, which returns.hasPermission() ‘PermissionStatus

PermissionStatus is an enumeration that can have one of three values:

  • PermissionStatus.granted: The location service right has been granted
  • PermissionStatus.denied: The location service permission is denied
  • PermissionStatus.deniedForever: The location service permission is permanently denied by the user. This is only for iOS. The dialog box is not displayed in this caserequestPermission()

If the status is, we can invoke a system prompt that displays the permission for the requested location. For status, we have immediate access to location, so we return.denied, ‘requestPermission()’ granted ‘null

If you also want to access user locations in the background, use. location.enableBackgroundMode(enable: **true**)

Get current location

If the location service is available and the user has granted location permissions, then we only need two lines of code to get the user’s location – no, I’m not kidding:

LocationData _locationData;
_locationData = await location.getLocation();
Copy the code

The LocationData class provides the following location information:

class LocationData {
  final double latitude; // Latitude, in degrees
  final double longitude; // Longitude, in degrees
  final double accuracy; // Estimated horizontal accuracy of this location, radial, in meters
  final double altitude; // In meters above the WGS 84 reference ellipsoid
  final double speed; // In meters/second
  final double speedAccuracy; // In meters/second, always 0 on iOS
  final double heading; // Heading is the horizontal direction of travel of this device, in degrees
  final double time; // timestamp of the LocationData
  final bool isMock; // Is the location currently mocked
}
Copy the code

You can also get continuous callbacks by adding the onLocationChanged listener to listen for position updates when the user’s position changes, which is a good use case for taxi applications, driver/rider applications, and so on:

location.onLocationChanged.listen((LocationData currentLocation) {
  // current user location
});
Copy the code

Note that if you want to stop listening to updates, don’t forget to unsubscribe from the stream.

Look! Now we have the current latitude and longitude values for the user’s location.

Let’s use these latitude and longitude values to get the user’s full address or reverse geocoding.

To do this, we will use another amazing Flutter package: GeoCode.

Use the Flutter geocode package

Set up the

Add the dependency to your file: pubspec.yaml

dependencies:
    geocode: 1.01.
Copy the code

Get the address

Getting the address couldn’t be easier. Just call. That’s it! The full function with null checking is as follows: reverseGeocoding(latitude: Lat, longitude: lang)

Future<String> _getAddress(double? lat, double? lang) async {
 if (lat == null || lang == null) return "";
 GeoCode geoCode = GeoCode();
 Address address =
     await geoCode.reverseGeocoding(latitude: lat, longitude: lang);
 return "${address.streetAddress}.${address.city}.${address.countryName}.${address.postal}";
}
Copy the code

It’s not that simple!

The complete code looks like this:

class GetUserLocation extends StatefulWidget {
 GetUserLocation({Key? key, required this.title}) : super(key: key);
 final String title;

 @override
 _GetUserLocationState createState() => _GetUserLocationState();
}

class _GetUserLocationState extends State<GetUserLocation> {
 LocationData? currentLocation;
 String address = "";

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(),
     body: Center(
       child: Padding(
         padding: EdgeInsets.all(16.0),
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: <Widget>[
             if(currentLocation ! =null)
               Text(
                   "Location: ${currentLocation? .latitude}.${currentLocation? .longitude}"),
             if(currentLocation ! =null) Text("Address: $address"), MaterialButton( onPressed: () { _getLocation().then((value) { LocationData? location = value; _getAddress(location? .latitude, location? .longitude) .then((value) { setState(() { currentLocation = location; address = value; }); }); }); }, color: Colors.purple, child: Text("Get Location", style: TextStyle(color: Colors.white), ), ), ], ), ), ), ); } Future<LocationData? > _getLocation()async {
   Location location = new Location();
   LocationData _locationData;

   bool _serviceEnabled;
   PermissionStatus _permissionGranted;

   _serviceEnabled = await location.serviceEnabled();
   if(! _serviceEnabled) { _serviceEnabled =await location.requestService();
     if(! _serviceEnabled) {return null;
     }
   }

   _permissionGranted = await location.hasPermission();
   if (_permissionGranted == PermissionStatus.denied) {
     _permissionGranted = await location.requestPermission();
     if(_permissionGranted ! = PermissionStatus.granted) {return null;
     }
   }


   _locationData = await location.getLocation();

   return _locationData;
 }

 Future<String> _getAddress(double? lat, double? lang) async {
   if (lat == null || lang == null) return "";
   GeoCode geoCode = GeoCode();
   Address address =
       await geoCode.reverseGeocoding(latitude: lat, longitude: lang);
   return "${address.streetAddress}.${address.city}.${address.countryName}.${address.postal}"; }}Copy the code

Common Pitfalls

Although these packages make our lives easier, and we don’t have to deal with the complicated process of accessing the location locally in Android and iOS, you can face a lot of problems. Let’s take a look at them and the steps that can help you fix them:

  • Apply memory leaks: If you have been listening to location updates, make sure to unsubscribe from the stream as soon as you want to stop listening to updates
  • Users must accept location permissions to always be allowed to use background locations. The Location permissions dialog prompt does not show always-allowed Android 11 options. The user must manually enable it from the application Settings
  • Users may forever refuse location on iOS, so no native prompt for location permission is displayed. Be sure to handle this edge caserequestPermisssions()
  • Users can revoke location permissions from application Settings at any time, so before accessing location data, be sure to check it when the application resumes

conclusion

Because Flutter simplifies access locations, we as developers might immediately add Flutter to our application. But at the same time, we need to make sure that our application is really suitable for use cases that request a user’s location and use it to add some value to the user, rather than just sending location data to the server.

With increased security and privacy in upcoming versions of the Android and iOS operating systems, accessing location data without providing value to users could result in your app being rejected by the store. There are many good use cases where you can use user location, such as personalizing the home screen for a food/delivery application based on user location that displays restaurants ordered by proximity to the user’s current location. Pick up/delivery applications are the most common use cases.

You can also ask for the user’s location on the specific screen you actually want to use, rather than immediately on the main screen. This makes it clearer to the user, and they are less likely to deny location rights.

Thank you for your company, nut front fans! You can access the sample application used in this article on GitHub.