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,228 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public final class BGSchedule: NSObject {
|
|
4
|
+
|
|
5
|
+
@objc public var days: NSMutableArray
|
|
6
|
+
@objc public private(set) var isLiteralDate: Bool = false
|
|
7
|
+
private var hasTriggered: Bool = false
|
|
8
|
+
private var datePattern: String
|
|
9
|
+
private var calendar: NSCalendar
|
|
10
|
+
@objc public var triggered: Bool = false
|
|
11
|
+
@objc public var onTime: NSDateComponents?
|
|
12
|
+
@objc public var onDate: Date?
|
|
13
|
+
@objc public var offTime: NSDateComponents?
|
|
14
|
+
@objc public var offDate: Date?
|
|
15
|
+
@objc public var trackingMode: Int = 1
|
|
16
|
+
@objc public var handlerBlock: (() -> Void)?
|
|
17
|
+
|
|
18
|
+
@objc public init(record: String) {
|
|
19
|
+
self.days = NSMutableArray()
|
|
20
|
+
self.triggered = false
|
|
21
|
+
self.hasTriggered = false
|
|
22
|
+
self.trackingMode = 1
|
|
23
|
+
self.datePattern = "^\\d{4}-\\d{2}-\\d{2}.*"
|
|
24
|
+
|
|
25
|
+
let cal = NSCalendar(calendarIdentifier: .gregorian)!
|
|
26
|
+
cal.locale = Locale(identifier: "en_US")
|
|
27
|
+
cal.timeZone = NSTimeZone.local
|
|
28
|
+
self.calendar = cal
|
|
29
|
+
|
|
30
|
+
let onComponents = NSDateComponents()
|
|
31
|
+
let offComponents = NSDateComponents()
|
|
32
|
+
self.onTime = onComponents
|
|
33
|
+
self.offTime = offComponents
|
|
34
|
+
|
|
35
|
+
super.init()
|
|
36
|
+
|
|
37
|
+
let parts = NSMutableArray(array: record.components(separatedBy: " "))
|
|
38
|
+
guard parts.count > 0, let part0 = parts.object(at: 0) as? String else { return }
|
|
39
|
+
|
|
40
|
+
if part0.contains("-") {
|
|
41
|
+
let isDate = part0.range(of: datePattern, options: .regularExpression) != nil
|
|
42
|
+
if isDate {
|
|
43
|
+
isLiteralDate = true
|
|
44
|
+
let dateComponents = part0.components(separatedBy: "-")
|
|
45
|
+
onComponents.year = Int(dateComponents[0]) ?? 0
|
|
46
|
+
onComponents.month = Int(dateComponents[1]) ?? 0
|
|
47
|
+
onComponents.day = Int(dateComponents[2]) ?? 0
|
|
48
|
+
|
|
49
|
+
if parts.count > 1, let part1 = parts.object(at: 1) as? String {
|
|
50
|
+
if part1.range(of: datePattern, options: .regularExpression) != nil {
|
|
51
|
+
offComponents.year = onComponents.year
|
|
52
|
+
offComponents.month = onComponents.month
|
|
53
|
+
offComponents.day = onComponents.day
|
|
54
|
+
} else {
|
|
55
|
+
let off = part1.components(separatedBy: "-")
|
|
56
|
+
offComponents.year = Int(off[0]) ?? 0
|
|
57
|
+
offComponents.month = Int(off[1]) ?? 0
|
|
58
|
+
offComponents.day = Int(off[2]) ?? 0
|
|
59
|
+
if dateComponents.count > 3 && off.count > 3 {
|
|
60
|
+
parts[1] = String(format: "%@-%@", dateComponents[3], off[3])
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// Numeric day range "from-to".
|
|
66
|
+
let range = part0.components(separatedBy: "-")
|
|
67
|
+
let from = Int(range[0]) ?? 0
|
|
68
|
+
let to = Int(range[1]) ?? 0
|
|
69
|
+
if from <= to {
|
|
70
|
+
for day in from...to {
|
|
71
|
+
days.add(NSNumber(value: day))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// Comma-separated day list.
|
|
77
|
+
for dayStr in part0.components(separatedBy: ",") {
|
|
78
|
+
days.add(NSNumber(value: Int(dayStr) ?? 0))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Parse time window from parts[1] ("HH:MM-HH:MM").
|
|
83
|
+
if parts.count > 1, let part1 = parts.object(at: 1) as? String {
|
|
84
|
+
let timeRange = part1.components(separatedBy: "-")
|
|
85
|
+
if timeRange.count >= 2 {
|
|
86
|
+
let onParts = timeRange[0].components(separatedBy: ":")
|
|
87
|
+
onComponents.hour = Int(onParts[0]) ?? 0
|
|
88
|
+
onComponents.minute = onParts.count > 1 ? (Int(onParts[1]) ?? 0) : 0
|
|
89
|
+
let offParts = timeRange[1].components(separatedBy: ":")
|
|
90
|
+
offComponents.hour = Int(offParts[0]) ?? 0
|
|
91
|
+
offComponents.minute = offParts.count > 1 ? (Int(offParts[1]) ?? 0) : 0
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if isLiteralDate {
|
|
96
|
+
onDate = calendar.date(from: onComponents as DateComponents)
|
|
97
|
+
offDate = calendar.date(from: offComponents as DateComponents)
|
|
98
|
+
if let onDate = onDate, let offDate = offDate,
|
|
99
|
+
(offDate as NSDate).earlierDate(onDate) == offDate {
|
|
100
|
+
let oneDay = NSDateComponents()
|
|
101
|
+
oneDay.day = 1
|
|
102
|
+
self.offDate = calendar.date(byAdding: oneDay as DateComponents, to: offDate, options: [])
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if parts.count >= 3, let part2 = parts.object(at: 2) as? String {
|
|
107
|
+
if part2.contains("geofence") {
|
|
108
|
+
trackingMode = 0
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@objc public func evaluate() -> Date {
|
|
114
|
+
let now = Date()
|
|
115
|
+
if triggered {
|
|
116
|
+
if (now as NSDate).laterDate(offDate ?? now) == now {
|
|
117
|
+
trigger(false)
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
if let onDate = onDate, (now as NSDate).laterDate(onDate) == now {
|
|
121
|
+
let withinWindow = (now as NSDate).earlierDate(offDate ?? now) == now
|
|
122
|
+
trigger(withinWindow)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return now
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@objc public func trigger(_ state: Bool) {
|
|
129
|
+
if hasTriggered && triggered == state {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
let logger = BGLog.sharedInstance()
|
|
133
|
+
if state {
|
|
134
|
+
if logger.shouldLog(5) {
|
|
135
|
+
let message = String(format: "%@", description)
|
|
136
|
+
logger.log(5, tag: 3, function: "-[BGSchedule trigger:]", message: message)
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
if logger.shouldLog(3) {
|
|
140
|
+
let message = String(format: "%@", description)
|
|
141
|
+
logger.log(3, tag: 5, function: "-[BGSchedule trigger:]", message: message)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
hasTriggered = true
|
|
145
|
+
triggered = state
|
|
146
|
+
|
|
147
|
+
let state = BGConfig.sharedInstance().toDictionary()
|
|
148
|
+
let event = BGScheduleEvent(schedule: self, state: state)
|
|
149
|
+
BGEventBus.sharedInstance().trigger(BGEventNameSchedule, payload: event)
|
|
150
|
+
BGEventManager.sharedInstance().trigger(BGEventNameSchedule, payload: event)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@objc public func make(_ components: NSDateComponents) {
|
|
154
|
+
guard !isLiteralDate else { return }
|
|
155
|
+
onTime?.year = components.year
|
|
156
|
+
onTime?.month = components.month
|
|
157
|
+
onTime?.day = components.day
|
|
158
|
+
onDate = calendar.date(from: (onTime ?? NSDateComponents()) as DateComponents)
|
|
159
|
+
|
|
160
|
+
offTime?.year = components.year
|
|
161
|
+
offTime?.month = components.month
|
|
162
|
+
offTime?.day = components.day
|
|
163
|
+
offDate = calendar.date(from: (offTime ?? NSDateComponents()) as DateComponents)
|
|
164
|
+
|
|
165
|
+
if let onDate = onDate, let offDate = offDate,
|
|
166
|
+
(offDate as NSDate).earlierDate(onDate) == offDate {
|
|
167
|
+
let oneDay = NSDateComponents()
|
|
168
|
+
oneDay.day = 1
|
|
169
|
+
self.offDate = calendar.date(byAdding: oneDay as DateComponents, to: offDate, options: [])
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@objc public func isNext(_ date: Date) -> Bool {
|
|
174
|
+
let comps = calendar.components([.year, .month, .day, .hour, .minute, .weekday], from: date)
|
|
175
|
+
if !isLiteralDate {
|
|
176
|
+
make(comps as NSDateComponents)
|
|
177
|
+
if !hasDay(comps.weekday ?? 0) {
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
guard let offDate = offDate else { return false }
|
|
182
|
+
return (date as NSDate).earlierDate(offDate) == date
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@objc public func reset() {
|
|
186
|
+
hasTriggered = false
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@objc public func expired() -> Bool {
|
|
190
|
+
let now = Date()
|
|
191
|
+
guard let offDate = offDate else { return false }
|
|
192
|
+
return (now as NSDate).laterDate(offDate) == now
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@objc public func startsBefore(_ date: Date) -> Bool {
|
|
196
|
+
guard let onDate = onDate else { return false }
|
|
197
|
+
return (onDate as NSDate).earlierDate(date) == onDate
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@objc public func startsAfter(_ date: Date) -> Bool {
|
|
201
|
+
guard let onDate = onDate else { return false }
|
|
202
|
+
return (onDate as NSDate).earlierDate(date) == date
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@objc public func endsBefore(_ date: Date) -> Bool {
|
|
206
|
+
guard let offDate = offDate else { return false }
|
|
207
|
+
return (offDate as NSDate).earlierDate(date) == offDate
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@objc public func endsAfter(_ date: Date) -> Bool {
|
|
211
|
+
guard let offDate = offDate else { return false }
|
|
212
|
+
return (offDate as NSDate).earlierDate(date) == date
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@objc public func hasDay(_ weekday: Int) -> Bool {
|
|
216
|
+
return days.contains(NSNumber(value: weekday))
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public override var description: String {
|
|
220
|
+
let onHour = onTime?.hour ?? 0
|
|
221
|
+
let onMinute = onTime?.minute ?? 0
|
|
222
|
+
let offHour = offTime?.hour ?? 0
|
|
223
|
+
let offMinute = offTime?.minute ?? 0
|
|
224
|
+
let daysString = days.componentsJoined(by: ",")
|
|
225
|
+
return String(format: "BGSchedule[triggered:%d, %02ld:%02ld - %02ld:%02ld, Days:%@, trackingMode:%d]",
|
|
226
|
+
triggered, onHour, onMinute, offHour, offMinute, daysString, trackingMode)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public final class BGScheduleEvent: NSObject {
|
|
4
|
+
|
|
5
|
+
@objc public private(set) var schedule: BGSchedule?
|
|
6
|
+
@objc public private(set) var state: Any?
|
|
7
|
+
|
|
8
|
+
@objc public init(schedule: BGSchedule?, state: Any?) {
|
|
9
|
+
self.schedule = schedule
|
|
10
|
+
self.state = state
|
|
11
|
+
super.init()
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class BGScheduler: NSObject {
|
|
4
|
+
|
|
5
|
+
private static var _sharedInstance: BGScheduler?
|
|
6
|
+
private static let lock = NSLock()
|
|
7
|
+
|
|
8
|
+
private var scheduleRules: [BGScheduleRule] = []
|
|
9
|
+
private var timer: Timer?
|
|
10
|
+
private var enabled: Bool = false
|
|
11
|
+
|
|
12
|
+
@objc public class func sharedInstance() -> BGScheduler {
|
|
13
|
+
lock.lock()
|
|
14
|
+
defer { lock.unlock() }
|
|
15
|
+
if _sharedInstance == nil {
|
|
16
|
+
_sharedInstance = BGScheduler()
|
|
17
|
+
}
|
|
18
|
+
return _sharedInstance!
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@objc public override init() {
|
|
22
|
+
super.init()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@objc public func start(withSchedule schedule: [String]) -> Bool {
|
|
26
|
+
stop()
|
|
27
|
+
scheduleRules = schedule.compactMap { BGScheduleRule(rule: $0) }
|
|
28
|
+
guard !scheduleRules.isEmpty else { return false }
|
|
29
|
+
enabled = true
|
|
30
|
+
startTimer()
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@objc public func stop() {
|
|
35
|
+
timer?.invalidate()
|
|
36
|
+
timer = nil
|
|
37
|
+
enabled = false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@objc public func isEnabled() -> Bool {
|
|
41
|
+
return enabled
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@objc public func isTracking() -> Bool {
|
|
45
|
+
guard enabled else { return false }
|
|
46
|
+
let now = Date()
|
|
47
|
+
return scheduleRules.contains { $0.isActiveAt(now) }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@objc public func nextScheduledDate() -> Date? {
|
|
51
|
+
let now = Date()
|
|
52
|
+
return scheduleRules.compactMap { $0.nextTriggerDate(after: now) }.min()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private func startTimer() {
|
|
56
|
+
timer = Timer.scheduledTimer(timeInterval: 60.0,
|
|
57
|
+
target: self,
|
|
58
|
+
selector: #selector(evaluate),
|
|
59
|
+
userInfo: nil,
|
|
60
|
+
repeats: true)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@objc private func evaluate() {
|
|
64
|
+
let tracking = isTracking()
|
|
65
|
+
NotificationCenter.default.post(
|
|
66
|
+
name: NSNotification.Name("BGSchedulerEvaluated"),
|
|
67
|
+
object: self,
|
|
68
|
+
userInfo: ["tracking": tracking]
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private class BGScheduleRule {
|
|
74
|
+
let raw: String
|
|
75
|
+
let startHour: Int
|
|
76
|
+
let startMinute: Int
|
|
77
|
+
let endHour: Int
|
|
78
|
+
let endMinute: Int
|
|
79
|
+
let weekdays: [Int]
|
|
80
|
+
|
|
81
|
+
init?(rule: String) {
|
|
82
|
+
raw = rule
|
|
83
|
+
let parts = rule.components(separatedBy: " ")
|
|
84
|
+
guard parts.count >= 2 else { return nil }
|
|
85
|
+
let timePart = parts[0].components(separatedBy: "-")
|
|
86
|
+
guard timePart.count == 2 else { return nil }
|
|
87
|
+
let startParts = timePart[0].components(separatedBy: ":")
|
|
88
|
+
let endParts = timePart[1].components(separatedBy: ":")
|
|
89
|
+
guard startParts.count == 2, endParts.count == 2 else { return nil }
|
|
90
|
+
startHour = Int(startParts[0]) ?? 0
|
|
91
|
+
startMinute = Int(startParts[1]) ?? 0
|
|
92
|
+
endHour = Int(endParts[0]) ?? 0
|
|
93
|
+
endMinute = Int(endParts[1]) ?? 0
|
|
94
|
+
weekdays = parts.dropFirst().compactMap { Int($0) }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func isActiveAt(_ date: Date) -> Bool {
|
|
98
|
+
let cal = Calendar.current
|
|
99
|
+
let weekday = cal.component(.weekday, from: date)
|
|
100
|
+
if !weekdays.isEmpty && !weekdays.contains(weekday) { return false }
|
|
101
|
+
let hour = cal.component(.hour, from: date)
|
|
102
|
+
let minute = cal.component(.minute, from: date)
|
|
103
|
+
let current = hour * 60 + minute
|
|
104
|
+
let start = startHour * 60 + startMinute
|
|
105
|
+
let end = endHour * 60 + endMinute
|
|
106
|
+
if start <= end {
|
|
107
|
+
return current >= start && current < end
|
|
108
|
+
} else {
|
|
109
|
+
return current >= start || current < end
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
func nextTriggerDate(after date: Date) -> Date? {
|
|
114
|
+
return nil
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import CoreLocation
|
|
3
|
+
|
|
4
|
+
@objc public class BGSingleLocationRequest: NSObject {
|
|
5
|
+
|
|
6
|
+
@objc public var type: String = "single"
|
|
7
|
+
@objc public var maximumAge: Double = 0
|
|
8
|
+
@objc public var timeout: Double = 30
|
|
9
|
+
@objc public var desiredAccuracy: CLLocationAccuracy = kCLLocationAccuracyBest
|
|
10
|
+
@objc public var allowStale: Bool = false
|
|
11
|
+
@objc public var samples: Int = 1
|
|
12
|
+
@objc public var label: String?
|
|
13
|
+
@objc public var persist: Bool = false
|
|
14
|
+
@objc public var extras: [AnyHashable: Any]?
|
|
15
|
+
@objc public var success: ((Any?) -> Void)?
|
|
16
|
+
@objc public var failure: ((Int) -> Void)?
|
|
17
|
+
@objc public var requestId: String = UUID().uuidString
|
|
18
|
+
|
|
19
|
+
@objc public override init() {
|
|
20
|
+
super.init()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@objc public init(
|
|
24
|
+
type: String,
|
|
25
|
+
maximumAge: Double,
|
|
26
|
+
timeout: Double,
|
|
27
|
+
desiredAccuracy: CLLocationAccuracy,
|
|
28
|
+
allowStale: Bool,
|
|
29
|
+
samples: Int,
|
|
30
|
+
label: String?,
|
|
31
|
+
persist: Bool,
|
|
32
|
+
extras: [AnyHashable: Any]?,
|
|
33
|
+
success: @escaping (Any?) -> Void,
|
|
34
|
+
failure: @escaping (Int) -> Void
|
|
35
|
+
) {
|
|
36
|
+
self.type = type
|
|
37
|
+
self.maximumAge = maximumAge
|
|
38
|
+
self.timeout = timeout
|
|
39
|
+
self.desiredAccuracy = desiredAccuracy
|
|
40
|
+
self.allowStale = allowStale
|
|
41
|
+
self.samples = samples
|
|
42
|
+
self.label = label
|
|
43
|
+
self.persist = persist
|
|
44
|
+
self.extras = extras
|
|
45
|
+
self.success = success
|
|
46
|
+
self.failure = failure
|
|
47
|
+
super.init()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import CoreLocation
|
|
3
|
+
|
|
4
|
+
@objc public class BGStreamLocationRequest: NSObject {
|
|
5
|
+
|
|
6
|
+
@objc public var streamId: Int = 0
|
|
7
|
+
@objc public var interval: Double = 1000.0
|
|
8
|
+
@objc public var desiredAccuracy: CLLocationAccuracy = kCLLocationAccuracyBest
|
|
9
|
+
@objc public var timeout: Double = 60.0
|
|
10
|
+
@objc public var persist: Bool = true
|
|
11
|
+
@objc public var extras: [AnyHashable: Any]?
|
|
12
|
+
@objc public var label: String?
|
|
13
|
+
@objc public var success: ((Any?) -> Void)?
|
|
14
|
+
@objc public var failure: ((Int) -> Void)?
|
|
15
|
+
|
|
16
|
+
@objc public override init() {
|
|
17
|
+
super.init()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@objc public init(
|
|
21
|
+
streamId: Int,
|
|
22
|
+
interval: Double,
|
|
23
|
+
desiredAccuracy: CLLocationAccuracy,
|
|
24
|
+
timeout: Double,
|
|
25
|
+
persist: Bool,
|
|
26
|
+
extras: [AnyHashable: Any]?,
|
|
27
|
+
label: String?,
|
|
28
|
+
success: @escaping (Any?) -> Void,
|
|
29
|
+
failure: @escaping (Int) -> Void
|
|
30
|
+
) {
|
|
31
|
+
self.streamId = streamId
|
|
32
|
+
self.interval = interval
|
|
33
|
+
self.desiredAccuracy = desiredAccuracy
|
|
34
|
+
self.timeout = timeout
|
|
35
|
+
self.persist = persist
|
|
36
|
+
self.extras = extras
|
|
37
|
+
self.label = label
|
|
38
|
+
self.success = success
|
|
39
|
+
self.failure = failure
|
|
40
|
+
super.init()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class BGTemplate: NSObject {
|
|
4
|
+
|
|
5
|
+
@objc public var name: String
|
|
6
|
+
@objc public var content: [String: Any]
|
|
7
|
+
|
|
8
|
+
@objc public init(name: String, content: [String: Any]) {
|
|
9
|
+
self.name = name
|
|
10
|
+
self.content = content
|
|
11
|
+
super.init()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@objc public override init() {
|
|
15
|
+
name = ""
|
|
16
|
+
content = [:]
|
|
17
|
+
super.init()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@objc public func render(with data: [String: Any]) -> [String: Any] {
|
|
21
|
+
var result: [String: Any] = [:]
|
|
22
|
+
for (key, value) in content {
|
|
23
|
+
if let strVal = value as? String {
|
|
24
|
+
result[key] = interpolate(strVal, with: data)
|
|
25
|
+
} else {
|
|
26
|
+
result[key] = value
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return result
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private func interpolate(_ template: String, with data: [String: Any]) -> String {
|
|
33
|
+
var result = template
|
|
34
|
+
let pattern = "<%=\\s*(.+?)\\s*%>"
|
|
35
|
+
guard let regex = try? NSRegularExpression(pattern: pattern) else { return template }
|
|
36
|
+
let range = NSRange(template.startIndex..., in: template)
|
|
37
|
+
let matches = regex.matches(in: template, range: range)
|
|
38
|
+
for match in matches.reversed() {
|
|
39
|
+
if let keyRange = Range(match.range(at: 1), in: template) {
|
|
40
|
+
let key = String(template[keyRange])
|
|
41
|
+
if let val = data[key] {
|
|
42
|
+
if let matchRange = Range(match.range, in: result) {
|
|
43
|
+
result.replaceSubrange(matchRange, with: "\(val)")
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@objc public override var description: String {
|
|
52
|
+
return "<BGTemplate name=\(name)>"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class BGTimerService: NSObject {
|
|
4
|
+
|
|
5
|
+
private var timers: [String: Timer] = [:]
|
|
6
|
+
private let lock = NSLock()
|
|
7
|
+
|
|
8
|
+
@objc public func scheduleTimer(
|
|
9
|
+
_ id: String,
|
|
10
|
+
interval: TimeInterval,
|
|
11
|
+
repeats: Bool,
|
|
12
|
+
block: @escaping () -> Void
|
|
13
|
+
) {
|
|
14
|
+
lock.lock()
|
|
15
|
+
timers[id]?.invalidate()
|
|
16
|
+
let timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: repeats) { _ in
|
|
17
|
+
block()
|
|
18
|
+
}
|
|
19
|
+
timers[id] = timer
|
|
20
|
+
lock.unlock()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@objc public func cancelTimer(_ id: String) {
|
|
24
|
+
lock.lock()
|
|
25
|
+
timers[id]?.invalidate()
|
|
26
|
+
timers.removeValue(forKey: id)
|
|
27
|
+
lock.unlock()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@objc public func cancelAllTimers() {
|
|
31
|
+
lock.lock()
|
|
32
|
+
timers.values.forEach { $0.invalidate() }
|
|
33
|
+
timers.removeAll()
|
|
34
|
+
lock.unlock()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@objc public func hasTimer(_ id: String) -> Bool {
|
|
38
|
+
lock.lock()
|
|
39
|
+
defer { lock.unlock() }
|
|
40
|
+
return timers[id]?.isValid ?? false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@objc public func isRunning(_ id: String) -> Bool {
|
|
44
|
+
return hasTimer(id)
|
|
45
|
+
}
|
|
46
|
+
}
|