Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save christocracy/a0464846de8a9c27c7e9de5616082878 to your computer and use it in GitHub Desktop.
Save christocracy/a0464846de8a9c27c7e9de5616082878 to your computer and use it in GitHub Desktop.
Flutter Background Geolocation hello_world.dart https://shop.transistorsoft.com/blogs/news
/**
* flutter_background_geolocation Hello World
* https://github.com/transistorsoft/flutter_background_geolocation
*/
import 'package:flutter/material.dart';
import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;
////
// For pretty-printing location JSON. Not a requirement of flutter_background_geolocation
//
import 'dart:convert';
JsonEncoder encoder = new JsonEncoder.withIndent(" ");
//
////
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'BackgroundGeolocation Demo',
theme: new ThemeData(
primarySwatch: Colors.amber,
),
home: new MyHomePage(title: 'BackgroundGeolocation Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isMoving;
bool _enabled;
String _motionActivity;
String _odometer;
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;
});
});
}
void _onClickEnable(enabled) {
if (enabled) {
bg.BackgroundGeolocation.start().then((bg.State state) {
print('[start] success $state');
setState(() {
_enabled = state.enabled;
_isMoving = state.isMoving;
});
});
} 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;
});
});
}
}
// 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.toString());
});
}
// 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');
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: Icon(Icons.gps_fixed),
onPressed: _onClickGetCurrentPosition,
),
Text('$_motionActivity · $_odometer km'),
MaterialButton(
minWidth: 50.0,
child: Icon((_isMoving) ? Icons.pause : Icons.play_arrow, color: Colors.white),
color: (_isMoving) ? Colors.red : Colors.green,
onPressed: _onClickChangePace
)
]
)
)
),
);
}
}
@christocracy
Copy link
Author

Does the debug/test version allows testing on real iPhone and real Android phone?

iOS is free. Only Android consumes license keys.

Android is fully functional in DEBUG builds without a license so you can try before you buy.

@davidzachariah
Copy link

Thanks, I will try this

@syedadeel2
Copy link

@christocracy Is there any way to find out either its a Driving Mode or Walking mode?

@christocracy
Copy link
Author

Listen to onActivityChange event.

@AhmedTitef
Copy link

This package is awesome. I am wondering if there is a function where the app continues to get location after it gets terminated totally from the background?
Thanks in advance

@ariefwijaya
Copy link

My question is same as @AhmedTitef, is it possible?, or there is an autostart background service after terminated?

@christocracy
Copy link
Author

stopOnTerminate: false, startOnBoot: true

@AlexKenbo
Copy link

AlexKenbo commented Apr 4, 2021

Can i use locationTemplate to build graphql json (example below)?
And what does a locationTemplate like for sending a batch from several locations?

{
    "variables": {{"objects": [{"lng": "1", "lat": "1", "driverID": 1},{"lng": "2", "lat": "2", "driverID": 2}]}},
    "extensions": {},
    "operationName": "InsertPoints",
    "query": "mutation InsertPoints($objects: [track_point_insert_input!]!) { \n insert_track_point(objects: $objects) { \n affected_rows \n} \n}"
}

@christocracy
Copy link
Author

Yes, you can. You just need to take care with escaping

\\\n

@erayhamurlu
Copy link

When i first install package work well but then says. "TrackingService destroyed "

Ekran Resmi 2021-06-08 14 57 43

@christocracy
Copy link
Author

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

@christocracy
Copy link
Author

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.

@christocracy
Copy link
Author

christocracy commented Jun 8, 2021

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

@christocracy
Copy link
Author

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.

@christocracy
Copy link
Author

@DevelopersCourt
Copy link

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?

@christocracy
Copy link
Author

Yes. Config.params are appended to each http request, regardless of anything.

@christocracy
Copy link
Author

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.

@christocracy
Copy link
Author

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.

@mrzky
Copy link

mrzky commented Mar 20, 2023

hey, can i embed flutter app that using this library to native android app?

@sisyfus
Copy link

sisyfus commented Jan 17, 2024

FWIW, I created a fork to update it for null safety and linting
https://gist.github.com/sisyfus/86a2817bc0d7c7f06e7cb866596c79d8

@jacsdev
Copy link

jacsdev commented Mar 1, 2024

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?

@christocracy
Copy link
Author

.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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment