Hasan A Yousef
Hasan A Yousef

Reputation: 24988

Granting location permission with Flutter at iOS

The below code run smoothly at Android, but stuck at iOS, when I click the map icon, the system should update my location:

import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:flutter/services.dart';
import 'package:simple_permissions/simple_permissions.dart';

class LocationState extends State {

  String _loca_ext;

  Location _location = new Location();
  Map<String, double> _currentLocation;

  String error;

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

    setState(() {
      _loca_ext = 'Clik to update location';
    });

  }

  // Platform messages are asynchronous, so we initialize in an async method.
  _getLocation() async {
    Map<String, double> location;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      await SimplePermissions.requestPermission(Permission.AccessFineLocation);
      location = await _location.getLocation();
      error = null;
    } on PlatformException catch (e) {
      if (e.code == 'PERMISSION_DENIED') {
        error = 'Permission denied';
      } else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {
        error =
        'Permission denied - please ask the user to enable it from the app settings';
      }
      location = null;
    }
    print("error $error");

    setState(() {
      _currentLocation = location;
      _loca_ext = ('${_currentLocation["latitude"]}, ${_currentLocation["longitude"]}' ?? 'Grant location Access');
      print(_currentLocation);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Baby Name Votes')),
      body: _buildBody(context),
    );
  }

  Widget _buildBody(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(color: Colors.grey),
          borderRadius: BorderRadius.circular(5.0),
        ),
        child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              ButtonTheme.bar(
                  child: ButtonBar(
                      children: <Widget>[
                        Text.rich(
                          TextSpan(text: '$_loca_ext'),
                        ),
                        FlatButton(
                          child: const Icon(Icons.map),
                          onPressed: () {
                            _getLocation();
                            var alt = _currentLocation["latitude"];
                            print("my $alt at location is: $_currentLocation");
                          },
                        )
                      ])
              )
            ]),
      ),
    );
  }
}

With iOS, it gave the below error:

error Permission denied

Knowing that in the Info.plist, I added the below:

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location in the background.</string>    
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location when open and in the background.</string>

NOTE

It work if I granted it manually in the settings/privacy/location, but I need to do it programmatically, or guide the user to do it.

Upvotes: 5

Views: 32490

Answers (2)

lodgmar
lodgmar

Reputation: 11

In my case, I'm using a FlutterMap with a CurrentLocationLayer, which internally uses Geolocator. So, when I try to ask for current location and, at the same time, I show the map, exception throws.

What it's really strange is that this only happens on iOS, not Android. Anyway, knowing the cause, you can prevent it by only showing this layer when you're sure you have permission (or even if you don't, at least when you've already asked for it).

Upvotes: 1

TWL
TWL

Reputation: 6664

Have you tried using https://pub.dev/packages/permission?

Sample methods:

import 'package:permission/permission.dart';

var permissions = await Permission.getPermissionsStatus([PermissionName.Calendar, PermissionName.Camera]);

var permissionNames = await Permission.requestPermissions([PermissionName.Calendar, PermissionName.Camera]);

Permission.openSettings;

But like the comments say, if the permission is rejected, then you have to manually go to the settings to enable it. For more understanding, see medium/Requesting Location Permissions in iOS (March 2018)

Users have only one chance to respond to these alerts, so you want to make your request at the right time and provide a good reason for it. If the user doesn’t allow access, they’ll need to go to the settings to enable location access.

Upvotes: 3

Related Questions