react-native-bg-geolocation 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BgGeolocation.podspec +39 -0
- package/LICENSE +20 -0
- package/README.md +366 -0
- package/android/build.gradle +69 -0
- package/android/src/main/AndroidManifest.xml +53 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationActivityRecognitionReceiver.kt +116 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationBootReceiver.kt +44 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationForegroundService.kt +373 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationGeofenceReceiver.kt +55 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationHeadlessTask.kt +138 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationModule.kt +1030 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationMotionStateMachine.kt +159 -0
- package/android/src/main/java/com/bggeolocation/BgGeolocationPackage.kt +31 -0
- package/android/src/main/res/drawable/bg_geo_notification.xml +9 -0
- package/ios/BgGeolocation.h +14 -0
- package/ios/BgGeolocation.mm +709 -0
- package/ios/engine/AtomicBoolean.swift +48 -0
- package/ios/engine/BGActivityChangeEvent.swift +20 -0
- package/ios/engine/BGActivityConfig.swift +71 -0
- package/ios/engine/BGAppConfig.swift +92 -0
- package/ios/engine/BGAppState.swift +147 -0
- package/ios/engine/BGAuthorization.swift +85 -0
- package/ios/engine/BGAuthorizationAlertPresenter.swift +39 -0
- package/ios/engine/BGAuthorizationConfig.swift +50 -0
- package/ios/engine/BGAuthorizationEvent.swift +40 -0
- package/ios/engine/BGBackgroundTaskManager.swift +143 -0
- package/ios/engine/BGCLRouter.swift +101 -0
- package/ios/engine/BGCallback.swift +19 -0
- package/ios/engine/BGConfig.swift +440 -0
- package/ios/engine/BGConfigModuleBase.swift +180 -0
- package/ios/engine/BGConfigOLD.swift +582 -0
- package/ios/engine/BGConnectivityChangeEvent.swift +15 -0
- package/ios/engine/BGCrashDetector.swift +122 -0
- package/ios/engine/BGCurrentPositionRequest.swift +87 -0
- package/ios/engine/BGDataStore.swift +75 -0
- package/ios/engine/BGDatabase.swift +677 -0
- package/ios/engine/BGDatabasePool.swift +220 -0
- package/ios/engine/BGDatabaseQueue.swift +215 -0
- package/ios/engine/BGDateUtils.swift +26 -0
- package/ios/engine/BGDeviceInfo.swift +54 -0
- package/ios/engine/BGDeviceManager.swift +65 -0
- package/ios/engine/BGEnabledChangeEvent.swift +11 -0
- package/ios/engine/BGEnv.swift +17 -0
- package/ios/engine/BGEventBus.swift +83 -0
- package/ios/engine/BGEventManager.swift +169 -0
- package/ios/engine/BGEventNames.swift +51 -0
- package/ios/engine/BGGeofence.swift +233 -0
- package/ios/engine/BGGeofenceDAO.swift +152 -0
- package/ios/engine/BGGeofenceEvent.swift +42 -0
- package/ios/engine/BGGeofenceLocationRequest.swift +94 -0
- package/ios/engine/BGGeofenceManager.swift +315 -0
- package/ios/engine/BGGeofenceTransition.swift +97 -0
- package/ios/engine/BGGeofencesChangeEvent.swift +26 -0
- package/ios/engine/BGGeolocationConfig.swift +136 -0
- package/ios/engine/BGHeartbeatEvent.swift +31 -0
- package/ios/engine/BGHeartbeatService.swift +51 -0
- package/ios/engine/BGHttpConfig.swift +105 -0
- package/ios/engine/BGHttpErrorCodes.swift +63 -0
- package/ios/engine/BGHttpEvent.swift +34 -0
- package/ios/engine/BGHttpRequest.swift +126 -0
- package/ios/engine/BGHttpResponse.swift +93 -0
- package/ios/engine/BGHttpService.swift +428 -0
- package/ios/engine/BGKalmanFilter.swift +105 -0
- package/ios/engine/BGLMActionNames.swift +55 -0
- package/ios/engine/BGLicenseManager.swift +26 -0
- package/ios/engine/BGLiveActivityManager.swift +327 -0
- package/ios/engine/BGLocation.swift +311 -0
- package/ios/engine/BGLocationAuthorization.swift +427 -0
- package/ios/engine/BGLocationDAO.swift +252 -0
- package/ios/engine/BGLocationErrors.swift +28 -0
- package/ios/engine/BGLocationEvent.swift +43 -0
- package/ios/engine/BGLocationFilter.swift +82 -0
- package/ios/engine/BGLocationFilterConfig.swift +57 -0
- package/ios/engine/BGLocationHelper.swift +54 -0
- package/ios/engine/BGLocationManager.swift +662 -0
- package/ios/engine/BGLocationMetricsEngine.swift +116 -0
- package/ios/engine/BGLocationRequestService.swift +459 -0
- package/ios/engine/BGLocationSatisfier.swift +14 -0
- package/ios/engine/BGLocationStreamEvent.swift +27 -0
- package/ios/engine/BGLog.swift +337 -0
- package/ios/engine/BGLogLevel.swift +26 -0
- package/ios/engine/BGLoggerConfig.swift +60 -0
- package/ios/engine/BGMotionActivity.swift +31 -0
- package/ios/engine/BGMotionActivityClassifier.swift +108 -0
- package/ios/engine/BGMotionActivityManagerAdapter.swift +40 -0
- package/ios/engine/BGMotionActivitySource.swift +46 -0
- package/ios/engine/BGMotionDetector.swift +377 -0
- package/ios/engine/BGMotionPermissionManager.swift +50 -0
- package/ios/engine/BGNativeLogger.swift +48 -0
- package/ios/engine/BGNotificaitons.swift +37 -0
- package/ios/engine/BGOdometer.swift +66 -0
- package/ios/engine/BGPersistenceConfig.swift +29 -0
- package/ios/engine/BGPolygonStreamRequest.swift +48 -0
- package/ios/engine/BGPowerSaveChangeEvent.swift +12 -0
- package/ios/engine/BGPropertySpec.swift +29 -0
- package/ios/engine/BGProviderChangeEvent.swift +31 -0
- package/ios/engine/BGQueue.swift +50 -0
- package/ios/engine/BGRPC.swift +194 -0
- package/ios/engine/BGReachability.swift +58 -0
- package/ios/engine/BGResultSet.swift +157 -0
- package/ios/engine/BGSchedule.swift +228 -0
- package/ios/engine/BGScheduleEvent.swift +13 -0
- package/ios/engine/BGScheduler.swift +116 -0
- package/ios/engine/BGSingleLocationRequest.swift +49 -0
- package/ios/engine/BGStreamLocationRequest.swift +42 -0
- package/ios/engine/BGTemplate.swift +54 -0
- package/ios/engine/BGTimerService.swift +46 -0
- package/ios/engine/BGTrackingAudioManager.swift +286 -0
- package/ios/engine/BGTrackingService.swift +879 -0
- package/ios/engine/BGWatchPositionRequest.swift +63 -0
- package/ios/engine/DatabaseQueue.swift +47 -0
- package/ios/engine/LogQuery.swift +10 -0
- package/ios/engine/SQLQuery.swift +65 -0
- package/ios/engine/TransistorAuthorizationToken.swift +182 -0
- package/ios/liveactivity/BGLiveTrackingAttributes.swift +52 -0
- package/ios/locationpush/BGLocationPushDeliverer.swift +260 -0
- package/ios/locationpush/BGLocationPushService.swift +161 -0
- package/ios/locationpush/BGLocationPushShared.swift +98 -0
- package/ios/locationpush/BGLocationPushSocketClient.swift +198 -0
- package/lib/module/NativeBgGeolocation.js +5 -0
- package/lib/module/NativeBgGeolocation.js.map +1 -0
- package/lib/module/events.js +20 -0
- package/lib/module/events.js.map +1 -0
- package/lib/module/index.js +706 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeBgGeolocation.d.ts +57 -0
- package/lib/typescript/src/NativeBgGeolocation.d.ts.map +1 -0
- package/lib/typescript/src/events.d.ts +18 -0
- package/lib/typescript/src/events.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +238 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +229 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +141 -0
- package/src/NativeBgGeolocation.ts +236 -0
- package/src/events.ts +17 -0
- package/src/index.tsx +935 -0
- package/src/types.ts +254 -0
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import CoreLocation
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
@objc public class BGLocationManager: NSObject {
|
|
6
|
+
|
|
7
|
+
private static var _sharedInstance: BGLocationManager?
|
|
8
|
+
private static let instanceLock = NSLock()
|
|
9
|
+
|
|
10
|
+
@objc public class func sharedInstance() -> BGLocationManager {
|
|
11
|
+
instanceLock.lock()
|
|
12
|
+
defer { instanceLock.unlock() }
|
|
13
|
+
if _sharedInstance == nil { _sharedInstance = BGLocationManager() }
|
|
14
|
+
return _sharedInstance!
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// MARK: - State
|
|
18
|
+
|
|
19
|
+
@objc public var viewController: UIViewController?
|
|
20
|
+
@objc public var beforeInsertBlock: ((BGLocation) -> BGLocation?)?
|
|
21
|
+
|
|
22
|
+
private var locationManager: CLLocationManager?
|
|
23
|
+
private var configChangeBufferTimer: Timer?
|
|
24
|
+
private var isReady: Bool = false
|
|
25
|
+
private let setupQueue = DispatchQueue(label: "BGLocationManager.setup")
|
|
26
|
+
|
|
27
|
+
@objc public override init() {
|
|
28
|
+
super.init()
|
|
29
|
+
setupCoreLocation()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private func setupCoreLocation() {
|
|
33
|
+
let configure = {
|
|
34
|
+
let mgr = CLLocationManager()
|
|
35
|
+
self.locationManager = mgr
|
|
36
|
+
BGLocationAuthorization.configureShared(withLocationManager: mgr)
|
|
37
|
+
BGLocationRequestService.configureShared(withLocationManager: mgr)
|
|
38
|
+
BGTrackingService.sharedInstance().locationManager = mgr
|
|
39
|
+
BGGeofenceManager.sharedInstance().locationManager = mgr
|
|
40
|
+
// BGScheduler does not hold a locationManager reference
|
|
41
|
+
|
|
42
|
+
// Configure the shared manager the instant it exists —
|
|
43
|
+
// allowsBackgroundLocationUpdates DEFAULTS TO false, and iOS refuses
|
|
44
|
+
// background delivery / pauses GPS without it. Doing this here (not
|
|
45
|
+
// only in start()) means the kill-state auto-resume path and any
|
|
46
|
+
// direct SLC/region arming get a correctly-configured manager.
|
|
47
|
+
BGTrackingService.sharedInstance().configureLocationManager(mgr)
|
|
48
|
+
|
|
49
|
+
// A CLLocationManager has exactly one delegate. Route every callback
|
|
50
|
+
// through BGCLRouter, which fans out to the services above. This MUST
|
|
51
|
+
// be the only place `mgr.delegate` is assigned.
|
|
52
|
+
mgr.delegate = BGCLRouter.sharedInstance()
|
|
53
|
+
|
|
54
|
+
// Kill-state / cold-boot auto-resume. On an iOS background relaunch
|
|
55
|
+
// (significant-change or region exit after system termination) JS may never
|
|
56
|
+
// call ready(), so the engine must re-arm monitoring itself or the OS
|
|
57
|
+
// wake is wasted and nothing is delivered. Only resume when tracking
|
|
58
|
+
// was persisted enabled (or startOnBoot fired) — i.e. the user had
|
|
59
|
+
// tracking on and didn't stop it. ready() is idempotent (guarded by
|
|
60
|
+
// isReady), so a later JS ready() is a no-op for start.
|
|
61
|
+
let cfg = BGConfig.sharedInstance()
|
|
62
|
+
let launchedInBackground = BGAppState.sharedInstance().didLaunchInBackground
|
|
63
|
+
NSLog("[BGGEO] setupCoreLocation auto-resume check: enabled=\(cfg.enabled) startOnBoot=\(cfg.app.startOnBoot) launchedInBackground=\(launchedInBackground)")
|
|
64
|
+
if cfg.enabled || (cfg.app.startOnBoot && launchedInBackground) {
|
|
65
|
+
NSLog("[BGGEO] auto-resuming engine natively (kill-state path)")
|
|
66
|
+
self.ready()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if Thread.isMainThread {
|
|
71
|
+
configure()
|
|
72
|
+
} else {
|
|
73
|
+
DispatchQueue.main.sync(execute: configure)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// MARK: - Lifecycle
|
|
78
|
+
|
|
79
|
+
@objc public func ready() {
|
|
80
|
+
guard !isReady else { return }
|
|
81
|
+
isReady = true
|
|
82
|
+
let config = BGConfig.sharedInstance()
|
|
83
|
+
// Mark the app as having booted at least once so isFirstBoot() returns false on next launch.
|
|
84
|
+
UserDefaults.standard.set(true, forKey: "BGLocationManager_booted")
|
|
85
|
+
BGLog.sharedInstance().configure()
|
|
86
|
+
BGHttpService.sharedInstance().startMonitoring()
|
|
87
|
+
BGLocationDAO.sharedInstance()
|
|
88
|
+
|
|
89
|
+
let appState = BGAppState.sharedInstance()
|
|
90
|
+
config.didLaunchInBackground = appState.didLaunchInBackground
|
|
91
|
+
if config.app.startOnBoot && config.didLaunchInBackground {
|
|
92
|
+
doStart(true)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if config.enabled {
|
|
96
|
+
doStart(config.isMoving)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Drain records left by an interrupted background request immediately.
|
|
100
|
+
// This does not depend on React Native listeners or a later reachability
|
|
101
|
+
// transition, so a location-triggered cold launch can deliver natively.
|
|
102
|
+
BGHttpService.sharedInstance().resumePendingAutoSync()
|
|
103
|
+
|
|
104
|
+
// Clear the background-launch flag UNCONDITIONALLY once it has been read
|
|
105
|
+
// into config — otherwise (when ready() runs via the cfg.enabled branch
|
|
106
|
+
// instead of startOnBoot) the flag leaks into the NEXT normal foreground
|
|
107
|
+
// launch, corrupting launch classification.
|
|
108
|
+
UserDefaults.standard.removeObject(forKey: "BGLocationManager_didLaunchInBackground")
|
|
109
|
+
|
|
110
|
+
// Mirror the HTTP config into the App Group so the Location Push Service
|
|
111
|
+
// Extension can POST locations to the same server while the app is killed.
|
|
112
|
+
syncConfigToAppGroup()
|
|
113
|
+
|
|
114
|
+
BGAppState.sharedInstance().clientReady = true
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Writes the current HTTP config (url, headers, params, auth token, etc.)
|
|
118
|
+
/// into the App Group shared UserDefaults. The CLLocationPushServiceExtension
|
|
119
|
+
/// runs in a separate process and reads this to know where/how to upload the
|
|
120
|
+
/// location it captures after an APNs location push. Safe no-op if the App
|
|
121
|
+
/// Group entitlement is not configured.
|
|
122
|
+
@objc public func syncConfigToAppGroup() {
|
|
123
|
+
guard let defaults = BGLocationPushShared.sharedDefaults() else {
|
|
124
|
+
NSLog("[BGGEO] App Group not configured — Location Push config not synced")
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
let config = BGConfig.sharedInstance()
|
|
128
|
+
let http = config.http
|
|
129
|
+
|
|
130
|
+
defaults.set(http.url, forKey: BGLocationPushShared.keyUrl)
|
|
131
|
+
defaults.set(http.method, forKey: BGLocationPushShared.keyMethod)
|
|
132
|
+
defaults.set(http.headers, forKey: BGLocationPushShared.keyHeaders)
|
|
133
|
+
defaults.set(http.params, forKey: BGLocationPushShared.keyParams)
|
|
134
|
+
defaults.set(http.rootProperty, forKey: BGLocationPushShared.keyRootProperty)
|
|
135
|
+
|
|
136
|
+
let auth = config.authorization
|
|
137
|
+
if let token = auth.accessToken, !token.isEmpty {
|
|
138
|
+
defaults.set(token, forKey: BGLocationPushShared.keyAccessToken)
|
|
139
|
+
} else {
|
|
140
|
+
defaults.removeObject(forKey: BGLocationPushShared.keyAccessToken)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
NSLog("[BGGEO] Synced HTTP config to App Group (url=\(http.url)) for Location Push Extension")
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/// Host-app-supplied delivery config for the Location Push Service Extension.
|
|
147
|
+
/// Lets the app hand the extension a preferred socket channel (and any extra
|
|
148
|
+
/// REST overrides). Keys: socketUrl, socketPath, socketEvent, socketAuthToken,
|
|
149
|
+
/// socketTimeout, url, accessToken, extras. Persisted to the App Group.
|
|
150
|
+
@objc public func setLocationPushConfig(_ config: [String: Any]) {
|
|
151
|
+
guard let defaults = BGLocationPushShared.sharedDefaults() else {
|
|
152
|
+
NSLog("[BGGEO] App Group not configured — Location Push config not stored")
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Partial update: only touch keys PRESENT in the dict. An explicit
|
|
157
|
+
// NSNull clears; an absent key is left unchanged (so a later
|
|
158
|
+
// fcmToken-only call doesn't wipe the socket config).
|
|
159
|
+
func apply(_ defaultsKey: String, _ srcKey: String) {
|
|
160
|
+
guard let value = config[srcKey] else { return }
|
|
161
|
+
if value is NSNull { defaults.removeObject(forKey: defaultsKey) }
|
|
162
|
+
else { defaults.set(value, forKey: defaultsKey) }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
apply(BGLocationPushShared.keySocketUrl, "socketUrl")
|
|
166
|
+
apply(BGLocationPushShared.keySocketPath, "socketPath")
|
|
167
|
+
apply(BGLocationPushShared.keySocketEvent, "socketEvent")
|
|
168
|
+
apply(BGLocationPushShared.keySocketAuthToken, "socketAuthToken")
|
|
169
|
+
apply(BGLocationPushShared.keySocketTimeout, "socketTimeout")
|
|
170
|
+
apply(BGLocationPushShared.keyFallbackUrl, "fallbackUrl")
|
|
171
|
+
apply(BGLocationPushShared.keyFcmToken, "fcmToken")
|
|
172
|
+
|
|
173
|
+
// Optional REST overrides (otherwise the values synced from http config win).
|
|
174
|
+
if let url = config["url"] { defaults.set(url, forKey: BGLocationPushShared.keyUrl) }
|
|
175
|
+
if let token = config["accessToken"] { defaults.set(token, forKey: BGLocationPushShared.keyAccessToken) }
|
|
176
|
+
if let extras = config["extras"] as? [String: Any] {
|
|
177
|
+
defaults.set(extras, forKey: BGLocationPushShared.keyExtras)
|
|
178
|
+
}
|
|
179
|
+
// Custom HTTP headers for the REST fallback (e.g. {"Device-Type": "ios"}).
|
|
180
|
+
if let headers = config["headers"] as? [String: String] {
|
|
181
|
+
defaults.set(headers, forKey: BGLocationPushShared.keyHeaders)
|
|
182
|
+
}
|
|
183
|
+
// Host-defined payload shape (applies to socket emit + REST fallback).
|
|
184
|
+
// Pass NSNull / omit to keep the built-in default payload.
|
|
185
|
+
if let template = config["payloadTemplate"] as? [String: Any] {
|
|
186
|
+
defaults.set(template, forKey: BGLocationPushShared.keyPayloadTemplate)
|
|
187
|
+
} else if config["payloadTemplate"] is NSNull {
|
|
188
|
+
defaults.removeObject(forKey: BGLocationPushShared.keyPayloadTemplate)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
NSLog("[BGGEO] Stored Location Push delivery config (socketUrl=\(config["socketUrl"] ?? "nil"))")
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@objc public func start() {
|
|
195
|
+
let config = BGConfig.sharedInstance()
|
|
196
|
+
config.enabled = true
|
|
197
|
+
// Start must be durable before returning to JS. If the process is
|
|
198
|
+
// terminated immediately after the user taps Start, an async archive
|
|
199
|
+
// can be lost and the next Core Location launch cannot auto-resume.
|
|
200
|
+
config.forcePersistNow()
|
|
201
|
+
syncConfigToAppGroup()
|
|
202
|
+
doStart(config.isMoving)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@objc public func doStart(_ isMoving: Bool) {
|
|
206
|
+
let config = BGConfig.sharedInstance()
|
|
207
|
+
config.validateLicense()
|
|
208
|
+
|
|
209
|
+
let tracking = BGTrackingService.sharedInstance()
|
|
210
|
+
tracking.beforeInsertBlock = beforeInsertBlock
|
|
211
|
+
tracking.start(isMoving)
|
|
212
|
+
BGLiveActivityManager.shared.startIfNeeded(isMoving: isMoving)
|
|
213
|
+
BGTrackingAudioManager.shared.startIfNeeded()
|
|
214
|
+
|
|
215
|
+
if config.app.preventSuspend {
|
|
216
|
+
BGBackgroundTaskManager.sharedInstance().startPreventSuspend(.invalid)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if config.hasSchedule() {
|
|
220
|
+
startSchedule()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
startGeofences()
|
|
224
|
+
BGEventBus.sharedInstance().emit(BGEventNames.enabledChange, payload: ["enabled": true])
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@objc public func stop() {
|
|
228
|
+
let config = BGConfig.sharedInstance()
|
|
229
|
+
config.enabled = false
|
|
230
|
+
config.isMoving = false
|
|
231
|
+
config.forcePersistNow()
|
|
232
|
+
|
|
233
|
+
BGTrackingService.sharedInstance().stop()
|
|
234
|
+
BGLiveActivityManager.shared.end()
|
|
235
|
+
BGTrackingAudioManager.shared.stop()
|
|
236
|
+
BGBackgroundTaskManager.sharedInstance().stopPreventSuspend(.invalid)
|
|
237
|
+
BGGeofenceManager.sharedInstance().stop()
|
|
238
|
+
BGScheduler.sharedInstance().stop()
|
|
239
|
+
BGEventBus.sharedInstance().emit(BGEventNames.enabledChange, payload: ["enabled": false])
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@objc public var enabled: Bool {
|
|
243
|
+
return BGConfig.sharedInstance().enabled
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// MARK: - Pace
|
|
247
|
+
|
|
248
|
+
@objc public func changePace(_ isMoving: Bool) {
|
|
249
|
+
BGTrackingService.sharedInstance().changePace(isMoving)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@objc public func setPace(_ isMoving: Bool) {
|
|
253
|
+
changePace(isMoving)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// MARK: - Current position
|
|
257
|
+
|
|
258
|
+
@objc public func getCurrentPosition(_ request: BGCurrentPositionRequest) {
|
|
259
|
+
BGTrackingService.sharedInstance().getCurrentPosition(request)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// MARK: - Watch position
|
|
263
|
+
|
|
264
|
+
@objc public func watchPosition(_ request: BGWatchPositionRequest) {
|
|
265
|
+
// Bridge the watch request onto a stream and drive its success block with
|
|
266
|
+
// a BGLocation on every emitted fix (previously the passed request was
|
|
267
|
+
// dropped and a blank stream with no callback was started instead).
|
|
268
|
+
let stream = BGStreamLocationRequest()
|
|
269
|
+
stream.interval = request.interval
|
|
270
|
+
stream.desiredAccuracy = request.desiredAccuracy
|
|
271
|
+
stream.persist = request.persist
|
|
272
|
+
stream.extras = request.extras
|
|
273
|
+
stream.success = { location in
|
|
274
|
+
guard let cl = location as? CLLocation else { return }
|
|
275
|
+
let tsLocation = BGLocation(location: cl, type: "watch", extras: request.extras as? [String: Any])
|
|
276
|
+
if request.persist {
|
|
277
|
+
_ = BGLocationDAO.sharedInstance().create(tsLocation, error: nil)
|
|
278
|
+
}
|
|
279
|
+
request.success?(tsLocation)
|
|
280
|
+
}
|
|
281
|
+
_ = BGLocationRequestService.sharedInstance().startStream(stream)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@objc public func stopWatchPosition(_ watchId: Int) {
|
|
285
|
+
// The bridge supports a single active watch, so stop all streams rather
|
|
286
|
+
// than relying on a stream id the JS layer never receives.
|
|
287
|
+
BGLocationRequestService.sharedInstance().stopAllStreams()
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// MARK: - Geofences
|
|
291
|
+
|
|
292
|
+
@objc public func addGeofence(_ geofence: BGGeofence, success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
293
|
+
BGGeofenceManager.sharedInstance().create(geofence, success: success, failure: failure)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
@objc public func addGeofences(_ geofences: [BGGeofence], success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
297
|
+
for geofence in geofences {
|
|
298
|
+
BGGeofenceManager.sharedInstance().create(geofence, success: nil, failure: nil)
|
|
299
|
+
}
|
|
300
|
+
success?()
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@objc public func removeGeofence(_ identifier: String, success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
304
|
+
BGGeofenceManager.sharedInstance().destroy(identifier, success: success, failure: failure)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@objc public func removeGeofences(_ identifiers: [String], success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
308
|
+
for id in identifiers {
|
|
309
|
+
BGGeofenceManager.sharedInstance().destroy(id, success: nil, failure: nil)
|
|
310
|
+
}
|
|
311
|
+
success?()
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
@objc public func removeGeofences() {
|
|
315
|
+
BGGeofenceDAO.sharedInstance().destroyAll()
|
|
316
|
+
BGGeofenceManager.sharedInstance().stopMonitoringGeofences()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
@objc public func getGeofence(_ identifier: String, success: ((BGGeofence) -> Void)?, failure: ((Error) -> Void)?) {
|
|
320
|
+
if let geofence = BGGeofenceDAO.sharedInstance().find(identifier) {
|
|
321
|
+
success?(geofence)
|
|
322
|
+
} else {
|
|
323
|
+
failure?(NSError(domain: "BGLocationManager", code: 404, userInfo: [NSLocalizedDescriptionKey: "Geofence not found: \(identifier)"]))
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@objc public func getGeofences(_ success: (([BGGeofence]) -> Void)?, failure: ((Error) -> Void)?) {
|
|
328
|
+
success?(BGGeofenceDAO.sharedInstance().all())
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
@objc public func getGeofences() -> [BGGeofence] {
|
|
332
|
+
return BGGeofenceDAO.sharedInstance().all()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
@objc public func geofenceExists(_ identifier: String, callback: ((Bool) -> Void)?) {
|
|
336
|
+
callback?(BGGeofenceDAO.sharedInstance().exists(identifier))
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
@objc public func startGeofences() {
|
|
340
|
+
BGGeofenceManager.sharedInstance().start()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// MARK: - Locations
|
|
344
|
+
|
|
345
|
+
@objc public func getLocations(_ success: (([[String: Any]]) -> Void)?, failure: ((Error) -> Void)?) {
|
|
346
|
+
let records = BGLocationDAO.sharedInstance().all()
|
|
347
|
+
success?(records)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@objc public func getCount() -> Int {
|
|
351
|
+
return BGLocationDAO.sharedInstance().getCount()
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
@objc public func insertLocation(_ location: BGLocation, success: ((BGLocation) -> Void)?, failure: ((Error) -> Void)?) {
|
|
355
|
+
if BGLocationDAO.sharedInstance().create(location, error: nil) {
|
|
356
|
+
success?(location)
|
|
357
|
+
} else {
|
|
358
|
+
failure?(NSError(domain: "BGLocationManager", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to insert location"]))
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
@objc public func persistLocation(_ location: BGLocation) {
|
|
363
|
+
_ = BGLocationDAO.sharedInstance().create(location, error: nil)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
@objc public func destroyLocation(_ uuid: String) -> Bool {
|
|
367
|
+
return BGLocationDAO.sharedInstance().destroy(uuid)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
@objc public func destroyLocation(_ uuid: String, success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
371
|
+
if BGLocationDAO.sharedInstance().destroy(uuid) {
|
|
372
|
+
success?()
|
|
373
|
+
} else {
|
|
374
|
+
failure?(NSError(domain: "BGLocationManager", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to destroy location"]))
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@objc public func destroyLocations(_ failure: ((Error) -> Void)?) {
|
|
379
|
+
BGLocationDAO.sharedInstance().clear()
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
@objc public func destroyLocations() {
|
|
383
|
+
BGLocationDAO.sharedInstance().clear()
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
@objc public func clearDatabase() {
|
|
387
|
+
destroyLocations()
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@objc public func sync(_ success: (([[String: Any]]) -> Void)?, failure: ((Error) -> Void)?) {
|
|
391
|
+
BGHttpService.sharedInstance().flush({ response in
|
|
392
|
+
let records = BGLocationDAO.sharedInstance().all()
|
|
393
|
+
success?(records)
|
|
394
|
+
}, failure: failure)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
@objc public func getStationaryLocation() -> CLLocation? {
|
|
398
|
+
return BGTrackingService.sharedInstance().stationaryLocation
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// MARK: - Odometer
|
|
402
|
+
|
|
403
|
+
@objc public func getOdometer() -> Double {
|
|
404
|
+
return BGOdometer.sharedInstance().getOdometer()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
@objc public func setOdometer(_ value: Double, request: BGCurrentPositionRequest?) {
|
|
408
|
+
BGTrackingService.sharedInstance().setOdometer(value, request: request)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// MARK: - Schedule
|
|
412
|
+
|
|
413
|
+
@objc public func startSchedule() {
|
|
414
|
+
guard let mgr = locationManager else { return }
|
|
415
|
+
_ = BGScheduler.sharedInstance().start(withSchedule: BGConfig.sharedInstance().app.schedule)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
@objc public func stopSchedule() {
|
|
419
|
+
BGScheduler.sharedInstance().stop()
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// MARK: - Log
|
|
423
|
+
|
|
424
|
+
@objc public func getLog(_ query: LogQuery?, success: (([String: Any]) -> Void)?, failure: ((Error) -> Void)?) {
|
|
425
|
+
let q = query ?? LogQuery()
|
|
426
|
+
let entries = BGLog.sharedInstance().getLog(q)
|
|
427
|
+
success?(["log": entries])
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
@objc public func getLog(_ query: LogQuery?, failure: ((Error) -> Void)?) {
|
|
431
|
+
getLog(query, success: nil, failure: failure)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
@objc public func emailLog(_ to: String, query: LogQuery?, success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
435
|
+
let q = query ?? LogQuery()
|
|
436
|
+
BGLog.sharedInstance().emailLog(to, query: q, success: success, failure: failure)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
@objc public func emailLog(_ to: String, success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
440
|
+
emailLog(to, query: nil, success: success, failure: failure)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
@objc public func uploadLog(_ url: String, query: LogQuery?, success: (([String: Any]) -> Void)?, failure: ((Error) -> Void)?) {
|
|
444
|
+
let q = query ?? LogQuery()
|
|
445
|
+
BGLog.sharedInstance().uploadLog(url, query: q, success: success, failure: failure)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
@objc public func destroyLog() {
|
|
449
|
+
BGLog.sharedInstance().destroy()
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
@objc public func setLogLevel(_ level: Int) {
|
|
453
|
+
BGLog.sharedInstance().setLogLevel(level)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@objc public func log(_ level: String, message: String) {
|
|
457
|
+
BGLog.sharedInstance().notify(message, debug: level == "debug")
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
@objc public func error(_ level: String, message: String) {
|
|
461
|
+
BGLog.sharedInstance().alert(level, message: message)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
@objc public func playSound(_ soundId: SystemSoundID) {
|
|
465
|
+
BGLog.sharedInstance().playSound(soundId)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// MARK: - Provider state
|
|
469
|
+
|
|
470
|
+
@objc public func getProviderState() -> [String: Any] {
|
|
471
|
+
let status = CLLocationManager.authorizationStatus()
|
|
472
|
+
return [
|
|
473
|
+
"status": status.rawValue,
|
|
474
|
+
"enabled": CLLocationManager.locationServicesEnabled(),
|
|
475
|
+
"gps": CLLocationManager.locationServicesEnabled(),
|
|
476
|
+
"network": false,
|
|
477
|
+
"accuracyAuthorization": 1
|
|
478
|
+
]
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
@objc public func getState() -> [String: Any] {
|
|
482
|
+
var state = BGConfig.sharedInstance().currentStateDictionary()
|
|
483
|
+
state["liveActivity"] = BGLiveActivityManager.shared.stateDictionary()
|
|
484
|
+
state["trackingAudio"] = BGTrackingAudioManager.shared.stateDictionary()
|
|
485
|
+
return state
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// MARK: - Hardware availability
|
|
489
|
+
|
|
490
|
+
@objc public func isLocationServicesEnabled() -> Bool {
|
|
491
|
+
return CLLocationManager.locationServicesEnabled()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
@objc public func isPowerSaveMode() -> Bool {
|
|
495
|
+
return ProcessInfo.processInfo.isLowPowerModeEnabled
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
@objc public func isAccelerometerAvailable() -> Bool {
|
|
499
|
+
return BGMotionDetector.sharedInstance().isAccelerometerAvailable()
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
@objc public func isGyroAvailable() -> Bool {
|
|
503
|
+
return BGMotionDetector.sharedInstance().isGyroAvailable()
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
@objc public func isDeviceMotionAvailable() -> Bool {
|
|
507
|
+
return BGMotionDetector.sharedInstance().isDeviceMotionAvailable()
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
@objc public func isMagnetometerAvailable() -> Bool {
|
|
511
|
+
return BGMotionDetector.sharedInstance().isMagnetometerAvailable()
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
@objc public func isMotionHardwareAvailable() -> Bool {
|
|
515
|
+
return BGMotionDetector.motionHardwareAvailable()
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
@objc public func isRotationAvailable() -> Bool {
|
|
519
|
+
return BGMotionDetector.sharedInstance().isGyroAvailable()
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// MARK: - Permissions
|
|
523
|
+
|
|
524
|
+
@objc public func requestPermission(_ success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
525
|
+
BGLocationAuthorization.sharedInstance().updateDesiredPolicyFromConfig()
|
|
526
|
+
BGLocationAuthorization.sharedInstance().requestAuthorization { status, error in
|
|
527
|
+
if let error = error {
|
|
528
|
+
failure?(error)
|
|
529
|
+
} else {
|
|
530
|
+
success?()
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
@objc public func requestTemporaryFullAccuracy(_ purposeKey: String, success: (() -> Void)?, failure: ((Error) -> Void)?) {
|
|
536
|
+
BGLocationAuthorization.sharedInstance().requestTemporaryFullAccuracy(purposeKey, success: success, failure: failure)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// MARK: - Background task
|
|
540
|
+
|
|
541
|
+
@objc public func createBackgroundTask() -> UIBackgroundTaskIdentifier {
|
|
542
|
+
return BGBackgroundTaskManager.sharedInstance().createBackgroundTask()
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
@objc public func stopBackgroundTask(_ taskId: UIBackgroundTaskIdentifier) {
|
|
546
|
+
BGBackgroundTaskManager.sharedInstance().stopBackgroundTask(taskId)
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// MARK: - Listeners
|
|
550
|
+
|
|
551
|
+
@objc public func onLocation(_ success: ((BGLocation) -> Void)?, failure: ((Error) -> Void)?) {
|
|
552
|
+
BGEventManager.sharedInstance().addLocationListener(success: { location in
|
|
553
|
+
if let loc = location as? BGLocation { success?(loc) }
|
|
554
|
+
}, failure: { payload in
|
|
555
|
+
if let err = payload as? Error { failure?(err) }
|
|
556
|
+
})
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
@objc public func onMotionChange(_ success: ((BGLocation) -> Void)?, failure: ((Error) -> Void)?) {
|
|
560
|
+
_ = BGEventManager.sharedInstance().addListener(BGEventNames.motionChangeComplete, callback: { payload in
|
|
561
|
+
if let loc = payload as? BGLocation { success?(loc) }
|
|
562
|
+
})
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
@objc public func onActivityChange(_ success: ((BGMotionActivity) -> Void)?) {
|
|
566
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.activityChange) { payload in
|
|
567
|
+
if let activity = payload as? BGMotionActivity { success?(activity) }
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
@objc public func onGeofence(_ success: ((BGGeofenceEvent) -> Void)?) {
|
|
572
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.geofence) { payload in
|
|
573
|
+
if let event = payload as? BGGeofenceEvent { success?(event) }
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
@objc public func onGeofencesChange(_ success: ((BGGeofencesChangeEvent) -> Void)?) {
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
@objc public func onHttp(_ success: (([String: Any]) -> Void)?) {
|
|
581
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.http) { payload in
|
|
582
|
+
if let dict = payload as? [String: Any] { success?(dict) }
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
@objc public func onHeartbeat(_ success: ((BGHeartbeatEvent) -> Void)?) {
|
|
587
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.heartbeat) { payload in
|
|
588
|
+
if let event = payload as? BGHeartbeatEvent { success?(event) }
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
@objc public func onSchedule(_ success: ((BGScheduleEvent) -> Void)?) {
|
|
593
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.schedule) { payload in
|
|
594
|
+
if let event = payload as? BGScheduleEvent { success?(event) }
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
@objc public func onEnabledChange(_ success: ((Bool) -> Void)?) {
|
|
599
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.enabledChange) { payload in
|
|
600
|
+
if let dict = payload as? [String: Any], let enabled = dict["enabled"] as? Bool {
|
|
601
|
+
success?(enabled)
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
@objc public func onConnectivityChange(_ success: ((Bool) -> Void)?) {
|
|
607
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.connectivityChange) { payload in
|
|
608
|
+
if let dict = payload as? [String: Any], let connected = dict["connected"] as? Bool {
|
|
609
|
+
success?(connected)
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
@objc public func onPowerSaveChange(_ success: ((Bool) -> Void)?) {
|
|
615
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.powerSaveChange) { payload in
|
|
616
|
+
if let dict = payload as? [String: Any], let enabled = dict["isPowerSaveMode"] as? Bool {
|
|
617
|
+
success?(enabled)
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
@objc public func onAuthorization(_ success: ((BGAuthorizationEvent) -> Void)?) {
|
|
623
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.authorization) { payload in
|
|
624
|
+
if let event = payload as? BGAuthorizationEvent { success?(event) }
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
@objc public func onProviderChange(_ success: ((BGProviderChangeEvent) -> Void)?) {
|
|
629
|
+
_ = BGEventBus.sharedInstance().on(BGEventNames.providerChange) { payload in
|
|
630
|
+
if let event = payload as? BGProviderChangeEvent { success?(event) }
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// MARK: - Remove listeners
|
|
635
|
+
|
|
636
|
+
@objc public func removeListener(_ event: String, callback: AnyObject) {
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
@objc public func removeListener(_ event: String, token: Int) {
|
|
640
|
+
BGEventBus.sharedInstance().off(event, token: String(token))
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
@objc public func removeListeners(_ event: String) {
|
|
644
|
+
BGEventBus.sharedInstance().offAll(event)
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
@objc public func removeListenersForEvent(_ event: String) {
|
|
648
|
+
removeListeners(event)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
@objc public func removeListeners() {
|
|
652
|
+
BGEventBus.sharedInstance().offAll()
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// MARK: - View controller
|
|
656
|
+
|
|
657
|
+
public func setViewController(_ vc: UIViewController) {
|
|
658
|
+
viewController = vc
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
import AudioToolbox
|