capacitor-mobilecron 0.2.4 → 0.2.6
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.
|
@@ -22,8 +22,6 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
22
22
|
CAPPluginMethod(name: "testGetPendingCount", returnType: CAPPluginReturnPromise)
|
|
23
23
|
]
|
|
24
24
|
|
|
25
|
-
private static let storageKey = "mobilecron:state"
|
|
26
|
-
|
|
27
25
|
private var jobs: [String: [String: Any]] = [:]
|
|
28
26
|
private var paused = false
|
|
29
27
|
private(set) var mode = "balanced"
|
|
@@ -60,9 +58,11 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
// ── Persistence ───────────────────────────────────────────────────────────
|
|
61
|
+
// Uses NativeJobEvaluator.readStateRaw() / writeStateRaw() for file-backed
|
|
62
|
+
// atomic writes that survive simctl terminate (SIGKILL) reliably.
|
|
63
63
|
|
|
64
64
|
private func loadState() {
|
|
65
|
-
guard let raw =
|
|
65
|
+
guard let raw = NativeJobEvaluator.readStateRaw(),
|
|
66
66
|
let data = raw.data(using: .utf8),
|
|
67
67
|
let state = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
|
|
68
68
|
return
|
|
@@ -87,7 +87,7 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
87
87
|
"jobs": Array(jobs.values)
|
|
88
88
|
]
|
|
89
89
|
// Preserve any pendingNativeEvents written by NativeJobEvaluator
|
|
90
|
-
if let raw =
|
|
90
|
+
if let raw = NativeJobEvaluator.readStateRaw(),
|
|
91
91
|
let data = raw.data(using: .utf8),
|
|
92
92
|
let existing = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any],
|
|
93
93
|
let pending = existing["pendingNativeEvents"] as? [[String: Any]],
|
|
@@ -96,16 +96,14 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
96
96
|
}
|
|
97
97
|
guard let data = try? JSONSerialization.data(withJSONObject: state),
|
|
98
98
|
let raw = String(data: data, encoding: .utf8) else { return }
|
|
99
|
-
|
|
100
|
-
// Force immediate disk flush so state survives simctl terminate / force-kill
|
|
101
|
-
UserDefaults.standard.synchronize()
|
|
99
|
+
NativeJobEvaluator.writeStateRaw(raw)
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
// ── Background wake ───────────────────────────────────────────────────────
|
|
105
103
|
|
|
106
104
|
/// Read pendingNativeEvents from storage, emit each as jobDue, then clear them.
|
|
107
105
|
private func firePendingNativeEvents() {
|
|
108
|
-
guard let raw =
|
|
106
|
+
guard let raw = NativeJobEvaluator.readStateRaw(),
|
|
109
107
|
let data = raw.data(using: .utf8),
|
|
110
108
|
var state = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
|
|
111
109
|
return
|
|
@@ -133,8 +131,7 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
133
131
|
state["jobs"] = Array(jobs.values)
|
|
134
132
|
if let newData = try? JSONSerialization.data(withJSONObject: state),
|
|
135
133
|
let newRaw = String(data: newData, encoding: .utf8) {
|
|
136
|
-
|
|
137
|
-
UserDefaults.standard.synchronize()
|
|
134
|
+
NativeJobEvaluator.writeStateRaw(newRaw)
|
|
138
135
|
}
|
|
139
136
|
}
|
|
140
137
|
|
|
@@ -270,8 +267,7 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
270
267
|
call.resolve(["firedCount": events.count])
|
|
271
268
|
}
|
|
272
269
|
|
|
273
|
-
/// Sets a job's nextDueAt in memory and saves to
|
|
274
|
-
/// Allows tests to mark a job as "due" without waiting for real time to pass.
|
|
270
|
+
/// Sets a job's nextDueAt in memory and saves to storage.
|
|
275
271
|
@objc func testSetNextDueAt(_ call: CAPPluginCall) {
|
|
276
272
|
guard let id = call.getString("id"),
|
|
277
273
|
let nextDueAtMs = call.getInt("nextDueAtMs"),
|
|
@@ -284,17 +280,16 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
284
280
|
call.resolve()
|
|
285
281
|
}
|
|
286
282
|
|
|
287
|
-
/// Appends a pending native event to
|
|
288
|
-
/// Allows tests to simulate what NativeJobEvaluator writes during background execution.
|
|
283
|
+
/// Appends a pending native event to storage.
|
|
289
284
|
@objc func testInjectPendingEvent(_ call: CAPPluginCall) {
|
|
290
285
|
guard let event = call.getObject("event") else {
|
|
291
286
|
call.reject("event is required")
|
|
292
287
|
return
|
|
293
288
|
}
|
|
294
|
-
guard let raw =
|
|
289
|
+
guard let raw = NativeJobEvaluator.readStateRaw(),
|
|
295
290
|
let data = raw.data(using: .utf8),
|
|
296
291
|
var state = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
|
|
297
|
-
call.reject("State not found in
|
|
292
|
+
call.reject("State not found in storage")
|
|
298
293
|
return
|
|
299
294
|
}
|
|
300
295
|
var pending = (state["pendingNativeEvents"] as? [[String: Any]]) ?? []
|
|
@@ -305,14 +300,13 @@ public class MobileCronPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
305
300
|
call.reject("Serialization failed")
|
|
306
301
|
return
|
|
307
302
|
}
|
|
308
|
-
|
|
309
|
-
UserDefaults.standard.synchronize()
|
|
303
|
+
NativeJobEvaluator.writeStateRaw(newRaw)
|
|
310
304
|
call.resolve()
|
|
311
305
|
}
|
|
312
306
|
|
|
313
|
-
/// Returns the count of pendingNativeEvents currently in
|
|
307
|
+
/// Returns the count of pendingNativeEvents currently in storage.
|
|
314
308
|
@objc func testGetPendingCount(_ call: CAPPluginCall) {
|
|
315
|
-
guard let raw =
|
|
309
|
+
guard let raw = NativeJobEvaluator.readStateRaw(),
|
|
316
310
|
let data = raw.data(using: .utf8),
|
|
317
311
|
let state = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
|
|
318
312
|
call.resolve(["count": 0])
|
|
@@ -12,8 +12,41 @@ final class NativeJobEvaluator {
|
|
|
12
12
|
private static let storageKey = "mobilecron:state"
|
|
13
13
|
private static let clockRegex = try? NSRegularExpression(pattern: #"^(\d{2}):(\d{2})$"#)
|
|
14
14
|
|
|
15
|
+
// ── Shared I/O ─────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/// JSON file in Application Support — survives simctl terminate (synchronous atomic write).
|
|
18
|
+
static var stateFileURL: URL? {
|
|
19
|
+
guard let dir = try? FileManager.default.url(
|
|
20
|
+
for: .applicationSupportDirectory,
|
|
21
|
+
in: .userDomainMask,
|
|
22
|
+
appropriateFor: nil,
|
|
23
|
+
create: true
|
|
24
|
+
) else { return nil }
|
|
25
|
+
return dir.appendingPathComponent("mobilecron-state.json")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Reads raw JSON: file preferred (reliable); UserDefaults as fallback.
|
|
29
|
+
static func readStateRaw() -> String? {
|
|
30
|
+
if let url = stateFileURL,
|
|
31
|
+
let raw = try? String(contentsOf: url, encoding: .utf8),
|
|
32
|
+
!raw.isEmpty {
|
|
33
|
+
return raw
|
|
34
|
+
}
|
|
35
|
+
return UserDefaults.standard.string(forKey: storageKey)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Writes raw JSON atomically to file AND to UserDefaults (belt-and-suspenders).
|
|
39
|
+
static func writeStateRaw(_ raw: String) {
|
|
40
|
+
if let url = stateFileURL {
|
|
41
|
+
try? raw.write(to: url, atomically: true, encoding: .utf8)
|
|
42
|
+
}
|
|
43
|
+
UserDefaults.standard.set(raw, forKey: storageKey)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── Evaluation ─────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
15
48
|
static func evaluate(source: String) -> [NativeJobEvent] {
|
|
16
|
-
guard let raw =
|
|
49
|
+
guard let raw = readStateRaw(),
|
|
17
50
|
let data = raw.data(using: .utf8),
|
|
18
51
|
var state = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
|
|
19
52
|
return []
|
|
@@ -101,8 +134,8 @@ final class NativeJobEvaluator {
|
|
|
101
134
|
}
|
|
102
135
|
|
|
103
136
|
if let nextData = try? JSONSerialization.data(withJSONObject: state),
|
|
104
|
-
let nextRaw = String(
|
|
105
|
-
|
|
137
|
+
let nextRaw = String(nextData, encoding: .utf8) {
|
|
138
|
+
writeStateRaw(nextRaw)
|
|
106
139
|
}
|
|
107
140
|
}
|
|
108
141
|
|
package/package.json
CHANGED