Use getPositionStream to add location indicator Flutter - flutter

I have a HERE map with various functionality operating fine
I have a location indicator that currently operates Geolocator.getCurrentPosition(); which works fine, taking the lat,long and heading to place indicator.
I want it to update with users location from device.
I need to use Geolocator.getPositionStream to achieve this but after trying the implementation example online I'm stuck as it has different requirements to Current Position and the code won't work
Here is the LocationIndicator method, set to getRandom
void _addLocationIndicator(GeoCoordinates geoCoordinates, LocationIndicatorIndicatorStyle indicatorStyle) {
LocationIndicator locationIndicator = LocationIndicator();
locationIndicator.locationIndicatorStyle = indicatorStyle;
Location location = Location.withCoordinates(geoCoordinates);
location.time = DateTime.now();
location.bearingInDegrees = _getRandom(0, 360);
locationIndicator.updateLocation(location);
_hereMapController.addLifecycleListener(locationIndicator);
}
This is the given code for Stream
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
StreamSubscription<Position> positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(
(Position position) {
print(position == null ? 'Unknown' : position.latitude.toString() + ', ' + position.longitude.toString());
});
This is the Current Location example which I have used and it works fine for current location
import 'package:geolocator/geolocator.dart';
/// Determine the current position of the device.
///
/// When the location services are not enabled or permissions
/// are denied the `Future` will return an error.
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
// Permissions are denied, next time you could try
// requesting permissions again (this is also where
// Android's shouldShowRequestPermissionRationale
// returned true. According to Android guidelines
// your App should show an explanatory UI now.
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
return await Geolocator.getCurrentPosition();
}
Thanks

Related

How can I test a future function using bloc test

I'm new to bloc and currently learning bloc testing. The below code is
working fine in debug mode. However, I can't find anything to await the
function to test the current position/error.
Here is my bloc
class GoogleMapBloc extends Bloc<GoogleMapEvent, GoogleMapState> {
GoogleMapBloc() : super(const GoogleMapState()) {
on<CurrentLocationEvent>(_showCurrentPosition);
}
//This is the bloc logic
void _showCurrentPosition(
CurrentLocationEvent event, Emitter<GoogleMapState> emit) async {
try {
emit(state.copyWith(loadStatus: LoadStatus.loading));
Position position = await _getCurrentLocation();
final Marker marker = Marker(
markerId: const MarkerId('current_position'),
position: LatLng(position.latitude, position.longitude),
);
Set<Marker> markers = {};
markers.add(marker);
emit(state.copyWith(
loadStatus: LoadStatus.success,
currentPosition: position,
markers: markers));
} catch (e) {
//debugPrint("Exception ===> ${e.toString()}");
emit(state.copyWith(
loadStatus: LoadStatus.fail,
markers: {},
error: e.toString().substring(11)));
}
}
//This will fetch current user or error
Future<Position> _getCurrentLocation() async {
bool serviceEnabled;
LocationPermission permission;
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
throw Exception('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
// Permissions are denied, next time you could try
// requesting permissions again (this is also where
// Android's shouldShowRequestPermissionRationale
// returned true. According to Android guidelines
// your App should show an explanatory UI now.
throw Exception('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
throw Exception(
'Location permissions are permanently denied, we cannot request permissions.');
}
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
return await Geolocator.getCurrentPosition();
}
}
Here, I'm confused, as to how can I await the function without using
the wait as this is an async call.
void googleMapBloc() {
group("Google Map Bloc Testing", () {
blocTest<GoogleMapBloc, GoogleMapState>(
'Check location enabled',
build: () => GoogleMapBloc(),
act: (bloc) => bloc.add(const CurrentLocationEvent()),
wait: const Duration(milliseconds: 10000),
expect: () => <GoogleMapState>[
const GoogleMapState(loadStatus: LoadStatus.loading),
const GoogleMapState(
markers: {}, loadStatus: LoadStatus.fail, error: ""),
],
);
});
}
Also, how can I mock this for the api request

Find Address From Coordinates

final addresses =
await Geocoder.local.findAddressesFromCoordinates(coordinates);
selectedAddress = addresses.first;
The plugin geocoder uses a deprecated version of the Android embedding.
To avoid unexpected runtime failures, or future build failures, try to see if this plugin supports the Android V2 embedding. Otherwise, consider removing it since a future release of Flutter will remove these deprecated APIs.
If you are plugin author, take a look at the docs for migrating the plugin to the V2 embedding: https://flutter.dev/go/android-plugin-migration.
Use [geolocator][1] package and write the below code to get the city name and coordinates
void main() async {
await configureInjection(Environment.dev);
WidgetsFlutterBinding.ensureInitialized();
Position _currentPosition = await getCurrentPosition();
List<Placemark> placemarks = await placemarkFromCoordinates(
_currentPosition.latitude, _currentPosition.longitude);
Placemark place = placemarks[0];
runApp(AppWidget());
}
Future<Position> getCurrentPosition() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
);
}

