@blueid/access-capacitor 0.78.0 → 0.80.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.
@@ -1,265 +0,0 @@
1
- //
2
- // BlueTokenSyncScheduler.swift
3
- //
4
- // Description: Synchronize all tokens from all available credentials at specific intervals.
5
- //
6
- // If you would like to test the background task during development, execute the following code in the console:
7
- // ```
8
- // e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.blue-id.BlueTokenSyncScheduler"]
9
- // ```
10
- //
11
- // Reference: https://developer.apple.com/documentation/backgroundtasks/starting-and-terminating-tasks-during-development#Launch-a-Task
12
- //
13
- // Copyright © 2023 BlueID. All rights reserved.
14
- //
15
-
16
- import Foundation
17
-
18
- private let bgTaskIdentifier = "com.blue-id.BlueTokenSyncScheduler"
19
-
20
- private class ForegroundScheduler {
21
- private var timer: Timer?
22
- private var scheduler: BlueTokenSyncScheduler?
23
-
24
- func setup(_ scheduler: BlueTokenSyncScheduler) {
25
- self.scheduler = scheduler
26
- }
27
-
28
- func suspend() {
29
- timer?.invalidate()
30
- timer = nil
31
- }
32
-
33
- func schedule(_ now: Bool? = false) {
34
- guard #available(macOS 10.15, *) else {
35
- blueLogWarn("Unsupported platform")
36
- return
37
- }
38
-
39
- suspend()
40
-
41
- if now == true {
42
- self.handleTask()
43
- } else {
44
- blueRunInMainThread {
45
- self.timer = Timer.scheduledTimer(
46
- timeInterval: self.scheduler!.timeInterval,
47
- target: self,
48
- selector: #selector(self.handleTask),
49
- userInfo: nil,
50
- repeats: false
51
- )
52
- }
53
- }
54
- }
55
-
56
- @available(macOS 10.15, *)
57
- @objc private func handleTask() {
58
- DispatchQueue.global(qos: .background).async {
59
- Task {
60
- do {
61
- try await self.scheduler!.syncTokens()
62
- } catch {
63
- blueLogError("Tokens could not be synchronized")
64
- }
65
-
66
- if (self.scheduler!.autoSchedule) {
67
- self.schedule()
68
- }
69
- }
70
- }
71
- }
72
- }
73
-
74
-
75
- #if os(iOS) || os(watchOS)
76
- import BackgroundTasks
77
-
78
- private class BackgroundScheduler {
79
- private var scheduler: BlueTokenSyncScheduler?
80
-
81
- func setup(_ scheduler: BlueTokenSyncScheduler) {
82
- self.scheduler = scheduler
83
- }
84
-
85
- func registerIdentifiers() {
86
- let registered = BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: DispatchQueue.global()) { task in
87
- self.handleTask(task: task as! BGProcessingTask)
88
- }
89
-
90
- if (!registered) {
91
- blueLogWarn("Could not register background task identifier: \(bgTaskIdentifier)")
92
- return
93
- }
94
-
95
- blueLogDebug("Background task identifier has been successfully registered: \(bgTaskIdentifier)")
96
- }
97
-
98
- func suspend() {
99
- BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: bgTaskIdentifier)
100
- }
101
-
102
- func schedule() {
103
- do {
104
- let request = BGProcessingTaskRequest(identifier: bgTaskIdentifier)
105
- request.earliestBeginDate = Date(timeIntervalSinceNow: scheduler!.timeInterval)
106
- request.requiresNetworkConnectivity = true
107
-
108
- try BGTaskScheduler.shared.submit(request)
109
-
110
- blueLogDebug("Background task has been successfully scheduled")
111
- } catch {
112
- blueLogError("Background task could not be scheduled: \(error)")
113
- }
114
- }
115
-
116
- private func handleTask(task: BGProcessingTask) -> Void {
117
- task.expirationHandler = {
118
- task.setTaskCompleted(success: false)
119
- }
120
-
121
- Task {
122
- do {
123
- try await scheduler!.syncTokens()
124
-
125
- task.setTaskCompleted(success: true)
126
- } catch {
127
- task.setTaskCompleted(success: false)
128
- }
129
-
130
- if (scheduler!.autoSchedule) {
131
- schedule()
132
- }
133
- }
134
- }
135
- }
136
- #endif
137
-
138
- internal class BlueTokenSyncScheduler: BlueEventListener {
139
- public static let shared = BlueTokenSyncScheduler()
140
-
141
- let timeInterval: TimeInterval
142
- let autoSchedule: Bool
143
-
144
- #if os(iOS) || os(watchOS)
145
- private let backgroundScheduler = BackgroundScheduler()
146
- #endif
147
-
148
- private let foregroundScheduler = ForegroundScheduler()
149
-
150
- private let command: BlueSynchronizeAccessCredentialCommand
151
-
152
- init(
153
- timeInterval: TimeInterval? = 60,
154
- autoSchedule: Bool? = true,
155
- command: BlueSynchronizeAccessCredentialCommand? = nil
156
- ) {
157
- self.command = command ?? blueCommands.synchronizeAccessCredential
158
- self.timeInterval = timeInterval ?? 60
159
- self.autoSchedule = autoSchedule ?? true
160
-
161
- foregroundScheduler.setup(self)
162
-
163
- #if os(iOS) || os(watchOS)
164
- backgroundScheduler.setup(self)
165
- #endif
166
-
167
- blueAddEventListener(listener: self)
168
- }
169
-
170
- deinit {
171
- blueRemoveEventListener(listener: self)
172
- }
173
-
174
- func willResignActive() {
175
- foregroundScheduler.suspend()
176
-
177
- #if os(iOS) || os(watchOS)
178
- backgroundScheduler.schedule()
179
- #endif
180
- }
181
-
182
- func didBecomeActive() {
183
- #if os(iOS) || os(watchOS)
184
- backgroundScheduler.suspend()
185
- #endif
186
-
187
- foregroundScheduler.schedule()
188
- }
189
-
190
- func didFinishLaunching() {
191
- setup()
192
- }
193
-
194
- func willTerminate() {
195
- suspend()
196
- }
197
-
198
- func blueEvent(event: BlueEventType, data: Any?) {
199
- if (event == .accessCredentialAdded) {
200
- schedule()
201
- }
202
- }
203
-
204
- func setup() {
205
- #if os(iOS)
206
- backgroundScheduler.registerIdentifiers()
207
- #endif
208
-
209
- schedule(true)
210
- }
211
-
212
- func schedule(_ now: Bool? = false) {
213
- do {
214
- guard try blueAccessCredentialsKeyChain.getNumberOfEntries() > 0 else {
215
- return
216
- }
217
- } catch {
218
- blueLogError(error.localizedDescription)
219
- }
220
-
221
- blueRemoveEventListener(listener: self)
222
-
223
- foregroundScheduler.schedule(now)
224
- }
225
-
226
- func suspend() {
227
- foregroundScheduler.suspend()
228
-
229
- #if os(iOS) || os(watchOS)
230
- backgroundScheduler.suspend()
231
- #endif
232
- }
233
-
234
- @available(macOS 10.15, *)
235
- func syncTokens() async throws -> Void {
236
- blueFireListeners(fireEvent: BlueEventType.tokenSyncStarted, data: nil)
237
-
238
- defer {
239
- blueFireListeners(fireEvent: BlueEventType.tokenSyncFinished, data: nil)
240
- }
241
-
242
- let accessCredentialList = try await blueCommands.getAccessCredentials.runAsync()
243
-
244
- await withThrowingTaskGroup(of: Void.self) { group in
245
- // After deleting the app, since we store credentials in KeyChain Access, they reappear upon app reinstallation.
246
- // But, as the device list is not saved there, it is lost.
247
- // So, when searching for nearby devices, nothing is shown due to the absence of the device list.
248
- // Although this issue would be solved in this synchronization, the synchronization may not return the device list as it depends on the refresh rate and can take up to 30 days, which is not ideal.
249
- // Therefore, we force a refresh in case the app has never been launched before.
250
- let forceRefresh = !blueAppHasLaunchedBefore()
251
-
252
- for credential in accessCredentialList.credentials {
253
- group.addTask {
254
- do {
255
- try await self.command.runAsync(credentialID: credential.credentialID.id, forceRefresh: forceRefresh)
256
-
257
- blueLogDebug("Access credential has been successfully synchronized: \(credential.credentialID.id)")
258
- } catch {
259
- blueLogError("Access credential could not be synchronized: \(credential.credentialID.id) - \(error.localizedDescription)")
260
- }
261
- }
262
- }
263
- }
264
- }
265
- }