@capacitor/background-runner 1.0.1-dev-20230731T175405.0 → 1.0.1-dev-20230809T182239.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,11 +1,48 @@
1
1
  export interface GetCurrentPositionResult {
2
+ /**
3
+ * Latitude in decimal degrees
4
+ *
5
+ * @since 1.0.0
6
+ */
2
7
  latitude: number;
8
+ /**
9
+ * longitude in decimal degrees
10
+ *
11
+ * @since 1.0.0
12
+ */
3
13
  longitude: number;
14
+ /**
15
+ * Accuracy level of the latitude and longitude coordinates in meters
16
+ *
17
+ * @since 1.0.0
18
+ */
4
19
  accuracy: number;
5
- altitude: number;
6
- altitudeAccuracy?: number;
7
- speed: number;
8
- heading: number;
20
+ /**
21
+ * The altitude the user is at (if available)
22
+ *
23
+ * @since 1.0.0
24
+ */
25
+ altitude: number | null;
26
+ /**
27
+ * Accuracy level of the altitude coordinate in meters, if available.
28
+ *
29
+ * Available on all iOS versions and on Android 8.0+.
30
+ *
31
+ * @since 1.0.0
32
+ */
33
+ altitudeAccuracy?: number | null | undefined;
34
+ /**
35
+ * The speed the user is traveling (if available)
36
+ *
37
+ * @since 1.0.0
38
+ */
39
+ speed: number | null;
40
+ /**
41
+ * The heading the user is facing (if available)
42
+ *
43
+ * @since 1.0.0
44
+ */
45
+ heading: number | null;
9
46
  }
