@capgo/background-geolocation 7.0.8 → 7.0.10
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/README.md +163 -70
- package/android/src/main/java/com/capgo/capacitor_background_geolocation/BackgroundGeolocation.java +46 -103
- package/android/src/main/java/com/capgo/capacitor_background_geolocation/BackgroundGeolocationService.java +192 -54
- package/dist/docs.json +106 -56
- package/dist/esm/definitions.d.ts +65 -42
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +5 -7
- package/dist/esm/web.js +27 -16
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +27 -16
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +27 -16
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/Plugin.m +3 -2
- package/ios/Plugin/Plugin.swift +114 -93
- package/package.json +1 -1
package/ios/Plugin/Plugin.swift
CHANGED
|
@@ -2,6 +2,7 @@ import Capacitor
|
|
|
2
2
|
import Foundation
|
|
3
3
|
import UIKit
|
|
4
4
|
import CoreLocation
|
|
5
|
+
import AVFoundation
|
|
5
6
|
|
|
6
7
|
// Avoids a bewildering type warning.
|
|
7
8
|
let null = Optional<Double>.none as Any
|
|
@@ -33,63 +34,42 @@ func formatLocation(_ location: CLLocation) -> PluginCallResultData {
|
|
|
33
34
|
]
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
class Watcher {
|
|
37
|
-
let callbackId: String
|
|
38
|
-
let locationManager: CLLocationManager = CLLocationManager()
|
|
39
|
-
private let created = Date()
|
|
40
|
-
private let allowStale: Bool
|
|
41
|
-
private var isUpdatingLocation: Bool = false
|
|
42
|
-
init(_ id: String, stale: Bool) {
|
|
43
|
-
callbackId = id
|
|
44
|
-
allowStale = stale
|
|
45
|
-
}
|
|
46
|
-
func start() {
|
|
47
|
-
// Avoid unnecessary calls to startUpdatingLocation, which can
|
|
48
|
-
// result in extraneous invocations of didFailWithError.
|
|
49
|
-
if !isUpdatingLocation {
|
|
50
|
-
locationManager.startUpdatingLocation()
|
|
51
|
-
isUpdatingLocation = true
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
func stop() {
|
|
55
|
-
if isUpdatingLocation {
|
|
56
|
-
locationManager.stopUpdatingLocation()
|
|
57
|
-
isUpdatingLocation = false
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
func isLocationValid(_ location: CLLocation) -> Bool {
|
|
61
|
-
return (
|
|
62
|
-
allowStale ||
|
|
63
|
-
location.timestamp >= created
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
37
|
@objc(BackgroundGeolocation)
|
|
69
38
|
public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
|
|
70
|
-
private var
|
|
39
|
+
private var locationManager: CLLocationManager?
|
|
40
|
+
private var created: Date?
|
|
41
|
+
private var allowStale: Bool = false
|
|
42
|
+
private var isUpdatingLocation: Bool = false
|
|
43
|
+
private var activeCallbackId: String?
|
|
44
|
+
private var audioPlayer: AVAudioPlayer?
|
|
71
45
|
|
|
72
46
|
@objc override public func load() {
|
|
73
47
|
UIDevice.current.isBatteryMonitoringEnabled = true
|
|
74
48
|
}
|
|
75
49
|
|
|
76
|
-
@objc func
|
|
50
|
+
@objc func start(_ call: CAPPluginCall) {
|
|
77
51
|
call.keepAlive = true
|
|
78
52
|
|
|
79
53
|
// CLLocationManager requires main thread
|
|
80
54
|
DispatchQueue.main.async {
|
|
55
|
+
// Check if already started
|
|
56
|
+
if self.locationManager != nil {
|
|
57
|
+
return call.reject("Location tracking already started", "ALREADY_STARTED")
|
|
58
|
+
}
|
|
59
|
+
// Create fresh location manager and initialize date
|
|
60
|
+
self.locationManager = CLLocationManager()
|
|
61
|
+
self.locationManager!.delegate = self
|
|
62
|
+
self.created = Date()
|
|
63
|
+
|
|
81
64
|
let background = call.getString("backgroundMessage") != nil
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
86
|
-
let manager = watcher.locationManager
|
|
87
|
-
manager.delegate = self
|
|
65
|
+
self.allowStale = call.getBool("stale") ?? false
|
|
66
|
+
self.activeCallbackId = call.callbackId
|
|
67
|
+
|
|
88
68
|
let externalPower = [
|
|
89
69
|
.full,
|
|
90
70
|
.charging
|
|
91
71
|
].contains(UIDevice.current.batteryState)
|
|
92
|
-
|
|
72
|
+
self.locationManager!.desiredAccuracy = (
|
|
93
73
|
externalPower
|
|
94
74
|
? kCLLocationAccuracyBestForNavigation
|
|
95
75
|
: kCLLocationAccuracyBest
|
|
@@ -100,11 +80,11 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
|
|
|
100
80
|
if distanceFilter == nil || distanceFilter == 0 {
|
|
101
81
|
distanceFilter = kCLDistanceFilterNone
|
|
102
82
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
83
|
+
self.locationManager!.distanceFilter = distanceFilter!
|
|
84
|
+
self.locationManager!.allowsBackgroundLocationUpdates = background
|
|
85
|
+
self.locationManager!.showsBackgroundLocationIndicator = background
|
|
86
|
+
self.locationManager!.pausesLocationUpdatesAutomatically = false
|
|
87
|
+
|
|
108
88
|
if call.getBool("requestPermissions") != false {
|
|
109
89
|
let status = CLLocationManager.authorizationStatus()
|
|
110
90
|
if [
|
|
@@ -114,35 +94,35 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
|
|
|
114
94
|
].contains(status) {
|
|
115
95
|
return (
|
|
116
96
|
background
|
|
117
|
-
?
|
|
118
|
-
:
|
|
97
|
+
? self.locationManager!.requestAlwaysAuthorization()
|
|
98
|
+
: self.locationManager!.requestWhenInUseAuthorization()
|
|
119
99
|
)
|
|
120
100
|
}
|
|
121
101
|
if background && status == .authorizedWhenInUse {
|
|
122
102
|
// Attempt to escalate.
|
|
123
|
-
|
|
103
|
+
self.locationManager!.requestAlwaysAuthorization()
|
|
124
104
|
}
|
|
125
105
|
}
|
|
126
|
-
return
|
|
106
|
+
return self.startUpdatingLocation()
|
|
127
107
|
}
|
|
128
108
|
}
|
|
129
109
|
|
|
130
|
-
@objc func
|
|
110
|
+
@objc func stop(_ call: CAPPluginCall) {
|
|
131
111
|
// CLLocationManager requires main thread
|
|
132
112
|
DispatchQueue.main.async {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
113
|
+
self.stopUpdatingLocation()
|
|
114
|
+
|
|
115
|
+
self.locationManager?.delegate = nil
|
|
116
|
+
self.locationManager = nil
|
|
117
|
+
self.created = nil
|
|
118
|
+
|
|
119
|
+
if let callbackId = self.activeCallbackId {
|
|
140
120
|
if let savedCall = self.bridge?.savedCall(withID: callbackId) {
|
|
141
121
|
self.bridge?.releaseCall(savedCall)
|
|
142
122
|
}
|
|
143
|
-
|
|
123
|
+
self.activeCallbackId = nil
|
|
144
124
|
}
|
|
145
|
-
return call.
|
|
125
|
+
return call.resolve()
|
|
146
126
|
}
|
|
147
127
|
}
|
|
148
128
|
|
|
@@ -169,46 +149,91 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
|
|
|
169
149
|
}
|
|
170
150
|
}
|
|
171
151
|
|
|
152
|
+
private func startUpdatingLocation() {
|
|
153
|
+
// Avoid unnecessary calls to startUpdatingLocation, which can
|
|
154
|
+
// result in extraneous invocations of didFailWithError.
|
|
155
|
+
if !isUpdatingLocation, let manager = locationManager {
|
|
156
|
+
manager.startUpdatingLocation()
|
|
157
|
+
isUpdatingLocation = true
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private func stopUpdatingLocation() {
|
|
162
|
+
if isUpdatingLocation, let manager = locationManager {
|
|
163
|
+
manager.stopUpdatingLocation()
|
|
164
|
+
isUpdatingLocation = false
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private func isLocationValid(_ location: CLLocation) -> Bool {
|
|
169
|
+
guard let created = created else { return allowStale }
|
|
170
|
+
return (
|
|
171
|
+
allowStale ||
|
|
172
|
+
location.timestamp >= created
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@objc func playSound(_ call: CAPPluginCall) {
|
|
177
|
+
// Use a background queue for audio loading to avoid blocking the main thread
|
|
178
|
+
DispatchQueue.global(qos: .background).async { [weak self] in
|
|
179
|
+
guard let self = self else { return }
|
|
180
|
+
|
|
181
|
+
let assetPath = "public/" + (call.getString("soundFile") ?? "")
|
|
182
|
+
let assetPathSplit = assetPath.components(separatedBy: ".")
|
|
183
|
+
guard let url = Bundle.main.url(forResource: assetPathSplit[0], withExtension: assetPathSplit[1]) else {
|
|
184
|
+
call.reject("Sound file not found: \(assetPath)")
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
do {
|
|
189
|
+
self.audioPlayer?.stop()
|
|
190
|
+
self.audioPlayer = nil
|
|
191
|
+
self.audioPlayer = try AVAudioPlayer(contentsOf: url)
|
|
192
|
+
self.audioPlayer?.play()
|
|
193
|
+
call.resolve()
|
|
194
|
+
} catch {
|
|
195
|
+
call.reject("Could not play the sound file: \(error.localizedDescription)")
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
172
200
|
public func locationManager(
|
|
173
201
|
_ manager: CLLocationManager,
|
|
174
202
|
didFailWithError error: Error
|
|
175
203
|
) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
return call.reject(error.localizedDescription, nil, error)
|
|
204
|
+
guard let callbackId = activeCallbackId,
|
|
205
|
+
let call = self.bridge?.savedCall(withID: callbackId) else {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if let clErr = error as? CLError {
|
|
210
|
+
if clErr.code == .locationUnknown {
|
|
211
|
+
// This error is sometimes sent by the manager if
|
|
212
|
+
// it cannot get a fix immediately.
|
|
213
|
+
return
|
|
214
|
+
} else if clErr.code == .denied {
|
|
215
|
+
stopUpdatingLocation()
|
|
216
|
+
return call.reject(
|
|
217
|
+
"Permission denied.",
|
|
218
|
+
"NOT_AUTHORIZED"
|
|
219
|
+
)
|
|
194
220
|
}
|
|
195
221
|
}
|
|
222
|
+
return call.reject(error.localizedDescription, nil, error)
|
|
196
223
|
}
|
|
197
224
|
|
|
198
225
|
public func locationManager(
|
|
199
226
|
_ manager: CLLocationManager,
|
|
200
227
|
didUpdateLocations locations: [CLLocation]
|
|
201
228
|
) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
}
|
|
229
|
+
guard let location = locations.last,
|
|
230
|
+
let callbackId = activeCallbackId,
|
|
231
|
+
let call = self.bridge?.savedCall(withID: callbackId) else {
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if isLocationValid(location) {
|
|
236
|
+
return call.resolve(formatLocation(location))
|
|
212
237
|
}
|
|
213
238
|
}
|
|
214
239
|
|
|
@@ -220,11 +245,7 @@ public class BackgroundGeolocation: CAPPlugin, CLLocationManagerDelegate {
|
|
|
220
245
|
// it is on iOS 14 when the permissions dialog is presented, we ignore
|
|
221
246
|
// it.
|
|
222
247
|
if status != .notDetermined {
|
|
223
|
-
|
|
224
|
-
where: { $0.locationManager == manager }
|
|
225
|
-
) {
|
|
226
|
-
return watcher.start()
|
|
227
|
-
}
|
|
248
|
+
startUpdatingLocation()
|
|
228
249
|
}
|
|
229
250
|
}
|
|
230
251
|
}
|
package/package.json
CHANGED