@capgo/capacitor-updater 4.2.7 → 4.3.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.
@@ -11,8 +11,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
11
11
  private var implementation = CapacitorUpdater()
12
12
  static let updateUrlDefault = "https://api.capgo.app/updates"
13
13
  static let statsUrlDefault = "https://api.capgo.app/stats"
14
- let DELAY_UPDATE = "delayUpdate"
15
- let DELAY_UPDATE_VAL = "delayUpdateVal"
14
+ let DELAY_CONDITION_PREFERENCES = ""
16
15
  private var updateUrl = ""
17
16
  private var statsUrl = ""
18
17
  private var currentVersionNative: Version = "0.0.0"
@@ -22,6 +21,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
22
21
  private var resetWhenUpdate = true
23
22
  private var autoDeleteFailed = false
24
23
  private var autoDeletePrevious = false
24
+ private var backgroundWork: DispatchWorkItem?
25
+ private var taskRunning = false
25
26
 
26
27
  override public func load() {
27
28
  print("\(self.implementation.TAG) init for device \(self.implementation.deviceID)")
@@ -120,6 +121,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
120
121
  if let vc = bridge.viewController as? CAPBridgeViewController {
121
122
  vc.setServerBasePath(path: destHot.path)
122
123
  self.checkAppReady()
124
+ self.notifyListeners("appReloaded", data: [:])
123
125
  return true
124
126
  }
125
127
  return false
@@ -241,24 +243,47 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
241
243
  call.resolve()
242
244
  }
243
245
 