10
47
  export interface BatteryStatus {
11
48
  batteryLevel: number;
@@ -16,37 +53,265 @@ export interface NetworkStatus {
16
53
  connectionType: string;
17
54
  }
18
55
  export interface NotificationScheduleOptions {
56
+ /**
57
+ * The notification identifier.
58
+ * On Android it's a 32-bit int.
59
+ * So the value should be between -2147483648 and 2147483647 inclusive.
60
+ *
61
+ * @since 1.0.0
62
+ */
19
63
  id: number;
64
+ /**
65
+ * The title of the notification.
66
+ *
67
+ * @since 1.0.0
68
+ */
20
69
  title: string;
70
+ /**
71
+ * The body of the notification, shown below the title.
72
+ *
73
+ * @since 1.0.0
74
+ */
21
75
  body: string;
76
+ /**
77
+ * Date to send this notification.
78
+ *
79
+ * @since 1.0.0
80
+ */
22
81
  scheduleAt: Date;
82
+ /**
83
+ * Name of the audio file to play when this notification is displayed.
84
+ *
85
+ * Include the file extension with the filename.
86
+ *
87
+ * On iOS, the file should be in the app bundle.
88
+ * On Android, the file should be in res/raw folder.
89
+ *
90
+ * Recommended format is `.wav` because is supported by both iOS and Android.
91
+ *
92
+ * Only available for iOS and Android < 26.
93
+ * For Android 26+ use channelId of a channel configured with the desired sound.
94
+ *
95
+ * If the sound file is not found, (i.e. empty string or wrong name)
96
+ * the default system notification sound will be used.
97
+ * If not provided, it will produce the default sound on Android and no sound on iOS.
98
+ *
99
+ * @since 1.0.0
100
+ */
23
101
  sound?: string;
102
+ /**
103
+ * Associate an action type with this notification.
104
+ *
105
+ * @since 1.0.0
106
+ */
24
107
  actionTypeId?: string;
108
+ /**
109
+ * Used to group multiple notifications.
110
+ *
111
+ * Sets `threadIdentifier` on the
112
+ * [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent).
113
+ *
114
+ * Only available for iOS.
115
+ *
116
+ * @since 1.0.0
117
+ */
25
118
  threadIdentifier?: string;
119
+ /**
120
+ * The string this notification adds to the category's summary format string.
121
+ *
122
+ * Sets `summaryArgument` on the
123
+ * [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent).
124
+ *
125
+ * Only available for iOS.
126
+ *
127
+ * @since 1.0.0
128
+ */
26
129
  summaryArgument?: string;
130
+ /**
131
+ * Used to group multiple notifications.
132
+ *
133
+ * Calls `setGroup()` on
134
+ * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)
135
+ * with the provided value.
136
+ *
137
+ * Only available for Android.
138
+ *
139
+ * @since 1.0.0
140
+ */
141
+ group?: string;
142
+ /**
143
+ * If true, this notification becomes the summary for a group of
144
+ * notifications.
145
+ *
146
+ * Calls `setGroupSummary()` on
147
+ * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)
148
+ * with the provided value.
149
+ *
150
+ * Only available for Android when using `group`.
151
+ *
152
+ * @since 1.0.0
153
+ */
27
154
  groupSummary?: string;
28
- extra?: unknown;
155
+ /**
156
+ * Set extra data to store within this notification.
157
+ *
158
+ * @since 1.0.0
159
+ */
160
+ extra?: any;
161
+ /**
162
+ * If true, the notification can't be swiped away.
163
+ *
164
+ * Calls `setOngoing()` on
165
+ * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)
166
+ * with the provided value.
167
+ *
168
+ * Only available for Android.
169
+ *
170
+ * @since 1.0.0
171
+ */
29
172
  ongoing?: boolean;
173
+ /**
174
+ * If true, the notification is canceled when the user clicks on it.
175
+ *
176
+ * Calls `setAutoCancel()` on
177
+ * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)
178
+ * with the provided value.
179
+ *
180
+ * Only available for Android.
181
+ *
182
+ * @since 1.0.0
183
+ */
30
184
  autoCancel?: boolean;
185
+ /**
186
+ * Sets a multiline text block for display in a big text notification style.
187
+ *
188
+ * @since 1.0.0
189
+ */
31
190
  largeBody?: string;
191
+ /**
192
+ * Used to set the summary text detail in inbox and big text notification styles.
193
+ *
194
+ * Only available for Android.
195
+ *
196
+ * @since 1.0.0
197
+ */
32
198
  summaryText?: string;
199
+ /**
200
+ * Set a custom status bar icon.
201
+ *
202
+ * If set, this overrides the `smallIcon` option from Capacitor
203
+ * configuration.
204
+ *
205
+ * Icons should be placed in your app's `res/drawable` folder. The value for
206
+ * this option should be the drawable resource ID, which is the filename
207
+ * without an extension.
208
+ *
209
+ * Only available for Android.
210
+ *
211
+ * @since 1.0.0
212
+ */
33
213
  smallIcon?: string;
214
+ /**
215
+ * Set a large icon for notifications.
216
+ *
217
+ * Icons should be placed in your app's `res/drawable` folder. The value for
218
+ * this option should be the drawable resource ID, which is the filename
219
+ * without an extension.
220
+ *
221
+ * Only available for Android.
222
+ *
223
+ * @since 1.0.0
224
+ */
34
225
  largeIcon?: string;
35
- group?: string;
226
+ /**
227
+ * Specifies the channel the notification should be delivered on.
228
+ *
229
+ * If channel with the given name does not exist then the notification will
230
+ * not fire. If not provided, it will use the default channel.
231
+ *
232
+ * Calls `setChannelId()` on
233
+ * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)
234
+ * with the provided value.
235
+ *
236
+ * Only available for Android 26+.
237
+ *
238
+ * @since 1.0.0
239
+ */
36
240
  channelId?: string;
37
241
  }
242
+ /**
243
+ * Get access to device location information.
244
+ *
245
+ * @since 1.0.0
246
+ */
38
247
  export interface CapacitorGeolocation {
248
+ /**
249
+ * Get the device's last known location
250
+ * @since 1.0.0
251
+ */
39
252
  getCurrentLocation: () => GetCurrentPositionResult;
40
253
  }
254
+ /**
255
+ * A simple string key / value store backed by UserDefaults on iOS and Shared Preferences on Android.
256
+ */
41
257
  export interface CapacitorKV {
258
+ /**
259
+ * Set a string value with the given key.
260
+ *
261
+ * @param key
262
+ * @param value
263
+ * @returns
264
+ * @since 1.0.0
265
+ */
42
266
  set: (key: string, value: string) => void;
267
+ /**
268
+ * Get a string value for the given key.
269
+ * @param key
270
+ * @returns
271
+ * @since 1.0.0
272
+ */
43
273
  get: (key: string) => string;
274
+ /**
275
+ * Remove a value with the given key.
276
+ * @param key
277
+ * @returns
278
+ * @since 1.0.0
279
+ */
44
280
  remove: (key: string) => void;
45
281
  }
282
+ /**
283
+ * Get information on the device, such as network connectivity and battery status.
284
+ */
46
285
  export interface CapacitorDevice {
286
+ /**
287
+ * Get the current battery status for the device.
288
+ *
289
+ * @since 1.0.0
290
+ */
47
291
  getBatteryStatus: () => BatteryStatus;
292
+ /**
293
+ * Get the current network status for the device.
294
+ *
295
+ * @since 1.0.0
296
+ */
48
297
  getNetworkStatus: () => NetworkStatus;
49
298
  }
299
+ /**
300
+ * Send basic local notifications.
301
+ */
50
302
  export interface CapacitorNotifications {
303
+ /**
304
+ * Schedule a local notification
305
+ * @example `CapacitorNotifications.schedule()`
306
+ * @param options
307
+ * @returns void
308
+ * @since 1.0.0
309
+ */
51
310
  schedule: (options: NotificationScheduleOptions[]) => void;
52
311
  }
312
+ export interface CapacitorAPI {
313
+ CapacitorDevice: CapacitorDevice;
314
+ CapacitorKV: CapacitorKV;
315
+ CapacitorNotifications: CapacitorNotifications;
316
+ CapacitorGeolocation: CapacitorGeolocation;
317
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"apis.js","sourceRoot":"","sources":["../../src/apis.ts"],"names":[],"mappings":"","sourcesContent":["export interface GetCurrentPositionResult {\n latitude: number;\n longitude: number;\n accuracy: number;\n altitude: number;\n altitudeAccuracy?: number;\n speed: number;\n heading: number;\n}\n\nexport interface BatteryStatus {\n batteryLevel: number;\n isCharging: boolean;\n}\n\nexport interface NetworkStatus {\n connected: boolean;\n connectionType: string;\n}\n\nexport interface NotificationScheduleOptions {\n id: number;\n title: string;\n body: string;\n scheduleAt: Date;\n sound?: string;\n actionTypeId?: string;\n threadIdentifier?: string;\n summaryArgument?: string;\n groupSummary?: string;\n extra?: unknown;\n ongoing?: boolean;\n autoCancel?: boolean;\n largeBody?: string;\n summaryText?: string;\n smallIcon?: string;\n largeIcon?: string;\n group?: string;\n channelId?: string;\n}\n\nexport interface CapacitorGeolocation {\n getCurrentLocation: () => GetCurrentPositionResult;\n}\n\nexport interface CapacitorKV {\n set: (key: string, value: string) => void;\n get: (key: string) => string;\n remove: (key: string) => void;\n}\n\nexport interface CapacitorDevice {\n getBatteryStatus: () => BatteryStatus;\n getNetworkStatus: () => NetworkStatus;\n}\n\nexport interface CapacitorNotifications {\n schedule: (options: NotificationScheduleOptions[]) => void;\n}\n"]}
1
+ {"version":3,"file":"apis.js","sourceRoot":"","sources":["../../src/apis.ts"],"names":[],"mappings":"","sourcesContent":["export interface GetCurrentPositionResult {\n /**\n * Latitude in decimal degrees\n *\n * @since 1.0.0\n */\n latitude: number;\n /**\n * longitude in decimal degrees\n *\n * @since 1.0.0\n */\n longitude: number;\n /**\n * Accuracy level of the latitude and longitude coordinates in meters\n *\n * @since 1.0.0\n */\n accuracy: number;\n /**\n * The altitude the user is at (if available)\n *\n * @since 1.0.0\n */\n altitude: number | null;\n /**\n * Accuracy level of the altitude coordinate in meters, if available.\n *\n * Available on all iOS versions and on Android 8.0+.\n *\n * @since 1.0.0\n */\n altitudeAccuracy?: number | null | undefined;\n /**\n * The speed the user is traveling (if available)\n *\n * @since 1.0.0\n */\n speed: number | null;\n /**\n * The heading the user is facing (if available)\n *\n * @since 1.0.0\n */\n heading: number | null;\n}\n\nexport interface BatteryStatus {\n batteryLevel: number;\n isCharging: boolean;\n}\n\nexport interface NetworkStatus {\n connected: boolean;\n connectionType: string;\n}\n\nexport interface NotificationScheduleOptions {\n /**\n * The notification identifier.\n * On Android it's a 32-bit int.\n * So the value should be between -2147483648 and 2147483647 inclusive.\n *\n * @since 1.0.0\n */\n id: number;\n /**\n * The title of the notification.\n *\n * @since 1.0.0\n */\n title: string;\n /**\n * The body of the notification, shown below the title.\n *\n * @since 1.0.0\n */\n body: string;\n /**\n * Date to send this notification.\n *\n * @since 1.0.0\n */\n scheduleAt: Date;\n /**\n * Name of the audio file to play when this notification is displayed.\n *\n * Include the file extension with the filename.\n *\n * On iOS, the file should be in the app bundle.\n * On Android, the file should be in res/raw folder.\n *\n * Recommended format is `.wav` because is supported by both iOS and Android.\n *\n * Only available for iOS and Android < 26.\n * For Android 26+ use channelId of a channel configured with the desired sound.\n *\n * If the sound file is not found, (i.e. empty string or wrong name)\n * the default system notification sound will be used.\n * If not provided, it will produce the default sound on Android and no sound on iOS.\n *\n * @since 1.0.0\n */\n sound?: string;\n /**\n * Associate an action type with this notification.\n *\n * @since 1.0.0\n */\n actionTypeId?: string;\n /**\n * Used to group multiple notifications.\n *\n * Sets `threadIdentifier` on the\n * [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent).\n *\n * Only available for iOS.\n *\n * @since 1.0.0\n */\n threadIdentifier?: string;\n /**\n * The string this notification adds to the category's summary format string.\n *\n * Sets `summaryArgument` on the\n * [`UNMutableNotificationContent`](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent).\n *\n * Only available for iOS.\n *\n * @since 1.0.0\n */\n summaryArgument?: string;\n /**\n * Used to group multiple notifications.\n *\n * Calls `setGroup()` on\n * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)\n * with the provided value.\n *\n * Only available for Android.\n *\n * @since 1.0.0\n */\n group?: string;\n /**\n * If true, this notification becomes the summary for a group of\n * notifications.\n *\n * Calls `setGroupSummary()` on\n * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)\n * with the provided value.\n *\n * Only available for Android when using `group`.\n *\n * @since 1.0.0\n */\n groupSummary?: string;\n /**\n * Set extra data to store within this notification.\n *\n * @since 1.0.0\n */\n extra?: any;\n /**\n * If true, the notification can't be swiped away.\n *\n * Calls `setOngoing()` on\n * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)\n * with the provided value.\n *\n * Only available for Android.\n *\n * @since 1.0.0\n */\n ongoing?: boolean;\n /**\n * If true, the notification is canceled when the user clicks on it.\n *\n * Calls `setAutoCancel()` on\n * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)\n * with the provided value.\n *\n * Only available for Android.\n *\n * @since 1.0.0\n */\n autoCancel?: boolean;\n /**\n * Sets a multiline text block for display in a big text notification style.\n *\n * @since 1.0.0\n */\n largeBody?: string;\n /**\n * Used to set the summary text detail in inbox and big text notification styles.\n *\n * Only available for Android.\n *\n * @since 1.0.0\n */\n summaryText?: string;\n /**\n * Set a custom status bar icon.\n *\n * If set, this overrides the `smallIcon` option from Capacitor\n * configuration.\n *\n * Icons should be placed in your app's `res/drawable` folder. The value for\n * this option should be the drawable resource ID, which is the filename\n * without an extension.\n *\n * Only available for Android.\n *\n * @since 1.0.0\n */\n smallIcon?: string;\n /**\n * Set a large icon for notifications.\n *\n * Icons should be placed in your app's `res/drawable` folder. The value for\n * this option should be the drawable resource ID, which is the filename\n * without an extension.\n *\n * Only available for Android.\n *\n * @since 1.0.0\n */\n largeIcon?: string;\n /**\n * Specifies the channel the notification should be delivered on.\n *\n * If channel with the given name does not exist then the notification will\n * not fire. If not provided, it will use the default channel.\n *\n * Calls `setChannelId()` on\n * [`NotificationCompat.Builder`](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder)\n * with the provided value.\n *\n * Only available for Android 26+.\n *\n * @since 1.0.0\n */\n channelId?: string;\n}\n\n/**\n * Get access to device location information.\n *\n * @since 1.0.0\n */\nexport interface CapacitorGeolocation {\n /**\n * Get the device's last known location\n * @since 1.0.0\n */\n getCurrentLocation: () => GetCurrentPositionResult;\n}\n\n/**\n * A simple string key / value store backed by UserDefaults on iOS and Shared Preferences on Android.\n */\nexport interface CapacitorKV {\n /**\n * Set a string value with the given key.\n *\n * @param key\n * @param value\n * @returns\n * @since 1.0.0\n */\n set: (key: string, value: string) => void;\n /**\n * Get a string value for the given key.\n * @param key\n * @returns\n * @since 1.0.0\n */\n get: (key: string) => string;\n /**\n * Remove a value with the given key.\n * @param key\n * @returns\n * @since 1.0.0\n */\n remove: (key: string) => void;\n}\n\n/**\n * Get information on the device, such as network connectivity and battery status.\n */\nexport interface CapacitorDevice {\n /**\n * Get the current battery status for the device.\n *\n * @since 1.0.0\n */\n getBatteryStatus: () => BatteryStatus;\n /**\n * Get the current network status for the device.\n *\n * @since 1.0.0\n */\n getNetworkStatus: () => NetworkStatus;\n}\n\n/**\n * Send basic local notifications.\n */\nexport interface CapacitorNotifications {\n /**\n * Schedule a local notification\n * @example `CapacitorNotifications.schedule()`\n * @param options\n * @returns void\n * @since 1.0.0\n */\n schedule: (options: NotificationScheduleOptions[]) => void;\n}\n\nexport interface CapacitorAPI {\n CapacitorDevice: CapacitorDevice;\n CapacitorKV: CapacitorKV;\n CapacitorNotifications: CapacitorNotifications;\n CapacitorGeolocation: CapacitorGeolocation;\n}\n"]}
@@ -145,17 +145,12 @@ public class BackgroundRunner {
145
145
  throw BackgroundRunnerPluginError.runnerError(reason: "no loaded context for config")
146
146
  }
147
147
 
148
- var inputArgsWithCallback = inputArgs
149
-
150
- if inputArgsWithCallback == nil {
151
- inputArgsWithCallback = [:]
152
- }
153
-
154
148
  let waitGroup = DispatchGroup()
155
149
 
156
150
  var result: [String: Any]?
151
+ var rejectionErr: JSError?
157
152
 
158
- let completedFunc: @convention(block)(JavaScriptCore.JSValue) -> Void = { returnObj in
153
+ let resolveFunc: @convention(block)(JavaScriptCore.JSValue) -> Void = { returnObj in
159
154
  if !returnObj.isUndefined && !returnObj.isNull {
160
155
  var dict: [String: Any] = [:]
161
156
 
@@ -170,14 +165,57 @@ public class BackgroundRunner {
170
165
  return
171
166
  }
172
167
 
173
- inputArgsWithCallback?["__ebr::completed"] = completedFunc
168
+ let rejectFunc: @convention(block)(JavaScriptCore.JSValue) -> Void = { rejectObj in
169
+ var rejectionTitle = "Error"
170
+ var rejectionMessage = ""
171
+
172
+ if !rejectObj.isUndefined && !rejectObj.isNull {
173
+ if let errStr = rejectObj.toString() {
174
+ let split = errStr.split(separator: ":", maxSplits: 1)
175
+ if split.count == 0 {
176
+ rejectionMessage = String(split.first ?? "")
177
+ } else {
178
+ rejectionTitle = String(split.first ?? "Error")
179
+ rejectionMessage = String(split.last ?? "")
180
+ }
181
+ }
182
+
183
+ if rejectObj.isObject, let errDict = rejectObj.toDictionary() {
184
+ if let errTitle = errDict["name"] as? String {
185
+ rejectionTitle = errTitle
186
+ }
187
+
188
+ if let errMsg = errDict["message"] as? String {
189
+ rejectionMessage = errMsg
190
+ }
191
+ }
192
+ }
193
+
194
+ rejectionErr = JSError(message: "\(rejectionTitle): \(rejectionMessage)")
195
+
196
+ waitGroup.leave()
197
+ return
198
+ }
199
+
200
+ var args: [String: Any] = [:]
201
+
202
+ var callbacks: [String: Any] = [:]
203
+ callbacks["__cbr::resolve"] = resolveFunc
204
+ callbacks["__cbr::reject"] = rejectFunc
205
+
206
+ args["callbacks"] = callbacks
207
+ args["dataArgs"] = inputArgs
174
208
 
175
209
  waitGroup.enter()
176
210
 
177
- try context.dispatchEvent(event: event, details: inputArgsWithCallback)
211
+ try context.dispatchEvent(event: event, details: args)
178
212
 
179
213
  waitGroup.wait()
180
214
 
215
+ if let rejection = rejectionErr {
216
+ throw EngineError.jsException(details: rejection.message)
217
+ }
218
+
181
219
  return result
182
220
  } catch {
183
221
  print("error executing task: \(error)")
@@ -3,7 +3,7 @@ import JavaScriptCore
3
3
 
4
4
  @objc protocol CapacitorKVStoreExports: JSExport {
5
5
  static func set(_ key: String, _ value: String)
6
- static func get(_ key: String) -> String?
6
+ static func get(_ key: String) -> JSValue
7
7
  static func remove(_ key: String)
8
8
  }
9
9
 
@@ -12,8 +12,13 @@ class CapacitorKVStore: NSObject, CapacitorKVStoreExports {
12
12
  UserDefaults.standard.set(value, forKey: key)
13
13
  }
14
14
 
15
- static func get(_ key: String) -> String? {
16
- return UserDefaults.standard.string(forKey: key)
15
+ static func get(_ key: String) -> JSValue {
16
+ var valueWrapper: [String: String] = [:]
17
+
18
+ let value = UserDefaults.standard.string(forKey: key)
19
+ valueWrapper["value"] = value
20
+
21
+ return JSValue(object: valueWrapper, in: JSContext.current())
17
22
  }
18
23
 
19
24
  static func remove(_ key: String) {
@@ -6,7 +6,9 @@ public class Context {
6
6
  let ctx: JSContext
7
7
 
8
8
  private var timers = [Int: Timer]()
9
- private var eventListeners = [String: [JSValue]]()
9
+ private var eventListeners = [String: JSValue]()
10
+ private var thread: Thread!
11
+ private var runLoop: RunLoop?
10
12
 
11
13
  // swiftlint:disable:next identifier_name
12
14
  public init(vm: JSVirtualMachine, ctxName: String) throws {
@@ -19,6 +21,20 @@ public class Context {
19
21
  name = ctxName
20
22
  ctx = newCtx
21
23
 
24
+ thread = Thread { [weak self] in
25
+ self?.runLoop = RunLoop.current
26
+
27
+ while self != nil && !self!.thread.isCancelled && self!.runLoop != nil {
28
+ self?.runLoop?.run(mode: .default, before: .distantFuture)
29
+ }
30
+
31
+ Thread.exit()
32
+ }
33
+
34
+ thread.name = "[\(name)] context thread"
35
+ thread.qualityOfService = .userInitiated
36
+ thread.start()
37
+
22
38
  try setupWebAPI()
23
39
  }
24
40
 
@@ -39,41 +55,51 @@ public class Context {
39
55
  }
40
56
 
41
57
  public func dispatchEvent(event: String, details: [String: Any]? = nil) throws {
42
- if let callbacks = eventListeners[event] {
43
- try callbacks.forEach { jsFunc in
44
- var thrownException: JSValue?
58
+ if let eventHandler = eventListeners[event] {
59
+ var dataArgs = details?["dataArgs"] as? [String: Any]
60
+ if dataArgs == nil {
61
+ dataArgs = details
62
+ }
45
63
 
46
- self.ctx.exceptionHandler = { _, exception in
47
- thrownException = exception
64
+ var callbackFunctions: [String: JSValue] = [:]
65
+
66
+ if let callbacks = details?["callbacks"] as? [String: Any] {
67
+ callbacks.keys.forEach { key in
68
+ if key.hasPrefix("__cbr::") {
69
+ let funcName = key.replacingOccurrences(of: "__cbr::", with: "")
70
+ callbackFunctions[funcName] = JSValue.init(object: callbacks[key], in: self.ctx)
71
+ }
48
72
  }
73
+ }
49
74
 
50
- if let detailsObj = details {
51
- var callbackFunctions: [String: Any] = [:]
75
+ var thrownException: JSValue?
52
76
 
53
- detailsObj.keys.forEach { key in
54
- if key.hasPrefix("__ebr::") {
55
- let funcName = key.replacingOccurrences(of: "__ebr::", with: "")
56
- callbackFunctions[funcName] = detailsObj[key]
57
- }
58
- }
77
+ self.ctx.exceptionHandler = { _, exception in
78
+ thrownException = exception
79
+ }
59
80
 
60
- guard let jsDetailsObj = JSValue(object: detailsObj, in: self.ctx) else {
61
- throw EngineError.jsValueError
62
- }
81
+ var callArgs: [Any] = []
63
82
 
64
- callbackFunctions.forEach { (funcName: String, jsFunc: Any) in
65
- jsDetailsObj.setValue(jsFunc, forProperty: funcName)
66
- }
83
+ if let resolveFunc = callbackFunctions["resolve"],
84
+ let rejectFunc = callbackFunctions["reject"] {
85
+ callArgs.append(resolveFunc)
86
+ callArgs.append(rejectFunc)
87
+ }
67
88
 
68
- jsFunc.call(withArguments: [jsDetailsObj])
69
- } else {
70
- jsFunc.call(withArguments: [])
89
+ if let dataArgs = dataArgs {
90
+ guard let jsDataArgs = JSValue(object: dataArgs, in: self.ctx) else {
91
+ throw EngineError.jsValueError
71
92
  }
72
93
 
73
- if let exception = thrownException {
74
- throw EngineError.jsException(details: String(describing: exception))
75
- }
94
+ callArgs.append(jsDataArgs)
76
95
  }
96
+
97
+ eventHandler.call(withArguments: callArgs)
98
+
99
+ if let exception = thrownException {
100
+ throw EngineError.jsException(details: String(describing: exception))
101
+ }
102
+
77
103
  }
78
104
  }
79
105
  private func setupWebAPI() throws {
@@ -93,6 +119,7 @@ public class Context {
93
119
  let fetchFunc: @convention(block) (JSValue, JSValue) -> JSValue = { resource, options in
94
120
  return fetch(resource: resource, options: options)
95
121
  }
122
+
96
123
  let newTextEncoderConst: @convention(block) () -> JSTextEncoder = JSTextEncoder.init
97
124
  let newTextDecoderConst: @convention(block) (String?, [AnyHashable: Any]?) -> JSTextDecoder = JSTextDecoder.init
98
125
 
@@ -110,15 +137,11 @@ public class Context {
110
137
  }
111
138
 
112
139
  private func addEventListener(eventName: String, callback: JSValue) {
113
- if eventListeners[eventName] == nil {
114
- eventListeners[eventName] = [callback]
115
- } else {
116
- eventListeners[eventName]?.append(callback)
117
- }
140
+ eventListeners[eventName] = callback
118
141
  }
119
142
 
120
143
  private func initTimer(callback: JSValue, timeout: Int, isInterval: Bool) -> Int {
121
- let timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(timeout / 1000), repeats: isInterval) { t in
144
+ let timer = Timer(timeInterval: TimeInterval(timeout / 1000), repeats: isInterval) { t in
122
145
  callback.call(withArguments: [])
123
146
  if !isInterval {
124
147
  let timerId = Int(Int32.init(truncatingIfNeeded: t.hashValue))
@@ -127,11 +150,16 @@ public class Context {
127
150
  }
128
151
 
129
152
  let timerId = Int(Int32.init(truncatingIfNeeded: timer.hashValue))
130
-
131
- RunLoop.current.add(timer, forMode: .common)
132
-
133
153
  timers[timerId] = timer
134
154
 
155
+ if let runLoop = self.runLoop {
156
+ runLoop.add(timer, forMode: .default)
157
+ runLoop.add(timer, forMode: .common)
158
+ } else {
159
+ RunLoop.current.add(timer, forMode: .default)
160
+ RunLoop.current.add(timer, forMode: .common)
161
+ }
162
+
135
163
  return timerId
136
164
  }
137
165
 
@@ -15,7 +15,7 @@ import JavaScriptCore
15
15
  dynamic var status: Int
16
16
  // swiftlint:disable:next identifier_name
17
17
  dynamic var ok: Bool {
18
- return status > 200 && status <= 299
18
+ return status >= 200 && status <= 299
19
19
  }
20
20
 
21
21
  private let data: Data?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/background-runner",
3
- "version": "1.0.1-dev-20230731T175405.0",
3
+ "version": "1.0.1-dev-20230809T182239.0",
4
4
  "description": "Capacitor Background Runner",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -38,8 +38,9 @@
38
38
  "prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
39
39
  "swiftlint": "node-swiftlint",
40
40
  "docgen": "docgen --api BackgroundRunnerPlugin --output-readme README.md --output-json dist/docs.json",
41
+ "docgen-api": "docgen --api CapacitorAPI --output-readme API.md --output-json dist/docs-api.json && node ./scripts/combine_docs.js",
41
42
  "build-sdk": "./scripts/build-native-sdks.sh",
42
- "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js && npm run build-sdk && ./scripts/copy-native-sdks.sh && npm pack && mv ./capacitor-background-runner-*.tgz ../../",
43
+ "build": "npm run clean && npm run docgen && npm run docgen-api && tsc && rollup -c rollup.config.js && npm run build-sdk && ./scripts/copy-native-sdks.sh && npm pack && mv ./capacitor-background-runner-*.tgz ../../ && ./scripts/copy-readme.sh",
43
44
  "pack": "npm run build && && ./scripts/copy-native-sdks.sh && npm pack && mv ./capacitor-background-runner-*.tgz ../../",
44
45
  "clean": "rimraf ./dist",
45
46
  "watch": "tsc --watch",
@@ -79,5 +80,5 @@
79
80
  "src": "android"
80
81
  }
81
82
  },
82
- "gitHead": "e954d30817185152c5ff0c63cd9bc7a6e3b5cfa0"
83
+ "gitHead": "e512c827056b1efb2be4da995d04b2755d86717e"
83
84
  }