Reputation: 24988
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
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
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