Not able to get the Latitude and Longitude while using 'GeoLocator' package

I am trying to use 'GeoLocator' to retrieve Latitude & Longitude. However, not able to get any output?
Also will be helpful if someone can help me organize the 'geoLocator' package as a service in a separate dart file.
As suggested I tried changing the code, but still not able to get the geolocation. Also when I call the '_determinePosition()' getting "Instance of 'Future'
".
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
return await Geolocator.getCurrentPosition();
}
#override
Widget build(BuildContext context) {
// TESTIST IF PRINT CAN WORK HERE
print(_determinePosition());
return Scaffold(
appBar: AppBar(
title: Text("Location"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
child: Text("Get location"),
onPressed: () {
// PRINTING IN THE CONSOLE
_determinePosition();
},
),
],
),
),
);
}
}
Try to add the Internet permission in addition to the location permissions per the documentation (https://pub.dev/packages/geolocator):
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Regarding getting "intsantce of a Future" instead of the result you need to await the call to _determinePosition() just like this:
onPressed: () async{
// PRINTING IN THE CONSOLE
await _determinePosition();
},
For using Geolocator as a service I recommend to use a dependency injection solution like Provider(https://pub.dev/packages/provider) or GetIt(https://pub.dev/packages/get_it)
Use below function which checks the permission and returns current position, so before getting location it's important to check whether we had required permission or not.
import 'package:geolocator/geolocator.dart';
/// Determine the current position of the device.
///
/// When the location services are not enabled or permissions
/// are denied the `Future` will return an error.
Future<Position> _determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
// Test if location services are enabled.
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Location services are not enabled don't continue
// accessing the position and request users of the
// App to enable the location services.
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.deniedForever) {
// Permissions are denied forever, handle appropriately.
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
if (permission == LocationPermission.denied) {
// Permissions are denied, next time you could try
// requesting permissions again (this is also where
// Android's shouldShowRequestPermissionRationale
// returned true. According to Android guidelines
// your App should show an explanatory UI now.
return Future.error(
'Location permissions are denied');
}
}
// When we reach here, permissions are granted and we can
// continue accessing the position of the device.
return await Geolocator.getCurrentPosition();
}

How do I handle a future not returning?

