react-native-background-geolocation
Version:
The most sophisticated cross-platform background location-tracking & geofencing module with battery-conscious motion-detection intelligence
663 lines (570 loc) • 20.1 kB
JavaScript
//'use strict'
import {
Platform,
AppRegistry
} from "react-native"
import NativeModule from './NativeModule';
import DeviceSettings from './DeviceSettings';
import Logger from './Logger';
import TransistorAuthorizationService from './TransistorAuthorizationService';
import {
LogLevel,
DesiredAccuracy,
PersistMode,
AuthorizationStatus,
AccuracyAuthorization,
LocationRequest,
AuthorizationStrategy,
LocationFilterPolicy,
KalmanProfile,
NotificationPriority,
HttpMethod,
TriggerActivity,
ActivityType,
Event
} from '@transistorsoft/background-geolocation-types';
// Build a lookup table of allowed event names (runtime)
const VALID_EVENT_NAMES = new Set(Object.values(Event));
let _deviceSettingsInstance = null;
const TAG = "BackgroundGeolocation";
const LOG_LEVEL_OFF = LogLevel.Off;
const LOG_LEVEL_ERROR = LogLevel.Error;
const LOG_LEVEL_WARNING = LogLevel.Warning;
const LOG_LEVEL_INFO = LogLevel.Info;
const LOG_LEVEL_DEBUG = LogLevel.Debug;
const LOG_LEVEL_VERBOSE = LogLevel.Verbose;
const DESIRED_ACCURACY_NAVIGATION = DesiredAccuracy.Navigation;
const DESIRED_ACCURACY_HIGH = DesiredAccuracy.High;
const DESIRED_ACCURACY_MEDIUM = DesiredAccuracy.Medium;
const DESIRED_ACCURACY_LOW = DesiredAccuracy.Low;
const DESIRED_ACCURACY_VERY_LOW = DesiredAccuracy.VeryLow;
const DESIRED_ACCURACY_LOWEST = DesiredAccuracy.Lowest;
const AUTHORIZATION_STATUS_NOT_DETERMINED = AuthorizationStatus.NotDetermined;
const AUTHORIZATION_STATUS_RESTRICTED = AuthorizationStatus.Restricted;
const AUTHORIZATION_STATUS_DENIED = AuthorizationStatus.Denied;
const AUTHORIZATION_STATUS_ALWAYS = AuthorizationStatus.Always;
const AUTHORIZATION_STATUS_WHEN_IN_USE = AuthorizationStatus.WhenInUse;
const NOTIFICATION_PRIORITY_DEFAULT = NotificationPriority.Default;
const NOTIFICATION_PRIORITY_HIGH = NotificationPriority.High;
const NOTIFICATION_PRIORITY_LOW = NotificationPriority.Low;
const NOTIFICATION_PRIORITY_MAX = NotificationPriority.Max;
const NOTIFICATION_PRIORITY_MIN = NotificationPriority.Min;
const ACTIVITY_TYPE_OTHER = ActivityType.Other;
const ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION = ActivityType.AutomotiveNavigation;
const ACTIVITY_TYPE_FITNESS = ActivityType.Fitness;
const ACTIVITY_TYPE_OTHER_NAVIGATION = ActivityType.OtherNavigation;
const ACTIVITY_TYPE_AIRBORNE = ActivityType.Airborne;
const LOCATION_AUTHORIZATION_ALWAYS = LocationRequest.Always;
const LOCATION_AUTHORIZATION_WHEN_IN_USE = LocationRequest.WhenInUse;
const LOCATION_AUTHORIZATION_ANY = LocationRequest.Any;
const PERSIST_MODE_ALL = PersistMode.All;
const PERSIST_MODE_LOCATION = PersistMode.Location;
const PERSIST_MODE_GEOFENCE = PersistMode.Geofence;
const PERSIST_MODE_NONE = PersistMode.None;
const ACCURACY_AUTHORIZATION_FULL = AccuracyAuthorization.Full;
const ACCURACY_AUTHORIZATION_REDUCED = AccuracyAuthorization.Reduced;
const emptyFn = function() {}
export default class BackgroundGeolocation {
static get EVENT_BOOT() { return Event.Boot; }
static get EVENT_TERMINATE() { return Event.Terminate; }
static get EVENT_LOCATION() { return Event.Location; }
static get EVENT_MOTIONCHANGE() { return Event.MotionChange; }
static get EVENT_HTTP() { return Event.Http; }
static get EVENT_HEARTBEAT() { return Event.Heartbeat; }
static get EVENT_PROVIDERCHANGE() { return Event.ProviderChange; }
static get EVENT_ACTIVITYCHANGE() { return Event.ActivityChange; }
static get EVENT_LOCATIONFILTER() { return Event.LocationFilter; }
static get EVENT_GEOFENCE() { return Event.Geofence; }
static get EVENT_GEOFENCESCHANGE() { return Event.GeofencesChange; }
static get EVENT_ENABLEDCHANGE() { return Event.EnabledChange; }
static get EVENT_CONNECTIVITYCHANGE() { return Event.ConnectivityChange; }
static get EVENT_SCHEDULE() { return Event.Schedule; }
static get EVENT_POWERSAVECHANGE() { return Event.PowerSaveChange; }
static get EVENT_NOTIFICATIONACTION() { return Event.NotificationAction; }
static get EVENT_AUTHORIZATION() { return Event.Authorization; }
static get LOG_LEVEL_OFF() { return LOG_LEVEL_OFF; }
static get LOG_LEVEL_ERROR() { return LOG_LEVEL_ERROR; }
static get LOG_LEVEL_WARNING() { return LOG_LEVEL_WARNING; }
static get LOG_LEVEL_INFO() { return LOG_LEVEL_INFO; }
static get LOG_LEVEL_DEBUG() { return LOG_LEVEL_DEBUG; }
static get LOG_LEVEL_VERBOSE() { return LOG_LEVEL_VERBOSE; }
static get ACTIVITY_TYPE_OTHER() { return ACTIVITY_TYPE_OTHER;}
static get ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION() { return ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION;}
static get ACTIVITY_TYPE_FITNESS() { return ACTIVITY_TYPE_FITNESS;}
static get ACTIVITY_TYPE_OTHER_NAVIGATION() { return ACTIVITY_TYPE_OTHER_NAVIGATION;}
static get ACTIVITY_TYPE_AIRBORNE() { return ACTIVITY_TYPE_AIRBORNE; }
static get DESIRED_ACCURACY_NAVIGATION() { return DESIRED_ACCURACY_NAVIGATION; }
static get DESIRED_ACCURACY_HIGH() { return DESIRED_ACCURACY_HIGH; }
static get DESIRED_ACCURACY_MEDIUM() { return DESIRED_ACCURACY_MEDIUM; }
static get DESIRED_ACCURACY_LOW() { return DESIRED_ACCURACY_LOW; }
static get DESIRED_ACCURACY_VERY_LOW() { return DESIRED_ACCURACY_VERY_LOW; }
static get DESIRED_ACCURACY_LOWEST() { return DESIRED_ACCURACY_LOWEST; }
static get AUTHORIZATION_STATUS_NOT_DETERMINED() { return AUTHORIZATION_STATUS_NOT_DETERMINED; }
static get AUTHORIZATION_STATUS_RESTRICTED() { return AUTHORIZATION_STATUS_RESTRICTED; }
static get AUTHORIZATION_STATUS_DENIED() { return AUTHORIZATION_STATUS_DENIED; }
static get AUTHORIZATION_STATUS_ALWAYS() { return AUTHORIZATION_STATUS_ALWAYS; }
static get AUTHORIZATION_STATUS_WHEN_IN_USE() { return AUTHORIZATION_STATUS_WHEN_IN_USE; }
static get NOTIFICATION_PRIORITY_DEFAULT() { return NOTIFICATION_PRIORITY_DEFAULT; }
static get NOTIFICATION_PRIORITY_HIGH() { return NOTIFICATION_PRIORITY_HIGH; }
static get NOTIFICATION_PRIORITY_LOW() { return NOTIFICATION_PRIORITY_LOW; }
static get NOTIFICATION_PRIORITY_MAX() { return NOTIFICATION_PRIORITY_MAX; }
static get NOTIFICATION_PRIORITY_MIN() { return NOTIFICATION_PRIORITY_MIN; }
static get LOCATION_AUTHORIZATION_ALWAYS() { return LOCATION_AUTHORIZATION_ALWAYS}
static get LOCATION_AUTHORIZATION_WHEN_IN_USE() { return LOCATION_AUTHORIZATION_WHEN_IN_USE}
static get LOCATION_AUTHORIZATION_ANY() { return LOCATION_AUTHORIZATION_ANY}
static get PERSIST_MODE_ALL() { return PERSIST_MODE_ALL; }
static get PERSIST_MODE_LOCATION() { return PERSIST_MODE_LOCATION; }
static get PERSIST_MODE_GEOFENCE() { return PERSIST_MODE_GEOFENCE; }
static get PERSIST_MODE_NONE() { return PERSIST_MODE_NONE; }
static get ACCURACY_AUTHORIZATION_FULL() { return ACCURACY_AUTHORIZATION_FULL; }
static get ACCURACY_AUTHORIZATION_REDUCED() { return ACCURACY_AUTHORIZATION_REDUCED; }
// Enum namespaces (mirroring @transistorsoft/background-geolocation-types)
static get LogLevel() {
return LogLevel;
}
static get DesiredAccuracy() {
return DesiredAccuracy;
}
static get PersistMode() {
return PersistMode;
}
static get AuthorizationStatus() {
return AuthorizationStatus;
}
static get AccuracyAuthorization() {
return AccuracyAuthorization;
}
static get LocationRequest() {
return LocationRequest;
}
static get AuthorizationStrategy() {
return AuthorizationStrategy;
}
static get LocationFilterPolicy() {
return LocationFilterPolicy;
}
static get KalmanProfile() {
return KalmanProfile;
}
static get NotificationPriority() {
return NotificationPriority;
}
static get HttpMethod() {
return HttpMethod;
}
static get TriggerActivity() {
return TriggerActivity;
}
static get ActivityType() {
return ActivityType;
}
static get Event() {
return Event;
}
static get deviceSettings() {
if (_deviceSettingsInstance === null) {
_deviceSettingsInstance = new DeviceSettings();
}
return _deviceSettingsInstance;
}
/**
* Core Plugin Control Methods
*/
static ready(config) {
return NativeModule.ready(config||{});
}
/**
* Reset plugin confg to default
*/
static reset(config) {
return NativeModule.reset(config);
}
/**
* Perform initial configuration of plugin. Reset config to default before applying supplied configuration
*/
static configure(config) {
return NativeModule.configure(config);
}
static requestPermission() {
return NativeModule.requestPermission();
}
static requestTemporaryFullAccuracy(purpose) {
return NativeModule.requestTemporaryFullAccuracy(purpose);
}
static getProviderState() {
return NativeModule.getProviderState();
}
/**
* Listen to a plugin event
*/
static addListener(event, success, failure) {
if (typeof(event) != 'string') { throw "BackgroundGeolocation#on must be provided a {String} event as 1st argument." }
if (!VALID_EVENT_NAMES.has(event)) {
throw `BackgroundGeolocation#on - Unknown event '${event}'`;
}
if (typeof(success) != 'function') { throw "BackgroundGeolocation#on must be provided a callback as 2nd argument. If you're attempting to use the Promise API to listen to an event, it won't work, since a Promise can only evaluate once, while the callback function must be executed for each event." }
return NativeModule.addListener.apply(NativeModule, arguments);
}
static onLocation(success, failure) {
return this.addListener(Event.Location, success, failure);
}
static onMotionChange(callback) {
return this.addListener(Event.MotionChange, callback);
}
static onHttp(callback) {
return this.addListener(Event.Http, callback);
}
static onHeartbeat(callback) {
return this.addListener(Event.Heartbeat, callback);
}
static onProviderChange(callback) {
return this.addListener(Event.ProviderChange, callback);
}
static onActivityChange(callback) {
return this.addListener(Event.ActivityChange, callback);
}
static onLocationFilter(callback) {
return this.addListener(Event.LocationFilter, callback);
}
static onGeofence(callback) {
return this.addListener(Event.Geofence, callback);
}
static onGeofencesChange(callback) {
return this.addListener(Event.GeofencesChange, callback);
}
static onSchedule(callback) {
return this.addListener(Event.Schedule, callback);
}
static onEnabledChange(callback) {
return this.addListener(Event.EnabledChange, callback);
}
static onConnectivityChange(callback) {
return this.addListener(Event.ConnectivityChange, callback);
}
static onPowerSaveChange(callback) {
return this.addListener(Event.PowerSaveChange, callback);
}
static onNotificationAction(callback) {
return this.addListener(Event.NotificationAction, callback);
}
static onAuthorization(callback) {
return this.addListener(Event.Authorization, callback);
}
/**
* Remove a single plugin event-listener, supplying a reference to the handler initially supplied to #un
*/
static removeListener(event, handler, success, failure) {
if (typeof(event) != 'string') { throw "BackgroundGeolocation#un must be provided a {String} event as 1st argument" }
if (!VALID_EVENT_NAMES.has(event)) { throw "BackgroundGeolocation#un - Unknown event '" + event + "'" }
NativeModule.removeListener.apply(NativeModule, arguments);
}
/**
* Remove all event listeners
*/
static removeListeners(success, failure) {
if (!arguments.length) {
return NativeModule.removeListeners();
} else {
NativeModule.removeListeners().then(success).catch(failure);
}
}
// @alias -> #removeListeners
static removeAllListeners(success, failure) {
this.removeListeners.apply(this, arguments);
}
/**
* Fetch current plugin configuration
*/
static getState(success, failure) {
return NativeModule.getState();
}
/**
* Start the plugin
*/
static start() {
return NativeModule.start();
}
/**
* Stop the plugin
*/
static stop() {
return NativeModule.stop();
}
/**
* Start the scheduler
*/
static startSchedule() {
return NativeModule.startSchedule();
}
/**
* Stop the scheduler
*/
static stopSchedule() {
return NativeModule.stopSchedule();
}
/**
* Initiate geofences-only mode
*/
static startGeofences() {
return NativeModule.startGeofences();
}
/**
* Start an iOS background-task, provding 180s of background running time
*/
static startBackgroundTask() {
return NativeModule.startBackgroundTask();
}
/**
* Signal to iOS that your background-task from #startBackgroundTask is complete
* TODO Rename native method #finish -> #stopBackgroundTask.
*/
static stopBackgroundTask(taskId) {
return NativeModule.stopBackgroundTask(taskId);
}
/**
* @deprecated Use #stopBackgroundTask
*/
static finish(taskId) {
this.stopBackgroundTask.apply(this, arguments);
}
/**
* Register HeadlessTask
* Have to wrap execution to finish our own headless-task because there's an unknown issue with TurboModules in new arch
* where RN's HeadlessJsTaskSupport is null. That module can automatically finish RN headless-tasks.
*/
static registerHeadlessTask(taskProvider) {
AppRegistry.registerHeadlessTask(TAG, () => {
// return to RN's AppRegistry a Function that returns a Promise.
return (event) => {
return new Promise((resolve, reject) => {
const taskId = event._transistorHeadlessTaskId;
delete(event._transistorHeadlessTaskId);
taskProvider(event).then(() => {
BackgroundGeolocation.finishHeadlessTask(taskId);
resolve();
}).catch(reason => {
BackgroundGeolocation.finishHeadlessTask(taskId);
reject(reason);
});
});
}
});
}
/**
* @private
* Signal completion of a react-native headless-task. This helps RN free-up resources allocated to the headless-task execution.
*/
static finishHeadlessTask(taskId) {
return NativeModule.finishHeadlessTask(taskId);
}
/**
* Toggle motion-state between stationary <-> moving
*/
static changePace(isMoving) {
return NativeModule.changePace(isMoving);
}
/**
* Provide new configuration to the plugin. This configuration will be *merged* to current configuration
*/
static setConfig(config) {
return NativeModule.setConfig(config);
}
/**
* HTTP & Persistence
*
*/
static getLocations(query) {
return NativeModule.getLocations(query);
}
/**
* Fetch the current count of location records in database
*/
static getCount() {
return NativeModule.getCount();
}
/**
* Destroy all records in locations database
*/
static destroyLocations() {
return NativeModule.destroyLocations();
}
/**
* Destroy a single location by uuid
*/
static destroyLocation(uuid) {
return NativeModule.destroyLocation(uuid);
}
/**
* Destroy a single record by uuid
*/
// @deprecated
static clearDatabase() {
return this.destroyLocations();
}
/**
* Insert a single record into locations database
*/
static insertLocation(location) {
return NativeModule.insertLocation(location);
}
/**
* Manually initiate an HTTP sync operation
*/
static sync() {
return NativeModule.sync();
}
/**
* Fetch the current value of odometer
*/
static getOdometer() {
return NativeModule.getOdometer();
}
/**
* Set the value of the odometer
*/
static setOdometer(value) {
return NativeModule.setOdometer(value);
}
/**
* Reset the value of odometer to 0
*/
static resetOdometer() {
return NativeModule.setOdometer(0);
}
/**
* Geofencing Methods
*/
/**
* Add a single geofence
*/
static addGeofence(config) {
return NativeModule.addGeofence(config);
}
/**
* Remove a single geofence by identifier
*/
static removeGeofence(identifier) {
return NativeModule.removeGeofence(identifier);
}
/**
* Add a list of geofences
*/
static addGeofences(geofences) {
return NativeModule.addGeofences(geofences);
}
/**
* Remove geofences. You may either supply an array of identifiers or nothing to destroy all geofences.
* 1. removeGeofences() <-- Promise
* 2. removeGeofences(['foo']) <-- Promise
*
* 3. removeGeofences(success, [failure])
* 4. removeGeofences(['foo'], success, [failure])
*/
static removeGeofences() {
return NativeModule.removeGeofences();
}
/**
* Fetch all geofences from database
*/
static getGeofences() {
return NativeModule.getGeofences();
}
/**
* Fetch a single geofence
*/
static getGeofence(identifier) {
return NativeModule.getGeofence(identifier);
}
/**
* Return true if geofence was added
*/
static geofenceExists(identifier) {
return NativeModule.geofenceExists(identifier);
}
/**
* Fetch the current position from location-services
*/
static getCurrentPosition(options) {
return NativeModule.getCurrentPosition(options)
}
/**
* Begin watching a stream of locations
*/
static watchPosition(options, success, failure) {
if (typeof success !== 'function') {
throw TAG + '#watchPosition requires a success callback';
}
options = options || {};
failure = failure || emptyFn;
return NativeModule.watchPosition(options, success, failure);
}
/**
* Stop watching location
*/
static stopWatchPosition(watchId) {
return NativeModule.stopWatchPosition(watchId);
}
/**
* Set the logLevel. This is just a helper method for setConfig({logLevel: level})
*/
static setLogLevel(value) {
return NativeModule.setLogLevel(value);
}
/**
* Fetch the entire contents of log database returned as a String
*/
static getLog() {
return Logger.getLog();
}
/**
* Destroy all contents of log database
*/
static destroyLog() {
return Logger.destroyLog();
}
/**
* Open deafult email client on device to email the contents of log database attached as a compressed file attachement
*/
static emailLog(email, query) {
query = query || {};
return Logger.emailLog(email, query);
}
/**
* Has device OS initiated power-saving mode?
*/
static isPowerSaveMode() {
return NativeModule.isPowerSaveMode();
}
/**
* Fetch the state of this device's available motion-sensors
*/
static getSensors() {
return NativeModule.getSensors();
}
/**
* Play a system sound via the plugin's Sound API
*/
static playSound(soundId) {
return NativeModule.playSound(soundId);
}
static findOrCreateTransistorAuthorizationToken(orgname, username, url) {
return TransistorAuthorizationService.findOrCreate(orgname, username, url);
}
static destroyTransistorAuthorizationToken(url) {
return TransistorAuthorizationService.destroy(url);
}
/**
* Insert a log message into the plugin's log database
*/
static get logger() { return Logger; }
static getDeviceInfo() {
return NativeModule.getDeviceInfo();
}
static async transistorTrackerParams() {
let deviceInfo = await NativeModule.getDeviceInfo();
deviceInfo.uuid = deviceInfo.model;
return {
device: deviceInfo
};
}
}