Get geographic location in fluent [fluent topic 61]

Hello, everyone. I am nuts. The official account is "nuts front end".

Get geographic location in fluent

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

But this is different from Flutter - it has many amazing packages that can abstract template code for you and make geolocation a dream. Another good 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 will take you through the two most popular and easy-to-use Flutter geolocation packages.

Let's start with location, which is Flutter's favorite bag. It's simple. In three simple steps, you can obtain the current user location and processing location permissions.

precondition

Before moving on, let's quickly check what we need:

  • Should FlutterSDK
  • Editor; You can use Visual Code or Android Studio
  • At least have a rudimentary understanding of Flutter

That's almost it!

Using the flyer positioning package

set up

Add dependencies to your file: pubspec.yaml

    location: ^4.3.0

Because Android and iOS handle permissions differently, we must add them separately on each platform.

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" />

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 in the manifest file: enableBackgroundMode({bool enable})

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

For iOS

Add the following location permissions to: Info.plist

<key>NSLocationWhenInUseUsageDescription</key> 
<string>This app needs access to your location</string>

NSLocationWhenInUseUsageDescription is the only license you need. This also allows you to access the background location. The only thing to note is that when the application accesses the location in the background, a blue badge is displayed in the status bar. 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's location, which can be easily completed with the following lines of code:

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

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 manually disabled by the user`` serviceEnabled()

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

Once we confirm 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 will return. hasPermission()``PermissionStatus

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

  • PermissionStatus.granted: location service permission has been granted
  • PermissionStatus.denied: location service permission denied
  • PermissionStatus.deniedForever: location service permission is permanently denied by the user. This applies only to iOS. In this case, the dialog requestPermission() is not displayed

If the status is, we can call to display the system prompt for requesting location permission. For status, we can access location immediately, so we return a. 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 permission, we only need two lines of code to get the user's location - no, I'm not kidding:

LocationData _locationData;
_locationData = await location.getLocation();

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
}

You can also add an onLocationChanged listener to listen for location updates when the user's location changes to obtain continuous callbacks. This is a good use case for taxi applications, driver / rider applications, etc

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

Note that once you want to stop listening to updates, don't forget to cancel your streaming subscription.

Look! Now we have the current latitude and longitude values of the user's location.

Let's use these latitude and longitude values to get the full address or address of the user Reverse geocoding.

To do this, we'll use another amazing Flutter package: geocode.

Using fluent geocoding packages

set up

Add dependencies to your file: pubspec.yaml

dependencies:
    geocode: 1.0.1

Get address

Getting the address can't be easier. Just call. this is it! The complete function with null checking is as follows: reverse geocoding (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}";
}

It's not that simple!

The complete code is as follows:

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

Common pitfalls

Although these packages make our lives easier and we don't have to deal with the complex process of accessing locations locally in Android and iOS, you may face many problems. Let's look at them and the steps that can help you fix them:

  • App memory leak: if you have been listening to location updates, please make sure to cancel the streaming subscription once you want to stop listening to updates
  • Users must accept location permissions to always allow background locations. The Android 11 option that is always allowed is not displayed in the prompt of the location permission dialog box. The user must enable it manually from the application settings
  • Users may always refuse to locate on iOS, so local prompts requiring location permission will not be displayed. Be sure to handle this edge condition requestpermissions()
  • Users may revoke location permissions from application settings at any time, so before accessing location data, make sure to check them when the application recovers

conclusion

Because Flutter simplifies the access location, we as developers may add it to our application immediately. But at the same time, we need to ensure that our application is really suitable for the use case that requests the user's location and uses it to add some value to the user, rather than just sending the location data to the server.

With the improvement of security and privacy in the upcoming versions of Android and iOS operating systems, accessing location data without providing value to users may cause your application to be rejected by the store. There are many good use cases where you can use the user location. For example, personalize the home screen for the food / takeout application according to the user location, which displays the restaurants ordered according to the proximity of 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 home screen. This makes users more aware and they are less likely to deny location permissions.

Thank you for your company, fans! You can On GitHub Access the sample application used in this article.

Tags: Linux Ubuntu Flutter server

Posted on Sat, 27 Nov 2021 22:06:36 -0500 by wobbit