-
-
Save christocracy/a0464846de8a9c27c7e9de5616082878 to your computer and use it in GitHub Desktop.
/// flutter_background_geolocation Hello World | |
/// https://github.com/transistorsoft/flutter_background_geolocation | |
//// | |
// For pretty-printing location JSON. Not a requirement of flutter_background_geolocation | |
// | |
import 'dart:convert'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' | |
as bg; | |
JsonEncoder encoder = const JsonEncoder.withIndent(' '); | |
// | |
//// | |
class MyHomePage extends StatefulWidget { | |
const MyHomePage({Key? key, required this.title}) : super(key: key); | |
final String title; | |
@override | |
_MyHomePageState createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
late bool _isMoving; | |
late bool _enabled; | |
late String _motionActivity; | |
late String _odometer; | |
late String _content; | |
@override | |
void initState() { | |
_isMoving = false; | |
_enabled = false; | |
_content = ''; | |
_motionActivity = 'UNKNOWN'; | |
_odometer = '0'; | |
// 1. Listen to events (See docs for all 12 available events). | |
bg.BackgroundGeolocation.onLocation(_onLocation); | |
bg.BackgroundGeolocation.onMotionChange(_onMotionChange); | |
bg.BackgroundGeolocation.onActivityChange(_onActivityChange); | |
bg.BackgroundGeolocation.onProviderChange(_onProviderChange); | |
bg.BackgroundGeolocation.onConnectivityChange(_onConnectivityChange); | |
// 2. Configure the plugin | |
bg.BackgroundGeolocation.ready(bg.Config( | |
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH, | |
distanceFilter: 10.0, | |
stopOnTerminate: false, | |
startOnBoot: true, | |
debug: true, | |
logLevel: bg.Config.LOG_LEVEL_VERBOSE, | |
reset: true)) | |
.then((bg.State state) { | |
setState(() { | |
_enabled = state.enabled; | |
_isMoving = state.isMoving == true; | |
}); | |
}); | |
} | |
void _onClickEnable(enabled) { | |
if (enabled) { | |
bg.BackgroundGeolocation.start().then((bg.State state) { | |
print('[start] success $state'); | |
setState(() { | |
_enabled = state.enabled; | |
_isMoving = state.isMoving == true; | |
}); | |
}); | |
} else { | |
bg.BackgroundGeolocation.stop().then((bg.State state) { | |
print('[stop] success: $state'); | |
// Reset odometer. | |
bg.BackgroundGeolocation.setOdometer(0.0); | |
setState(() { | |
_odometer = '0.0'; | |
_enabled = state.enabled; | |
_isMoving = state.isMoving == true; | |
}); | |
}); | |
} | |
} | |
// Manually toggle the tracking state: moving vs stationary | |
void _onClickChangePace() { | |
setState(() { | |
_isMoving = !_isMoving; | |
}); | |
print('[onClickChangePace] -> $_isMoving'); | |
bg.BackgroundGeolocation.changePace(_isMoving).then((bool isMoving) { | |
print('[changePace] success $isMoving'); | |
}).catchError((e) { | |
print('[changePace] ERROR: ${e.code}'); | |
}); | |
} | |
// Manually fetch the current position. | |
void _onClickGetCurrentPosition() { | |
bg.BackgroundGeolocation.getCurrentPosition( | |
persist: false, // <-- do not persist this location | |
desiredAccuracy: 0, // <-- desire best possible accuracy | |
timeout: 30000, // <-- wait 30s before giving up. | |
samples: 3 // <-- sample 3 location before selecting best. | |
) | |
.then((bg.Location location) { | |
print('[getCurrentPosition] - $location'); | |
}).catchError((error) { | |
print('[getCurrentPosition] ERROR: $error'); | |
}); | |
} | |
//// | |
// Event handlers | |
// | |
void _onLocation(bg.Location location) { | |
print('[location] - $location'); | |
final String odometerKM = (location.odometer / 1000.0).toStringAsFixed(1); | |
setState(() { | |
_content = encoder.convert(location.toMap()); | |
_odometer = odometerKM; | |
}); | |
} | |
void _onMotionChange(bg.Location location) { | |
print('[motionchange] - $location'); | |
} | |
void _onActivityChange(bg.ActivityChangeEvent event) { | |
print('[activitychange] - $event'); | |
setState(() { | |
_motionActivity = event.activity; | |
}); | |
} | |
void _onProviderChange(bg.ProviderChangeEvent event) { | |
print('$event'); | |
setState(() { | |
_content = encoder.convert(event.toMap()); | |
}); | |
} | |
void _onConnectivityChange(bg.ConnectivityChangeEvent event) { | |
print('$event'); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: | |
AppBar(title: const Text('Background Geolocation'), actions: <Widget>[ | |
Switch(value: _enabled, onChanged: _onClickEnable), | |
]), | |
body: SingleChildScrollView(child: Text(_content)), | |
bottomNavigationBar: BottomAppBar( | |
child: Container( | |
padding: const EdgeInsets.only(left: 5.0, right: 5.0), | |
child: Row( | |
mainAxisSize: MainAxisSize.max, | |
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
children: <Widget>[ | |
IconButton( | |
icon: const Icon(Icons.gps_fixed), | |
onPressed: _onClickGetCurrentPosition, | |
), | |
Text('$_motionActivity · $_odometer km'), | |
MaterialButton( | |
minWidth: 50.0, | |
color: _isMoving ? Colors.red : Colors.green, | |
onPressed: _onClickChangePace, | |
child: Icon(_isMoving ? Icons.pause : Icons.play_arrow, | |
color: Colors.white)) | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Yes, you can. You just need to take care with escaping
\\\n
You are assuming that note means something bad. It is not. It is exactly what's supposed to happen.
This plugin uses a number of foreground-services, keeping each activated only when required (when the device is in-motion). The default state of this plugin is to have no foreground-services activated, thus "destroyed".
When the device is detected to be in-motion (typically after movement of ~200 meters), a foreground-service is automatically re-launched and kept alive for as long as the device remains in motion, regardless if app is terminated or device rebooted.
If i use like that still work when app killed
Yes, that's what stopOnTerminate: false
means.
For Android only, your Flutter App
no longer exists and event-handlers will no longer be called (eg: BackgroundGeolocation.onLocation
).
See Wiki Android Headless Mode
I suggest you try the /example app at flutter_background_geolocation repo first.
Do not touch the code. Just boot the app on your device and observe logs after terminating the app.
The Github repo has a link to purchase at the top:
https://www.transistorsoft.com/shop/products/flutter-background-geolocation
Hi @transistorsoft.
For Android if the configuration include stopOnTerminate: false
and url: 'api endpoint'
and params: {...}
, when the app terminate, the plugin will continue uploading location to the endpoint with params too or only locations?
Yes. Config.params are appended to each http request, regardless of anything.
This plugin was originally developed for a disaster response app, tracking emergency workers in hurricanes and earthquakes where life depended on it.
you are free to manually engage location services by calling .changePace(true).
the automatic tracking requires the device move ~200 meters for iOS. For Android, the plugin is able to use the motion api to detect when device is moving (as long as user grants the “motion” runtime permission) and tracking can occur much less than 200 meters.
This is really not the place to seek specific tech support, in a code gist.
I suggest you post an issue at the GitHub repo.
hey, can i embed flutter app that using this library to native android app?
FWIW, I created a fork to update it for null safety and linting
https://gist.github.com/sisyfus/86a2817bc0d7c7f06e7cb866596c79d8
One question, in the case of the onLocation method, should it be configured only once for the whole app? or should it be instantiated in each part of the app where it is needed?
.onLocation is merely an event subscription. You can add as many as you wish or none at all. The /example app does this with separate subscribers updating info on the bottom-bar and another to print markers on the map.
hey, I am a beginner and I am not understanding how it works do we have to call the event manually or it will automatically get called?
When I am running flutter run
then it invokes two event location and motion
after that it is not showing any update on location?
This is what I am getting I/flutter ( 6786): [location] - [Location {odometer: 0.0, activity: {confidence: 100, type: still}, extras: {}, event: motionchange, battery: {level: 0.58, is_charging: true}, uuid: d3342545-3e76-4f88-b113-8fb38e9110b7, age: 185, coords: {altitude: -40.5, heading: -1.0, latitude: 19.3145539, accuracy: 87.27, heading_accuracy: -1.0, altitude_accuracy: 9.17, speed_accuracy: 1.5, speed: 0.0, age: 220, longitude: 72.8565985, ellipsoidal_altitude: -40.5}, is_moving: false, timestamp: 2024-04-24T08:50:37.364Z}]
I/flutter ( 6786): [motionchange] - [Location {odometer: 0.0, activity: {confidence: 100, type: still}, extras: {}, event: motionchange, battery: {level: 0.58, is_charging: true}, uuid: d3342545-3e76-4f88-b113-8fb38e9110b7, age: 185, coords: {altitude: -40.5, heading: -1.0, latitude: 19.3145539, accuracy: 87.27, heading_accuracy: -1.0, altitude_accuracy: 9.17, speed_accuracy: 1.5, speed: 0.0, age: 220, longitude: 72.8565985, ellipsoidal_altitude: -40.5}, is_moving: false, timestamp: 2024-04-24T08:50:37.364Z}]
and later when terminating the app then it is not printing anything
☯️ onPause
D/TSLocationManager( 6786): [c.t.l.l.LifecycleManager onStop] ☯️ onStop
D/TSBackgroundFetch( 6786): ☯️ onStop
I/TSLocationManager( 6786): [c.t.l.scheduler.ScheduleEvent a]
I/TSLocationManager( 6786): ╔═════════════════════════════════════════════
I/TSLocationManager( 6786): ║ ⏰ OneShot event fired: TERMINATE_EVENT
I/TSLocationManager( 6786): ╠═════════════════════════════════════════════
D/TSLocationManager( 6786): [c.t.l.event.TerminateEvent$a onChange]
D/TSLocationManager( 6786): ℹ️ TERMINATE_EVENT ignored (MainActivity is still active).
PLEASE HELP ME!
when I am terminating then callback function is not getting called
It is not detecting the motion.
This is not the place to seek support. I suggest you post an issue at the GitHub repo.
I am using this flutter_background_geolocation package to fetch the user's current location from the background service (workmanager). but it shows this error
Error:
Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
How can I resolve it? Although I am fetching location correctly when I used code onPressed listener. but on background service, it gave me that error and did not fetch the location.
returning read-only value.
A resd-only value is all the plug-in wants.. This is not a problem. I’m aware of this warning.
A gist is not the place to seek tech support. Post an issue at the GitHub repo.
I updated null-safety and build ready flutter 3.22.0
https://gist.github.com/trunghieuvn/a5a235d6228f1bf00556bd47cb869321
A How to Implement Article for implementing this in FlutterFlow Apps will be Greatly Appreciated.,
Also How to Receive and Store the Data using FASTAPI Python into Postgresql., Will make a Valuable addon to your Project.,
Howdy, my friend, I have a question, I was using version 4.12.3, and now I have version 4.14.1, and now it is asking me for a license. Do I have to buy another one for the new version?
Do I have to buy another one for the new version?
Why are you asking a licensing question on a random gist?
A How to Implement Article for implementing this in FlutterFlow Apps will be Greatly Appreciated.
@ravisvf how to implement plugins on FlutterFlow (there’s no magic, easy way): https://docs.flutterflow.io/customizing-your-app/manage-custom-code-in-github
Listen, I only want to get latitude and longitude in real time while the app is running in the background. Is this package suitable for that?
Why don’t you try it and see?
Tech support is not handled by posting at a Gist. Post an issue at the Github repo.
Can i use locationTemplate to build graphql json (example below)?
And what does a locationTemplate like for sending a batch from several locations?