I'm using a location plugin to get the current location of the device. However, on certain devices, await getLocation() never returns (there are also no errors in the debug console). How do I handle such an issue?
this is my code for getCurrentLocation()
import 'package:geolocator/geolocator.dart';
import 'location.dart';
/// Determine the current position of the device.
///
/// When the location services are not enabled or permissions
/// are denied the `Future` will return an error.
Future<Position> getCurrentLocation() async {
bool serviceEnabled;
LocationPermission permission;
Position position;
await reqLocation(); // requests turn on location
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permantly denied, we cannot request permissions.');
}
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission != LocationPermission.whileInUse &&
permission != LocationPermission.always) {
return Future.error(
'Location permissions are denied (actual value: $permission).');
}
}
print('LOGIC');
position = await Geolocator.getCurrentPosition();
if (position == null) {
print('null');
} else {
print('LOCATION');
print(position);
}
return position;
}
Use a timeout for your future to handle this case: Flutter - Future Timeout
Use your future like this:
var result = await getCurrentLocation().timeout(const Duration(seconds: 5, onTimeout: () => null));
Now, your future runs for 5 seconds and if the operation is not complete yet, the future completes with null (because onTimeout returned null. You can use a different value as you like [Refer to the link above]).
Now check result. if null, the operation did not complete within specified time limit else you get your position value in result as usual if it managed to complete within the specified duration.

Fetching Current Location with Permission not working

I am using
geolocator: '^3.0.1'
permission_handler: '^3.0.0'
Now I want to fetch the current location of the user and show it on the map as the user opens the Map.
So my Code is :
Future<void> requestPermission() async {
PermissionHandler()
.checkPermissionStatus(PermissionGroup.location)
.then((PermissionStatus permissionStatus) async {
print("Checking Permission " + permissionStatus.toString());
if (permissionStatus == PermissionStatus.granted) {
_getCurrentLocation();
} else {
print("Asking Permission " + permissionStatus.toString());
final List<PermissionGroup> permissions = <PermissionGroup>[
PermissionGroup.locationWhenInUse
];
final Map<PermissionGroup, PermissionStatus> permissionRequestResult =
await PermissionHandler().requestPermissions(permissions);
if (PermissionStatus.granted ==
permissionRequestResult[PermissionGroup.locationWhenInUse]) {
print("Permission Granted " + permissionStatus.toString());
_getCurrentLocation();
}
}
});
}
and permissions are defined in the manifest for android and info.list for IOS.
Now the issue is when I run this function and when it calls requestPermission function, it shows the popup asking for the permission and
when I allow the permission app crashes with an error :
java.lang.RuntimeException: Failure delivering result ResultInfo{who=#android:requestPermissions: ... java.lang.IllegalStateException: Reply already submitted
and also the result of permission is Permission.disabled though I allowed the permission in application settings and in permission it shows that location is permission is allowed. but I tried opening app several times it shows Permission.disabled.
and even if I deny the app crashes with the same error.
So what I have concluded is :
If I allow or deny it crashes because it is requesting multiple times and even if I allow the result is Permission.disabled.
Link for the video: https://youtu.be/A1DKkw6u4HI
Can anyone help me solving this issue?
Or please tell me how to take the current location map easily
please tell me how to take the current location map easily
If you just need to fetch current location easily and you just need location permission then :
you can use location plugin with flutter :
In your pubspec.yml : location : ^2.3.0
Then for fetching Current location :
Import location Package
import 'package:location/location.dart' as locationPackage;
Add this to your State
locationPackage.Location _locationService = new locationPackage.Location();
bool _permission = false;
Call this function in initState or whenever you need current Location
fetchCurrentLocation() async {
await _locationService.changeSettings(
accuracy: locationPackage.LocationAccuracy.HIGH, interval: 1000);
locationPackage.LocationData location;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
bool serviceStatus = await _locationService.serviceEnabled();
print("Service status: $serviceStatus");
if (serviceStatus) {
_permission = await _locationService.requestPermission();
print("Permission: $_permission");
if (_permission) {
location = await _locationService.getLocation();
print("Location: ${location.latitude}");
}
} else {
bool serviceStatusResult = await _locationService.requestService();
print("Service status activated after request: $serviceStatusResult");
if (serviceStatusResult) {
fetchCurrentLocation();
}
}
} on PlatformException catch (e) {
print(e);
if (e.code == 'PERMISSION_DENIED') {
//error = e.message;
} else if (e.code == 'SERVICE_STATUS_ERROR') {
//error = e.message;
}
location = null;
}
}