Awesome
Background Geolocation for Capacitor ยท
![npm](https://img.shields.io/npm/v/@transistorsoft/capacitor-background-geolocation.svg)
The most sophisticated background location-tracking & geofencing module with battery-conscious motion-detection intelligence for iOS and Android.
The plugin's Philosophy of Operation is to use motion-detection APIs (using accelerometer, gyroscope and magnetometer) to detect when the device is moving and stationary.
-
When the device is detected to be moving, the plugin will automatically start recording a location according to the configured
distanceFilter
(meters). -
When the device is detected be stationary, the plugin will automatically turn off location-services to conserve energy.
Also available for Flutter, Cordova, and React Native.
The Android module requires purchasing a license. However, it will work for DEBUG builds. It will not work with RELEASE builds without purchasing a license.
(2018) This plugin is supported full-time and field-tested daily since 2013.
:rotating_light: This plugin requires Capacitor 5 :rotating_light:
For Capacitor 4, use the 4.x version of the plugin.
Contents
-
๐ซ Help!
-
:books: API Documentation
-
Installing the Plugin
-
Setup Guides
-
Configure your License
-
Using the plugin
-
Example
-
Debugging
-
Demo Application
-
Testing Server
-
Privacy Policy
:large_blue_diamond: Installing the Plugin
:warning: Capacitor 3+ required.
With yarn
$ yarn add @transistorsoft/capacitor-background-geolocation
$ yarn add @transistorsoft/capacitor-background-fetch
$ npx cap sync
With npm
$ npm install @transistorsoft/capacitor-background-geolocation --save
$ npm install @transistorsoft/capacitor-background-fetch --save
$ npx cap sync
:large_blue_diamond: Setup Guides
iOS
Android
:large_blue_diamond: Configure your license
-
Login to Customer Dashboard to generate an application key: www.transistorsoft.com/shop/customers
-
Add your license-key to
android/app/src/main/AndroidManifest.xml
:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.transistorsoft.backgroundgeolocation.react">
<application
android:name=".MainApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme">
<!-- capacitor-background-geolocation licence -->
+ <meta-data android:name="com.transistorsoft.locationmanager.license" android:value="YOUR_LICENCE_KEY_HERE" />
.
.
.
</application>
</manifest>
:large_blue_diamond: Using the plugin
import BackgroundGeolocation from "@transistorsoft/capacitor-background-geolocation";
:large_blue_diamond: Example
There are three main steps to using BackgroundGeolocation
- Wire up event-listeners.
#ready
the plugin.#start
the plugin.
:warning: Do not execute any API method which will require accessing location-services until the callback to #ready
executes (eg: #getCurrentPosition
, #watchPosition
, #start
).
// NO! .ready() has not resolved.
BackgroundGeolocation.getCurrentPosition(options);
BackgroundGeolocation.start();
BackgroundGeolocation.ready(config).then((state) => {
// YES -- .ready() has now resolved.
BackgroundGeolocation.getCurrentPosition(options);
BackgroundGeolocation.start();
});
// NO! .ready() has not resolved.
BackgroundGeolocation.getCurrentPosition(options);
BackgroundGeolocation.start();
Example 1. โ React
<img alt="alt_text" width="50px" src="https://hackr.io/tutorials/react/logo-react.svg?ver=1610114789" /> <details> <summary>View Source</summary>import {
IonContent,
IonHeader,
IonPage,
IonTitle,
IonToolbar,
IonButtons,
IonToggle,
IonItemDivider,
IonLabel
} from '@ionic/react';
import React from "react";
import BackgroundGeolocation, {
Subscription
} from "@transistorsoft/capacitor-background-geolocation";
const HelloWorld: React.FC = () => {
const [ready, setReady] = React.useState(false);
const [enabled, setEnabled] = React.useState(false);
const [events, setEvents] = React.useState<any[]>([]);
const addEvent = (name: string, event:any) => {
setEvents(previous => [...previous, {
name: name,
json: JSON.stringify(event, null, 2)
}]);
}
React.useEffect(() => {
/// 1. Subscribe to events.
const onLocation:Subscription = BackgroundGeolocation.onLocation((location) => {
addEvent('onLocation', location);
})
const onMotionChange:Subscription = BackgroundGeolocation.onMotionChange((event) => {
addEvent('onMotionChange', event);
});
const onActivityChange:Subscription = BackgroundGeolocation.onActivityChange((event) => {
addEvent('onActivityChange', event);
})
const onProviderChange:Subscription = BackgroundGeolocation.onProviderChange((event) => {
addEvent('onProviderChange', event);
})
/// 2. ready the plugin.
BackgroundGeolocation.ready({
// Geolocation Config
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
distanceFilter: 10,
// Activity Recognition
stopTimeout: 5,
// Application config
debug: true, // <-- enable this hear sounds for background-geolocation life-cycle.
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
stopOnTerminate: false, // <-- Allow the background-service to continue tracking when user closes the app.
startOnBoot: true, // <-- Auto start tracking when device is powered-up.
}).then((state) => {
setReady(true);
setEnabled(state.enabled)
addEvent('State', state);
});
return () => {
// Remove BackgroundGeolocation event-subscribers when the View is removed or refreshed
// during development live-reload. Without this, event-listeners will accumulate with
// each refresh during live-reload.
onLocation.remove();
onMotionChange.remove();
onActivityChange.remove();
onProviderChange.remove();
}
}, []);
/// 3. start / stop BackgroundGeolocation
React.useEffect(() => {
if (!ready) { return }
if (enabled) {
BackgroundGeolocation.start();
} else {
BackgroundGeolocation.stop();
setEvents([]);
}
}, [enabled]);
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="end">
<IonLabel>Toggle to <code>{(enabled ? 'stop()' : 'start()')}</code> —></IonLabel>
<IonToggle checked={enabled} onIonChange={e => setEnabled(e.detail.checked)}/>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<div style={{padding:10}}>
{ events.slice().reverse().map((event, i) => (
<div key={i}>
<p><strong>{event.name}</strong></p>
<small><pre><code>{event.json}</code></pre></small>
<IonItemDivider />
</div>
))}
</div>
</IonContent>
</IonPage>
)
}
</details>
Example 2. โ Angular
<img alt="alt_text" width="55px" src="https://dl.dropbox.com/s/w4hw88clxqmlis2/angular-logo.svg?dl=1" /> <details> <summary>View Source</summary>import {
Component,
NgZone,
OnDestroy
} from '@angular/core'
import BackgroundGeolocation, {
Location,
Subscription
} from "@transistorsoft/capacitor-background-geolocation";
@Component({
selector: 'hello-world',
template: `
<ion-header>
<ion-toolbar>
<ion-buttons slot="end">
<ion-label>Toggle to <code>{{(enabled ? 'stop()' : 'start()')}}</code> —></ion-label>
<ion-toggle [(ngModel)]="enabled" (ionChange)="onToggleEnabled()" style="display:block;"></ion-toggle>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content fullscreen>
<div *ngFor="let event of events.slice().reverse()" style="padding:10px">
<div>
<p><strong>{{event.name}}</strong></p>
<small><pre><code>{{event.json}}</code></pre></small>
<ion-item-divider></ion-item-divider>
</div>
</div>
</ion-content>
`,
styles: []
})
export class HelloWorldPage implements OnDestroy {
ready:boolean = false;
enabled:boolean = false;
events:any = [];
subscriptions:Subscription[] = [];
constructor(private zone:NgZone) {}
/// WARNING: DO NOT Use ionViewWillEnter to configure the SDK -- use ngAfterContentInit.
/// ionViewWillEnter only executes when the app is brought to the foreground.
/// It will NOT execute when the app is launched in the background, as the SDK will often do.
///
ngAfterContentInit() {
/// Step 1: Subscribe to BackgroundGeolocation events.
this.subscriptions.push(BackgroundGeolocation.onLocation((location) => {
this.addEvent('onLocation', location);
}))
this.subscriptions.push(BackgroundGeolocation.onMotionChange((event) => {
this.addEvent('onMotionChange', event);
}))
this.subscriptions.push(BackgroundGeolocation.onActivityChange((event) => {
this.addEvent('onActivityChange', event);
}))
this.subscriptions.push(BackgroundGeolocation.onProviderChange((event) => {
this.addEvent('onProviderChange', event);
}))
/// Step 2: Ready the plugin.
BackgroundGeolocation.ready({
// Geolocation Config
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
distanceFilter: 10,
// Activity Recognition
stopTimeout: 5,
// Application config
debug: true, // <-- enable this hear sounds for background-geolocation life-cycle.
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
stopOnTerminate: false, // <-- Allow the background-service to continue tracking when user closes the app.
startOnBoot: true, // <-- Auto start tracking when device is powered-up.
}).then((state) => {
// BackgroundGeolocation is now ready to use.
this.ready = true;
this.enabled = state.enabled;
this.addEvent('State', state);
});
}
/// When view is destroyed, be sure to .remove() all BackgroundGeolocation
/// event-subscriptions.
ngOnDestroy() {
this.subscriptions.forEach((subscription:Subscription) => {
subscription.remove();
})
}
/// Add an event to the view.
addEvent(name:string, event:any) {
this.zone.run(() => {
this.events.push({
name: name,
json: JSON.stringify(event, null, 2)
})
})
}
/// Toggle the plugin on/off.
onToggleEnabled() {
if (!this.ready) { return }
this.events = [];
if (this.enabled) {
BackgroundGeolocation.start().then((state) => {
this.addEvent('State', state);
})
} else {
BackgroundGeolocation.stop().then((state) => {
this.addEvent('State', state);
})
}
}
}
</details>
Promise API
The BackgroundGeolocation
Javascript API supports Promises for nearly every method (the exceptions are #watchPosition
and adding event-listeners via onXXX
methods (eg: onLocation
, onProviderChange
). For more information, see the API Documentation
:large_blue_diamond: Demo Application
A fully-featured Demo App is available in this repo, for both React and Angular. After first cloning this repo, follow the installation instructions in the README there. This demo-app includes an advanced settings-screen allowing you to quickly experiment with all the different settings available for each platform.
:large_blue_diamond: Simple Testing Server
A simple Node-based web-application with SQLite database is available for field-testing and performance analysis. If you're familiar with Node, you can have this server up-and-running in about one minute.