@capacitor/background-runner 2.2.0 → 3.0.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/CapacitorBackgroundRunner.podspec +2 -2
- package/Package.swift +45 -0
- package/README.md +12 -2
- package/android/build.gradle +12 -12
- package/android/src/main/java/io/ionic/backgroundrunner/plugin/BackgroundRunnerPlugin.kt +1 -1
- package/android/src/main/java/io/ionic/backgroundrunner/plugin/api/Device.kt +1 -1
- package/android/src/main/java/io/ionic/backgroundrunner/plugin/api/Notifications.kt +2 -10
- package/android/src/main/java/io/ionic/backgroundrunner/plugin/api/TimedNotificationPublisher.kt +1 -0
- package/android/src/main/libs/android-js-engine-release.aar +0 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +2 -4
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +2 -4
- package/dist/plugin.js.map +1 -1
- package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/BackgroundRunner.swift +26 -11
- package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Geolocation.swift +21 -9
- package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Notifications.swift +2 -1
- package/ios/Sources/CapacitorBackgroundRunner/CapacitorBackgroundRunner.swift +308 -0
- package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/Context+CapacitorAPI.swift +8 -2
- package/ios/{Plugin → Sources}/RunnerEngine/Context.swift +1 -1
- package/ios/{Plugin → Sources}/RunnerEngine/JSCrypto.swift +3 -3
- package/ios/{Plugin → Sources}/RunnerEngine/JSError.swift +1 -1
- package/ios/{Plugin → Sources}/RunnerEngine/Runner.swift +1 -1
- package/ios/Tests/CapacitorBackgroundRunnerTests/CapacitorBackgroundRunnerTests.swift +21 -0
- package/ios/Tests/RunnerEngineTests/ContextTests.swift +393 -0
- package/ios/Tests/RunnerEngineTests/RunnerTests.swift +32 -0
- package/package.json +24 -22
- package/scripts/install_libs.js +4 -12
- package/ios/Plugin/BackgroundRunnerPlugin.h +0 -10
- package/ios/Plugin/BackgroundRunnerPlugin.m +0 -12
- package/ios/Plugin/BackgroundRunnerPlugin.swift +0 -228
- package/ios/Plugin/Info.plist +0 -24
- /package/ios/{Plugin/BackgroundRunnerErrors.swift → Sources/CapacitorBackgroundRunner/BackgroundRunnerPluginError.swift} +0 -0
- /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/App.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Device.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/KV.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Reachability.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Watch.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/RunnerConfig.swift +0 -0
- /package/ios/{Plugin/WatchConnectivtySessionDelegate.swift → Sources/CapacitorBackgroundRunner/WatchConnectivitySessionDelegate.swift} +0 -0
- /package/ios/{Plugin → Sources}/RunnerEngine/Errors.swift +0 -0
- /package/ios/{Plugin → Sources}/RunnerEngine/JSConsole.swift +0 -0
- /package/ios/{Plugin → Sources}/RunnerEngine/JSFetch.swift +0 -0
- /package/ios/{Plugin → Sources}/RunnerEngine/JSResponse.swift +0 -0
- /package/ios/{Plugin → Sources}/RunnerEngine/JSTextDecoder.swift +0 -0
- /package/ios/{Plugin → Sources}/RunnerEngine/JSTextEncoder.swift +0 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
// swiftlint:disable all
|
|
2
|
+
|
|
3
|
+
import XCTest
|
|
4
|
+
import JavaScriptCore
|
|
5
|
+
@testable import RunnerEngine
|
|
6
|
+
|
|
7
|
+
final class ContextTests: XCTestCase {
|
|
8
|
+
func testNullEval() throws {
|
|
9
|
+
let runner = Runner()
|
|
10
|
+
let context = try runner.createContext(name: "io.backgroundrunner.nulleval")
|
|
11
|
+
guard let value = try context.execute(code: "undefined") else {
|
|
12
|
+
XCTFail("value is null")
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
XCTAssertTrue(value.isUndefined)
|
|
17
|
+
|
|
18
|
+
guard let value = try context.execute(code: "const test = null; test;") else {
|
|
19
|
+
XCTFail("value is null")
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
XCTAssertTrue(value.isNull)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func testBoolEval() throws {
|
|
27
|
+
let runner = Runner()
|
|
28
|
+
let context = try runner.createContext(name: "io.backgroundrunner.booleval")
|
|
29
|
+
|
|
30
|
+
guard let value = try context.execute(code: "let test = (1 == 1); test;") else {
|
|
31
|
+
XCTFail("value is null")
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
XCTAssertTrue(value.isBoolean)
|
|
36
|
+
XCTAssertTrue(value.toBool())
|
|
37
|
+
|
|
38
|
+
guard let value = try context.execute(code: "test = (100 == 200); test;") else {
|
|
39
|
+
XCTFail("value is null")
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
XCTAssertTrue(value.isBoolean)
|
|
44
|
+
XCTAssertFalse(value.toBool())
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func testIntegerEval() throws {
|
|
48
|
+
let runner = Runner()
|
|
49
|
+
let context = try runner.createContext(name: "io.backgroundrunner.inteval")
|
|
50
|
+
|
|
51
|
+
guard let value = try context.execute(code: "1 +2;") else {
|
|
52
|
+
XCTFail("value is null")
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
XCTAssertTrue(value.isNumber)
|
|
57
|
+
XCTAssertEqual(3, value.toInt32())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func testFloatEval() throws {
|
|
61
|
+
let runner = Runner()
|
|
62
|
+
let context = try runner.createContext(name: "io.backgroundrunner.dbleval")
|
|
63
|
+
|
|
64
|
+
guard let value = try context.execute(code: "10.8 + 2.77;") else {
|
|
65
|
+
XCTFail("value is null")
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
XCTAssertTrue(value.isNumber)
|
|
70
|
+
XCTAssertEqual(13.57, value.toDouble())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func testStringEval() throws {
|
|
74
|
+
let runner = Runner()
|
|
75
|
+
let context = try runner.createContext(name: "io.backgroundrunner.stringeval")
|
|
76
|
+
|
|
77
|
+
guard let value = try context.execute(code: "'hello' + ' ' + 'world';") else {
|
|
78
|
+
XCTFail("value is null")
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
XCTAssertTrue(value.isString)
|
|
83
|
+
XCTAssertEqual("hello world", value.toString())
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func testConsoleAPI() throws {
|
|
87
|
+
let runner = Runner()
|
|
88
|
+
let context = try runner.createContext(name: "io.backgroundrunner.consoletests")
|
|
89
|
+
|
|
90
|
+
_ = try context.execute(code: "console.log('hello world');")
|
|
91
|
+
_ = try context.execute(code: "console.info('this message is for informational purposes');")
|
|
92
|
+
_ = try context.execute(code: "console.warn('this is a warning message');")
|
|
93
|
+
_ = try context.execute(code: "console.error('a problem has occurred');")
|
|
94
|
+
_ = try context.execute(code: "console.debug('this is a debugging statement');")
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func testEventListeners() throws {
|
|
98
|
+
let runner = Runner()
|
|
99
|
+
let context = try runner.createContext(name: "io.backgroundrunner.eventlistenertests")
|
|
100
|
+
|
|
101
|
+
let expectation = XCTestExpectation(description: "Run callback on event")
|
|
102
|
+
let expectation2 = XCTestExpectation(description: "Run another callback on event")
|
|
103
|
+
let expectation3 = XCTestExpectation(description: "Run another callback on event with details")
|
|
104
|
+
|
|
105
|
+
var successCallbackCalled = 0
|
|
106
|
+
var altSuccessCallbackCalled = 0
|
|
107
|
+
|
|
108
|
+
let successCallback: @convention(block) () -> Void = {
|
|
109
|
+
successCallbackCalled += 1
|
|
110
|
+
expectation.fulfill()
|
|
111
|
+
}
|
|
112
|
+
let successCallback2: @convention(block) () -> Void = {
|
|
113
|
+
altSuccessCallbackCalled += 1
|
|
114
|
+
expectation2.fulfill()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let successCallbackDetails: @convention(block) (JSValue) -> Void = {details in
|
|
118
|
+
XCTAssertTrue(details.isObject)
|
|
119
|
+
|
|
120
|
+
let detailsObj = details.toDictionary() as? [String: String]
|
|
121
|
+
XCTAssertEqual(detailsObj?["name"], "John Doe")
|
|
122
|
+
|
|
123
|
+
expectation3.fulfill()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
context.jsContext.setObject(successCallback, forKeyedSubscript: "successCallback" as NSString)
|
|
127
|
+
context.jsContext.setObject(successCallback2, forKeyedSubscript: "altSuccessCallback" as NSString)
|
|
128
|
+
context.jsContext.setObject(successCallbackDetails, forKeyedSubscript: "successCallbackDetails" as NSString)
|
|
129
|
+
|
|
130
|
+
_ = try context.execute(code: "addEventListener('myEvent', () => { successCallback(); });")
|
|
131
|
+
try context.dispatchEvent(event: "myEvent")
|
|
132
|
+
|
|
133
|
+
wait(for: [expectation], timeout: 1)
|
|
134
|
+
|
|
135
|
+
_ = try context.execute(code: "addEventListener('myEvent', () => { altSuccessCallback(); });")
|
|
136
|
+
try context.dispatchEvent(event: "myEvent")
|
|
137
|
+
|
|
138
|
+
wait(for: [expectation2], timeout: 1)
|
|
139
|
+
|
|
140
|
+
XCTAssertEqual(successCallbackCalled, 1)
|
|
141
|
+
XCTAssertEqual(altSuccessCallbackCalled, 1)
|
|
142
|
+
|
|
143
|
+
var detailsObject = [String: String]()
|
|
144
|
+
detailsObject["name"] = "John Doe"
|
|
145
|
+
|
|
146
|
+
_ = try context.execute(code: "addEventListener('myEventDetails', (details) => { successCallbackDetails(details); });")
|
|
147
|
+
try context.dispatchEvent(event: "myEventDetails", details: detailsObject)
|
|
148
|
+
|
|
149
|
+
wait(for: [expectation3], timeout: 1)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func testCryptoAPI() throws {
|
|
153
|
+
let runner = Runner()
|
|
154
|
+
let context = try runner.createContext(name: "io.backgroundrunner.cryptotests")
|
|
155
|
+
|
|
156
|
+
guard let value = try context.execute(code: "const array = new Uint32Array(10); crypto.getRandomValues(array); array;") else {
|
|
157
|
+
XCTFail("value is null")
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
if value.isNull || value.isUndefined {
|
|
161
|
+
XCTFail("value is null")
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
XCTAssertTrue(value.isObject)
|
|
166
|
+
XCTAssertEqual(10, value.toDictionary().count)
|
|
167
|
+
|
|
168
|
+
guard let value = try context.execute(code: "crypto.randomUUID();") else {
|
|
169
|
+
XCTFail("value is null")
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
if value.isNull || value.isUndefined {
|
|
173
|
+
XCTFail("value is null")
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
XCTAssertTrue(value.isString)
|
|
178
|
+
XCTAssertEqual(36, value.toString().count)
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
func testTimeoutAPI() throws {
|
|
183
|
+
let runner = Runner()
|
|
184
|
+
let context = try runner.createContext(name: "io.backgroundrunner.timeouttests")
|
|
185
|
+
|
|
186
|
+
let expectation = XCTestExpectation(description: "Run callback set on timeout")
|
|
187
|
+
let cancelExpectation = XCTestExpectation(description: "Cancel an already set up timeout")
|
|
188
|
+
|
|
189
|
+
let successCallback: @convention(block) () -> Void = {
|
|
190
|
+
expectation.fulfill()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let failureCallback: @convention(block) () -> Void = {
|
|
194
|
+
XCTFail("callback was called and not canceled")
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
context.jsContext.setObject(successCallback, forKeyedSubscript: "successCallback" as NSString)
|
|
198
|
+
context.jsContext.setObject(failureCallback, forKeyedSubscript: "failureCallback" as NSString)
|
|
199
|
+
|
|
200
|
+
guard let value = try context.execute(code: "setTimeout(() => { successCallback(); }, 2000)") else {
|
|
201
|
+
XCTFail("value is null")
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
XCTAssertGreaterThan(value.toInt32(), 0)
|
|
206
|
+
|
|
207
|
+
wait(for: [expectation], timeout: 2.5)
|
|
208
|
+
|
|
209
|
+
guard let value = try context.execute(code: "setTimeout(() => { failureCallback(); }, 4000)") else {
|
|
210
|
+
XCTFail("value is null")
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let timerId = value.toInt32()
|
|
215
|
+
|
|
216
|
+
_ = Timer.scheduledTimer(withTimeInterval: TimeInterval(4.5), repeats: false) {_ in
|
|
217
|
+
cancelExpectation.fulfill()
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
_ = try context.execute(code: "clearTimeout(\(timerId))")
|
|
221
|
+
|
|
222
|
+
wait(for: [cancelExpectation], timeout: 5)
|
|
223
|
+
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
func testIntervalAPI() throws {
|
|
227
|
+
let runner = Runner()
|
|
228
|
+
let context = try runner.createContext(name: "io.backgroundrunner.intervaltests")
|
|
229
|
+
|
|
230
|
+
var calls = 0
|
|
231
|
+
|
|
232
|
+
let expectation = XCTestExpectation(description: "Run callback set on timeout")
|
|
233
|
+
|
|
234
|
+
let timerCallback: @convention(block) () -> Void = {
|
|
235
|
+
calls += 1
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
context.jsContext.setObject(timerCallback, forKeyedSubscript: "timerCallback" as NSString)
|
|
239
|
+
|
|
240
|
+
guard let value = try context.execute(code: "setInterval(() => { timerCallback(); }, 2000)") else {
|
|
241
|
+
XCTFail("value is null")
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
let timerId = value.toInt32()
|
|
246
|
+
|
|
247
|
+
_ = Timer.scheduledTimer(withTimeInterval: TimeInterval(8), repeats: false) {_ in
|
|
248
|
+
do {
|
|
249
|
+
_ = try context.execute(code: "clearInterval(\(timerId))")
|
|
250
|
+
} catch {
|
|
251
|
+
XCTFail("\(error)")
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
_ = Timer.scheduledTimer(withTimeInterval: TimeInterval(11), repeats: false) {_ in
|
|
256
|
+
expectation.fulfill()
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
wait(for: [expectation], timeout: 12)
|
|
260
|
+
|
|
261
|
+
XCTAssertEqual(calls, 4)
|
|
262
|
+
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
func testTextEncoderAPI() throws {
|
|
266
|
+
let runner = Runner()
|
|
267
|
+
let context = try runner.createContext(name: "io.backgroundrunner.textencodertests")
|
|
268
|
+
|
|
269
|
+
guard let value = try context.execute(code: "const encoder = new TextEncoder(); encoder.encode('€');") else {
|
|
270
|
+
XCTFail("value is null")
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
XCTAssertTrue(value.isObject)
|
|
275
|
+
|
|
276
|
+
guard let arrayObject = value.toDictionary() as? [String: Int] else {
|
|
277
|
+
XCTFail("could not get array object")
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
XCTAssertEqual(226, arrayObject["0"])
|
|
281
|
+
XCTAssertEqual(130, arrayObject["1"])
|
|
282
|
+
XCTAssertEqual(172, arrayObject["2"])
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
func testTextDecoderAPI() throws {
|
|
286
|
+
let runner = Runner()
|
|
287
|
+
let context = try runner.createContext(name: "io.backgroundrunner.textdecodertests")
|
|
288
|
+
|
|
289
|
+
guard let value = try context.execute(code: "const win1251decoder = new TextDecoder(\"windows-1251\"); win1251decoder.decode(new Uint8Array([ 207, 240, 232, 226, 229, 242, 44, 32, 236, 232, 240, 33]));") else {
|
|
290
|
+
XCTFail("value is null")
|
|
291
|
+
return
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
XCTAssertTrue(value.isString)
|
|
295
|
+
XCTAssertEqual("Привет, мир!", value.toString())
|
|
296
|
+
|
|
297
|
+
guard let value = try context.execute(code: "const decoder = new TextDecoder(); decoder.decode(new Uint8Array([240, 160, 174, 183]));") else {
|
|
298
|
+
XCTFail("value is null")
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
XCTAssertTrue(value.isString)
|
|
303
|
+
XCTAssertEqual("𠮷", value.toString())
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
func testErrorHandling() throws {
|
|
307
|
+
let runner = Runner()
|
|
308
|
+
let context = try runner.createContext(name: "io.backgroundrunner.testexceptions")
|
|
309
|
+
|
|
310
|
+
XCTAssertThrowsError(try context.execute(code: "() => { throw new Error('this method has an error'); }();")) { error in
|
|
311
|
+
XCTAssertTrue(String(describing: error).contains("SyntaxError: Unexpected token"))
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
XCTAssertThrowsError(try context.execute(code: "addEventListener(")) { error in
|
|
315
|
+
XCTAssertTrue(String(describing: error).contains("SyntaxError: Unexpected end of script"))
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
_ = try context.execute(code: "addEventListener('myThrowingEvent', () => { throw new Error('this event throws an error') })")
|
|
319
|
+
|
|
320
|
+
XCTAssertThrowsError(try context.dispatchEvent(event: "myThrowingEvent")) { error in
|
|
321
|
+
XCTAssertTrue(String(describing: error).contains("this event throws an error"))
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
func testFetchAPI() throws {
|
|
326
|
+
let runner = Runner()
|
|
327
|
+
let context = try runner.createContext(name: "io.backgroundrunner.testfetch")
|
|
328
|
+
|
|
329
|
+
let expectation = XCTestExpectation(description: "Run callback on completed (or failed) fetch")
|
|
330
|
+
let optionsExpectation = XCTestExpectation(description: "Run callback on completed options fetch")
|
|
331
|
+
let failureExpectation = XCTestExpectation(description: "Run catch callback on failed fetch")
|
|
332
|
+
|
|
333
|
+
let successCallback: @convention(block) () -> Void = {
|
|
334
|
+
expectation.fulfill()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
let failureCallback: @convention(block) () -> Void = {
|
|
338
|
+
failureExpectation.fulfill()
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let optionsSuccessCallback: @convention(block) () -> Void = {
|
|
342
|
+
optionsExpectation.fulfill()
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
context.jsContext.setObject(successCallback, forKeyedSubscript: "successCallback" as NSString)
|
|
346
|
+
context.jsContext.setObject(optionsSuccessCallback, forKeyedSubscript: "successCallback2" as NSString)
|
|
347
|
+
context.jsContext.setObject(failureCallback, forKeyedSubscript: "failureCallback" as NSString)
|
|
348
|
+
|
|
349
|
+
let basicFetchExample = """
|
|
350
|
+
fetch('https://jsonplaceholder.typicode.com/todos/1')
|
|
351
|
+
.then(response => response.json())
|
|
352
|
+
.then(json => { console.log(JSON.stringify(json)); successCallback(); })
|
|
353
|
+
.catch(err => { console.error(err); successCallback(); });
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
_ = try context.execute(code: basicFetchExample)
|
|
357
|
+
|
|
358
|
+
wait(for: [expectation], timeout: 3)
|
|
359
|
+
|
|
360
|
+
let fetchFailureExample = """
|
|
361
|
+
fetch('https://blablabla.fake/todos/1')
|
|
362
|
+
.catch(err => { console.error(err); failureCallback(); });
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
_ = try context.execute(code: fetchFailureExample)
|
|
366
|
+
|
|
367
|
+
wait(for: [failureExpectation], timeout: 3)
|
|
368
|
+
|
|
369
|
+
let fetchWithOptionsExample = """
|
|
370
|
+
fetch('https://jsonplaceholder.typicode.com/posts', {
|
|
371
|
+
method: 'POST',
|
|
372
|
+
body: JSON.stringify({
|
|
373
|
+
title: 'foo',
|
|
374
|
+
body: 'bar',
|
|
375
|
+
userId: 1,
|
|
376
|
+
}),
|
|
377
|
+
headers: {
|
|
378
|
+
'Content-type': 'application/json; charset=UTF-8',
|
|
379
|
+
}
|
|
380
|
+
})
|
|
381
|
+
.catch(err => { console.error(err); })
|
|
382
|
+
.then(response => response.json())
|
|
383
|
+
.then(json => { console.log(JSON.stringify(json)); successCallback2(); })
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
_ = try context.execute(code: fetchWithOptionsExample)
|
|
387
|
+
|
|
388
|
+
wait(for: [optionsExpectation], timeout: 3)
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// swiftlint:enable all
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// swiftlint:disable all
|
|
2
|
+
import XCTest
|
|
3
|
+
@testable import RunnerEngine
|
|
4
|
+
|
|
5
|
+
final class RunnerTests: XCTestCase {
|
|
6
|
+
func testMultipleContexts() throws {
|
|
7
|
+
let runner = Runner()
|
|
8
|
+
|
|
9
|
+
var calls = 0
|
|
10
|
+
let count = Int.random(in: 20..<40)
|
|
11
|
+
|
|
12
|
+
let expectation = XCTestExpectation(description: "Run callback on completed timeout callbacks")
|
|
13
|
+
|
|
14
|
+
let timeoutCallback: @convention(block) () -> Void = {
|
|
15
|
+
calls += 1
|
|
16
|
+
|
|
17
|
+
if calls >= count {
|
|
18
|
+
expectation.fulfill()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for i in 1...count {
|
|
23
|
+
let context = try runner.createContext(name: "context #\(i)")
|
|
24
|
+
context.jsContext.setObject(timeoutCallback, forKeyedSubscript: "timeoutCallback" as NSString)
|
|
25
|
+
_ = try context.execute(code: "setTimeout(() => { timeoutCallback(); }, 2000)")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
wait(for: [expectation], timeout: 5)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
// swiftlint:enable all
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/background-runner",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Capacitor Background Runner",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"android/src/main/",
|
|
12
12
|
"android/build.gradle",
|
|
13
13
|
"dist/",
|
|
14
|
-
"ios/
|
|
14
|
+
"ios/Sources",
|
|
15
|
+
"ios/Tests",
|
|
16
|
+
"Package.swift",
|
|
15
17
|
"scripts/install_libs.js",
|
|
16
18
|
"CapacitorBackgroundRunner.podspec"
|
|
17
19
|
],
|
|
@@ -30,18 +32,18 @@
|
|
|
30
32
|
],
|
|
31
33
|
"scripts": {
|
|
32
34
|
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
33
|
-
"verify:ios": "
|
|
35
|
+
"verify:ios": "xcodebuild -scheme CapacitorBackgroundRunner -destination generic/platform=iOS && xcodebuild test -scheme CapacitorBackgroundRunner -destination 'platform=iOS Simulator,OS=18.6,name=iPhone 16 Pro'",
|
|
34
36
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
35
37
|
"verify:web": "npm run build",
|
|
36
38
|
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
37
39
|
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
38
40
|
"eslint": "eslint . --ext ts",
|
|
39
|
-
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
41
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
40
42
|
"swiftlint": "node-swiftlint",
|
|
41
43
|
"docgen": "docgen --api BackgroundRunnerPlugin --output-readme README.md --output-json dist/docs.json",
|
|
42
44
|
"docgen-api": "docgen --api CapacitorAPI --output-readme API.md --output-json dist/docs-api.json && node ./scripts/combine_docs.js",
|
|
43
45
|
"build-sdk": "./scripts/build-native-sdks.sh",
|
|
44
|
-
"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",
|
|
46
|
+
"build": "npm run clean && npm run docgen && npm run docgen-api && tsc && rollup -c rollup.config.js --bundleConfigAsCjs && npm run build-sdk && ./scripts/copy-native-sdks.sh && npm pack && mv ./capacitor-background-runner-*.tgz ../../ && ./scripts/copy-readme.sh",
|
|
45
47
|
"pack": "npm run build && ./scripts/copy-native-sdks.sh && npm pack && mv ./capacitor-background-runner-*.tgz ../../",
|
|
46
48
|
"clean": "rimraf ./dist",
|
|
47
49
|
"watch": "tsc --watch",
|
|
@@ -49,24 +51,24 @@
|
|
|
49
51
|
"postinstall": "node ./scripts/install_libs.js"
|
|
50
52
|
},
|
|
51
53
|
"devDependencies": {
|
|
52
|
-
"@capacitor/android": "^
|
|
53
|
-
"@capacitor/cli": "^
|
|
54
|
-
"@capacitor/core": "^
|
|
55
|
-
"@capacitor/docgen": "^0.
|
|
56
|
-
"@capacitor/ios": "^
|
|
57
|
-
"@ionic/eslint-config": "^0.
|
|
58
|
-
"@ionic/prettier-config": "^
|
|
59
|
-
"@ionic/swiftlint-config": "^
|
|
60
|
-
"eslint": "^
|
|
61
|
-
"prettier": "
|
|
62
|
-
"prettier-plugin-java": "
|
|
63
|
-
"rimraf": "^
|
|
64
|
-
"rollup": "^
|
|
65
|
-
"swiftlint": "^
|
|
66
|
-
"typescript": "^5.
|
|
54
|
+
"@capacitor/android": "^8.0.0",
|
|
55
|
+
"@capacitor/cli": "^8.0.0",
|
|
56
|
+
"@capacitor/core": "^8.0.0",
|
|
57
|
+
"@capacitor/docgen": "^0.3.0",
|
|
58
|
+
"@capacitor/ios": "^8.0.0",
|
|
59
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
60
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
61
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
62
|
+
"eslint": "^8.57.1",
|
|
63
|
+
"prettier": "^3.6.2",
|
|
64
|
+
"prettier-plugin-java": "^2.7.7",
|
|
65
|
+
"rimraf": "^6.1.2",
|
|
66
|
+
"rollup": "^4.53.3",
|
|
67
|
+
"swiftlint": "^2.0.0",
|
|
68
|
+
"typescript": "^5.9.3"
|
|
67
69
|
},
|
|
68
70
|
"peerDependencies": {
|
|
69
|
-
"@capacitor/core": "
|
|
71
|
+
"@capacitor/core": ">=8.0.0"
|
|
70
72
|
},
|
|
71
73
|
"prettier": "@ionic/prettier-config",
|
|
72
74
|
"swiftlint": "@ionic/swiftlint-config",
|
|
@@ -81,5 +83,5 @@
|
|
|
81
83
|
"src": "android"
|
|
82
84
|
}
|
|
83
85
|
},
|
|
84
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "4559cf862ec7575f579a3bc38257efebe552daaf"
|
|
85
87
|
}
|
package/scripts/install_libs.js
CHANGED
|
@@ -22,10 +22,8 @@ if (!fs.existsSync(androidGradlePath)) {
|
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const searchText =
|
|
26
|
-
|
|
27
|
-
const insertText =
|
|
28
|
-
"\n\t\tdirs '../../node_modules/@capacitor/background-runner/android/src/main/libs', 'libs'";
|
|
25
|
+
const searchText = "dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'";
|
|
26
|
+
const insertText = "\n\t\tdirs '../../node_modules/@capacitor/background-runner/android/src/main/libs', 'libs'";
|
|
29
27
|
|
|
30
28
|
let gradleFile = fs.readFileSync(androidGradlePath).toString('utf-8');
|
|
31
29
|
if (gradleFile.indexOf(insertText) != -1) {
|
|
@@ -33,18 +31,12 @@ if (gradleFile.indexOf(insertText) != -1) {
|
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
let insertIndex = gradleFile.indexOf(searchText) + searchText.length;
|
|
36
|
-
gradleFile =
|
|
37
|
-
gradleFile.substring(0, insertIndex) +
|
|
38
|
-
insertText +
|
|
39
|
-
gradleFile.substring(insertIndex);
|
|
34
|
+
gradleFile = gradleFile.substring(0, insertIndex) + insertText + gradleFile.substring(insertIndex);
|
|
40
35
|
|
|
41
36
|
fs.writeFileSync(androidGradlePath, gradleFile);
|
|
42
37
|
|
|
43
38
|
// remove old version of aar
|
|
44
|
-
const oldReleaseAARPath = path.join(
|
|
45
|
-
workingDir,
|
|
46
|
-
'android/src/main/libs/android-js-engine-release.aar',
|
|
47
|
-
);
|
|
39
|
+
const oldReleaseAARPath = path.join(workingDir, 'android/src/main/libs/android-js-engine-release.aar');
|
|
48
40
|
if (fs.existsSync(oldReleaseAARPath)) {
|
|
49
41
|
fs.rmSync(oldReleaseAARPath);
|
|
50
42
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#import <UIKit/UIKit.h>
|
|
2
|
-
|
|
3
|
-
//! Project version number for Plugin.
|
|
4
|
-
FOUNDATION_EXPORT double PluginVersionNumber;
|
|
5
|
-
|
|
6
|
-
//! Project version string for Plugin.
|
|
7
|
-
FOUNDATION_EXPORT const unsigned char PluginVersionString[];
|
|
8
|
-
|
|
9
|
-
// In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
|
|
10
|
-
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#import <Foundation/Foundation.h>
|
|
2
|
-
#import <Capacitor/Capacitor.h>
|
|
3
|
-
|
|
4
|
-
// Define the plugin using the CAP_PLUGIN Macro, and
|
|
5
|
-
// each method the plugin supports using the CAP_PLUGIN_METHOD macro.
|
|
6
|
-
CAP_PLUGIN(BackgroundRunnerPlugin, "BackgroundRunner",
|
|
7
|
-
CAP_PLUGIN_METHOD(dispatchEvent, CAPPluginReturnPromise);
|
|
8
|
-
CAP_PLUGIN_METHOD(registerBackgroundTask, CAPPluginReturnPromise);
|
|
9
|
-
CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise);
|
|
10
|
-
CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise);
|
|
11
|
-
CAP_PLUGIN_METHOD(removeNotificationListeners, CAPPluginReturnPromise);
|
|
12
|
-
)
|