244
- @objc func setDelay(_ call: CAPPluginCall) {
245
- guard let kind = call.getString("kind") else {
246
- print("\(self.implementation.TAG) setDelay called without kind")
247
- call.reject("setDelay called without kind")
246
+ @objc func setMultiDelay(_ call: CAPPluginCall) {
247
+ guard let delayConditionList = call.getValue("delayConditions") else {
248
+ print("\(self.implementation.TAG) setMultiDelay called without delayCondition")
249
+ call.reject("setMultiDelay called without delayCondition")
248
250
  return
249
251
  }
250
- let val = call.getString("value") ?? ""
251
- UserDefaults.standard.set(kind, forKey: DELAY_UPDATE)
252
- UserDefaults.standard.set(val, forKey: DELAY_UPDATE_VAL)
253
- UserDefaults.standard.synchronize()
254
- print("\(self.implementation.TAG) Delay update saved.", kind, val)
255
- call.resolve()
252
+ let delayConditions: String = toJson(object: delayConditionList)
253
+ if _setMultiDelay(delayConditions: delayConditions) {
254
+ call.resolve()
255
+ } else {
256
+ call.reject("Failed to delay update")
257
+ }
258
+ }
259
+
260
+ @available(*, deprecated, message: "use SetMultiDelay instead")
261
+ @objc func setDelay(_ call: CAPPluginCall) {
262
+ let kind: String = call.getString("kind", "")
263
+ let value: String? = call.getString("value", "")
264
+ let delayConditions: String = "[{\"kind\":\"\(kind)\", \"value\":\"\(value ?? "")\"}]"
265
+ if _setMultiDelay(delayConditions: delayConditions) {
266
+ call.resolve()
267
+ } else {
268
+ call.reject("Failed to delay update")
269
+ }
270
+ }
271
+
272
+ private func _setMultiDelay(delayConditions: String?) -> Bool {
273
+ if delayConditions != nil && "" != delayConditions {
274
+ UserDefaults.standard.set(delayConditions, forKey: DELAY_CONDITION_PREFERENCES)
275
+ UserDefaults.standard.synchronize()
276
+ print("\(self.implementation.TAG) Delay update saved.")
277
+ return true
278
+ } else {
279
+ print("\(self.implementation.TAG) Failed to delay update, [Error calling '_setMultiDelay()']")
280
+ return false
281
+ }
256
282
  }
257
283
 
258
284
  private func _cancelDelay(source: String) {
259
285
  print("\(self.implementation.TAG) delay Canceled from \(source)")
260
- UserDefaults.standard.removeObject(forKey: DELAY_UPDATE)
261
- UserDefaults.standard.removeObject(forKey: DELAY_UPDATE_VAL)
286
+ UserDefaults.standard.removeObject(forKey: DELAY_CONDITION_PREFERENCES)
262
287
  UserDefaults.standard.synchronize()
263
288
  }
264
289
 
@@ -268,39 +293,65 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
268
293
  }
269
294
 
270
295
  private func _checkCancelDelay(killed: Bool) {
271
- let delayUpdate = UserDefaults.standard.string(forKey: DELAY_UPDATE)
272
- if delayUpdate != nil {
273
- if delayUpdate == "background" && !killed {
274
- self._cancelDelay(source: "background check")
275
- } else if delayUpdate == "kill" && killed {
276
- self._cancelDelay(source: "kill check")
277
- }
278
- guard let delayVal = UserDefaults.standard.string(forKey: DELAY_UPDATE_VAL) else {
279
- self._cancelDelay(source: "delayVal absent")
280
- return
281
- }
282
- if delayUpdate == "date" {
283
- let dateFormatter = ISO8601DateFormatter()
284
- guard let ExpireDate = dateFormatter.date(from: delayVal) else {
285
- self._cancelDelay(source: "date parsing issue")
286
- return
287
- }
288
- if ExpireDate < Date() {
289
- self._cancelDelay(source: "date expired")
290
- }
291
- } else if delayUpdate == "nativeVersion" {
292
- do {
293
- let versionLimit = try Version(delayVal)
294
- if self.currentVersionNative >= versionLimit {
295
- self._cancelDelay(source: "nativeVersion above limit")
296
+ let delayUpdatePreferences = UserDefaults.standard.string(forKey: DELAY_CONDITION_PREFERENCES) ?? "[]"
297
+ let delayConditionList: [DelayCondition] = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
298
+ let kind: String = obj.value(forKey: "kind") as! String
299
+ let value: String? = obj.value(forKey: "value") as? String
300
+ return DelayCondition(kind: kind, value: value)
301
+ }
302
+ for condition in delayConditionList {
303
+ let kind: String? = condition.getKind()
304
+ let value: String? = condition.getValue()
305
+ if kind != nil {
306
+ switch kind {
307
+ case "background":
308
+ if !killed {
309
+ self._cancelDelay(source: "background check")
310
+ }
311
+ break
312
+ case "kill":
313
+ if killed {
314
+ self._cancelDelay(source: "kill check")
315
+ // instant install for kill action
316
+ self.installNext()
296
317
  }
297
- } catch {
298
- self._cancelDelay(source: "nativeVersion parsing issue")
318
+ break
319
+ case "date":
320
+ if value != nil && value != "" {
321
+ let dateFormatter = ISO8601DateFormatter()
322
+ guard let ExpireDate = dateFormatter.date(from: value!) else {
323
+ self._cancelDelay(source: "date parsing issue")
324
+ return
325
+ }
326
+ if ExpireDate < Date() {
327
+ self._cancelDelay(source: "date expired")
328
+ }
329
+ } else {
330
+ self._cancelDelay(source: "delayVal absent")
331
+ }
332
+ break
333
+ case "nativeVersion":
334
+ if value != nil && value != "" {
335
+ do {
336
+ let versionLimit = try Version(value!)
337
+ if self.currentVersionNative >= versionLimit {
338
+ self._cancelDelay(source: "nativeVersion above limit")
339
+ }
340
+ } catch {
341
+ self._cancelDelay(source: "nativeVersion parsing issue")
342
+ }
343
+ } else {
344
+ self._cancelDelay(source: "delayVal absent")
345
+ }
346
+ break
347
+ case .none:
348
+ print("\(self.implementation.TAG) _checkCancelDelay switch case none error")
349
+ case .some:
350
+ print("\(self.implementation.TAG) _checkCancelDelay switch case some error")
299
351
  }
300
352
  }
301
353
  }
302
-
303
- self.checkAppReady()
354
+ // self.checkAppReady() why this here?
304
355
  }
305
356
 
306
357
  private func _isAutoUpdateEnabled() -> Bool {
@@ -361,6 +412,10 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
361
412
  }
362
413
 
363
414
  @objc func appMovedToForeground() {
415
+ if backgroundWork != nil && taskRunning {
416
+ backgroundWork!.cancel()
417
+ print("\(self.implementation.TAG) Background Timer Task canceled, Activity resumed before timer completes")
418
+ }
364
419
  if self._isAutoUpdateEnabled() {
365
420
  DispatchQueue.global(qos: .background).async {
366
421
  print("\(self.implementation.TAG) Check for update via \(self.updateUrl)")
@@ -420,13 +475,49 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
420
475
 
421
476
  @objc func appMovedToBackground() {
422
477
  print("\(self.implementation.TAG) Check for pending update")
423
- let delayUpdate = UserDefaults.standard.string(forKey: DELAY_UPDATE)
424
- self._checkCancelDelay(killed: false)
425
- if delayUpdate != nil {
478
+ let delayUpdatePreferences = UserDefaults.standard.string(forKey: DELAY_CONDITION_PREFERENCES) ?? "[]"
479
+
480
+ let delayConditionList: [DelayCondition] = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
481
+ let kind: String = obj.value(forKey: "kind") as! String
482
+ let value: String? = obj.value(forKey: "value") as? String
483
+ return DelayCondition(kind: kind, value: value)
484
+ }
485
+ var backgroundValue: String?
486
+ for delayCondition in delayConditionList {
487
+ if delayCondition.getKind() == "background" {
488
+ let value: String? = delayCondition.getValue()
489
+ backgroundValue = (value != nil && value != "") ? value! : "0"
490
+ }
491
+ }
492
+ if backgroundValue != nil {
493
+ self.taskRunning = true
494
+ let interval: Double = (Double(backgroundValue!) ?? 0.0) / 1000
495
+ self.backgroundWork?.cancel()
496
+ self.backgroundWork = DispatchWorkItem(block: {
497
+ // IOS never executes this task in background
498
+ self.taskRunning = false
499
+ self._checkCancelDelay(killed: false)
500
+ self.installNext()
501
+ })
502
+ DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + interval, execute: self.backgroundWork!)
503
+ } else {
504
+ self._checkCancelDelay(killed: false)
505
+ self.installNext()
506
+ }
507
+
508
+ }
509
+
510
+ private func installNext() {
511
+ let delayUpdatePreferences = UserDefaults.standard.string(forKey: DELAY_CONDITION_PREFERENCES) ?? "[]"
512
+ let delayConditionList: [DelayCondition]? = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
513
+ let kind: String = obj.value(forKey: "kind") as! String
514
+ let value: String? = obj.value(forKey: "value") as? String
515
+ return DelayCondition(kind: kind, value: value)
516
+ }
517
+ if delayConditionList != nil && delayConditionList?.capacity != 0 {
426
518
  print("\(self.implementation.TAG) Update delayed to next backgrounding")
427
519
  return
428
520
  }
429
-
430
521
  let current: BundleInfo = self.implementation.getCurrentBundle()
431
522
  let next: BundleInfo? = self.implementation.getNextBundle()
432
523
 
@@ -440,4 +531,20 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
440
531
  }
441
532
  }
442
533
  }
534
+
535
+ @objc private func toJson(object: Any) -> String {
536
+ guard let data = try? JSONSerialization.data(withJSONObject: object, options: []) else {
537
+ return ""
538
+ }
539
+ return String(data: data, encoding: String.Encoding.utf8) ?? ""
540
+ }
541
+
542
+ @objc private func fromJsonArr(json: String) -> [NSObject] {
543
+ let jsonData = json.data(using: .utf8)!
544
+ let object = try? JSONSerialization.jsonObject(
545
+ with: jsonData,
546
+ options: .mutableContainers
547
+ ) as? [NSObject]
548
+ return object ?? []
549
+ }
443
550
  }
@@ -0,0 +1,68 @@
1
+ //
2
+ // DelayCondition.swift
3
+ // Plugin
4
+ //
5
+ // Created by Luca Peruzzo on 12/09/22.
6
+ // Copyright © 2022 Capgo. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ private func delayUntilNextValue(value: String) -> DelayUntilNext {
12
+ switch value {
13
+ case "background": return .background
14
+ case "kill": return .kill
15
+ case "nativeVersion": return .nativeVersion
16
+ case "date": return .date
17
+ default:
18
+ return .background
19
+ }
20
+ }
21
+
22
+ @objc public class DelayCondition: NSObject, Decodable, Encodable {
23
+ private let kind: DelayUntilNext
24
+ private let value: String?
25
+
26
+ convenience init(kind: String, value: String?) {
27
+ self.init(kind: delayUntilNextValue(value: kind), value: value)
28
+ }
29
+
30
+ init(kind: DelayUntilNext, value: String?) {
31
+ self.kind = kind
32
+ self.value = value
33
+ }
34
+
35
+ public required init(from decoder: Decoder) throws {
36
+ let values = try decoder.container(keyedBy: CodingKeys.self)
37
+ kind = try values.decode(DelayUntilNext.self, forKey: .kind)
38
+ value = try values.decode(String.self, forKey: .value)
39
+ }
40
+
41
+ enum CodingKeys: String, CodingKey {
42
+ case kind, value
43
+ }
44
+
45
+ public func getKind() -> String {
46
+ return self.kind.description
47
+ }
48
+
49
+ public func getValue() -> String? {
50
+ return self.value
51
+ }
52
+
53
+ public func toJSON() -> [String: String] {
54
+ return [
55
+ "kind": self.getKind(),
56
+ "value": self.getValue() ?? ""
57
+ ]
58
+ }
59
+
60
+ public static func == (lhs: DelayCondition, rhs: DelayCondition) -> Bool {
61
+ return lhs.getKind() == rhs.getKind() && lhs.getValue() == rhs.getValue()
62
+ }
63
+
64
+ public func toString() -> String {
65
+ return "{ \"kind\": \"\(self.getKind())\", \"value\": \"\(self.getValue() ?? "")\"}"
66
+ }
67
+
68
+ }
@@ -0,0 +1,24 @@
1
+ //
2
+ // DelayUntilNext.swift
3
+ // Plugin
4
+ //
5
+ // Created by Luca Peruzzo on 12/09/22.
6
+ // Copyright © 2022 Capgo. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+ enum DelayUntilNext: Decodable, Encodable, CustomStringConvertible {
11
+ case background
12
+ case kill
13
+ case nativeVersion
14
+ case date
15
+
16
+ var description: String {
17
+ switch self {
18
+ case .background: return "background"
19
+ case .kill: return "kill"
20
+ case .nativeVersion: return "nativeVersion"
21
+ case .date: return "date"
22
+ }
23
+ }
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "4.2.7",
3
+ "version": "4.3.0",
4
4
  "license": "LGPL-3.0-only",
5
5
  "description": "OTA update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",