@capawesome/capacitor-live-update 7.3.0 → 7.4.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.
Files changed (30) hide show
  1. package/README.md +216 -0
  2. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +519 -246
  3. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdateHttpClient.java +33 -5
  4. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +134 -3
  5. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePreferences.java +25 -0
  6. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/api/GetLatestBundleResponse.java +2 -2
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/options/SetConfigOptions.java +19 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/GetBlockedBundlesResult.java +27 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/GetConfigResult.java +40 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/GetDownloadedBundlesResult.java +27 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/IsSyncingResult.java +26 -0
  12. package/dist/docs.json +319 -0
  13. package/dist/esm/definitions.d.ts +165 -0
  14. package/dist/esm/definitions.js.map +1 -1
  15. package/dist/esm/web.d.ts +8 -1
  16. package/dist/esm/web.js +21 -0
  17. package/dist/esm/web.js.map +1 -1
  18. package/dist/plugin.cjs.js +21 -0
  19. package/dist/plugin.cjs.js.map +1 -1
  20. package/dist/plugin.js +21 -0
  21. package/dist/plugin.js.map +1 -1
  22. package/ios/Plugin/Classes/Options/SetConfigOptions.swift +14 -0
  23. package/ios/Plugin/Classes/Results/GetBlockedBundlesResult.swift +16 -0
  24. package/ios/Plugin/Classes/Results/GetConfigResult.swift +19 -0
  25. package/ios/Plugin/Classes/Results/GetDownloadedBundlesResult.swift +16 -0
  26. package/ios/Plugin/Classes/Results/IsSyncingResult.swift +16 -0
  27. package/ios/Plugin/LiveUpdate.swift +77 -4
  28. package/ios/Plugin/LiveUpdatePlugin.swift +78 -1
  29. package/ios/Plugin/LiveUpdatePreferences.swift +44 -2
  30. package/package.json +1 -1
@@ -35,11 +35,18 @@ import CommonCrypto
35
35
  self.preferences = LiveUpdatePreferences()
36
36
  super.init()
37
37
 
38
+ // Check version and reset config if version changed
39
+ checkAndResetConfigIfVersionChanged()
40
+
38
41
  // Start the rollback timer to rollback to the default bundle
39
42
  // if the app is not ready after a certain time
40
43
  startRollbackTimer()
41
44
  }
42
45
 
46
+ @objc public func clearBlockedBundles() {
47
+ preferences.setBlockedBundleIds(nil)
48
+ }
49
+
43
50
  @objc public func deleteBundle(_ options: DeleteBundleOptions, completion: @escaping (Error?) -> Void) {
44
51
  let bundleId = options.getBundleId()
45
52
 
@@ -82,18 +89,40 @@ import CommonCrypto
82
89
  return FetchLatestBundleResult(artifactType: response?.artifactType, bundleId: response?.bundleId, checksum: response?.checksum, customProperties: response?.customProperties, downloadUrl: response?.url, signature: response?.signature)
83
90
  }
84
91
 
92
+ @objc public func getBlockedBundles(completion: @escaping (Result?, Error?) -> Void) {
93
+ var bundleIds: [String] = []
94
+ if let blockedIds = preferences.getBlockedBundleIds(), !blockedIds.isEmpty {
95
+ bundleIds = blockedIds.split(separator: ",").map(String.init)
96
+ }
97
+ let result = GetBlockedBundlesResult(bundleIds: bundleIds)
98
+ completion(result, nil)
99
+ }
100
+
85
101
  @objc public func getBundles(completion: @escaping (Result?, Error?) -> Void) {
86
- let bundleIds = getBundleIds()
102
+ let bundleIds = getDownloadedBundleIds()
87
103
  let result = GetBundlesResult(bundleIds: bundleIds)
88
104
  completion(result, nil)
89
105
  }
90
106
 
107
+ @objc public func getDownloadedBundles(completion: @escaping (Result?, Error?) -> Void) {
108
+ let bundleIds = getDownloadedBundleIds()
109
+ let result = GetDownloadedBundlesResult(bundleIds: bundleIds)
110
+ completion(result, nil)
111
+ }
112
+
91
113
  @objc public func getChannel(completion: @escaping (Result?, Error?) -> Void) {
92
114
  let channel = getChannel()
93
115
  let result = GetChannelResult(channel: channel)
94
116
  completion(result, nil)
95
117
  }
96
118
 
119
+ @objc public func getConfig(completion: @escaping (Result?, Error?) -> Void) {
120
+ let appId = getAppId()
121
+ let autoUpdateStrategy = config.autoUpdateStrategy
122
+ let result = GetConfigResult(appId: appId, autoUpdateStrategy: autoUpdateStrategy)
123
+ completion(result, nil)
124
+ }
125
+
97
126
  @objc public func getCurrentBundle(completion: @escaping (Result?, Error?) -> Void) {
98
127
  let bundleId = getCurrentBundleId()
99
128
  let result = GetCurrentBundleResult(bundleId: bundleId)
@@ -131,6 +160,11 @@ import CommonCrypto
131
160
  completion(result, nil)
132
161
  }
133
162
 
163
+ @objc public func isSyncing(completion: @escaping (Result?, Error?) -> Void) {
164
+ let result = IsSyncingResult(syncing: syncInProgress)
165
+ completion(result, nil)
166
+ }
167
+
134
168
  @objc public func handleLoad() {
135
169
  if config.autoUpdateStrategy == "background" {
136
170
  performAutoUpdate()
@@ -180,6 +214,10 @@ import CommonCrypto
180
214
  self.setNextBundleById(nil)
181
215
  }
182
216
 
217
+ @objc public func resetConfig() {
218
+ preferences.setAppId(nil)
219
+ }
220
+
183
221
  @objc public func setChannel(_ options: SetChannelOptions, completion: @escaping (Error?) -> Void) {
184
222
  let channel = options.getChannel()
185
223
 
@@ -187,6 +225,11 @@ import CommonCrypto
187
225
  completion(nil)
188
226
  }
189
227
 
228
+ @objc public func setConfig(_ options: SetConfigOptions) {
229
+ let appId = options.getAppId()
230
+ preferences.setAppId(appId)
231
+ }
232
+
190
233
  @objc public func setCustomId(_ options: SetCustomIdOptions, completion: @escaping (Error?) -> Void) {
191
234
  let customId = options.getCustomId()
192
235
 
@@ -371,7 +414,7 @@ import CommonCrypto
371
414
  }
372
415
 
373
416
  private func deleteUnusedBundles() {
374
- let bundleIds = getBundleIds()
417
+ let bundleIds = getDownloadedBundleIds()
375
418
  let currentBundleId = getCurrentBundleId()
376
419
  let nextBundleId = getNextBundleId()
377
420
 
@@ -516,7 +559,7 @@ import CommonCrypto
516
559
  parameters["osVersion"] = await UIDevice.current.systemVersion
517
560
  parameters["platform"] = "1"
518
561
  parameters["pluginVersion"] = LiveUpdatePlugin.version
519
- var urlComponents = URLComponents(string: "https://\(config.serverDomain)/v1/apps/\(config.appId ?? "")/bundles/latest")!
562
+ var urlComponents = URLComponents(string: "https://\(config.serverDomain)/v1/apps/\(getAppId() ?? "")/bundles/latest")!
520
563
  urlComponents.queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) }
521
564
  let url = try urlComponents.asURL()
522
565
  CAPLog.print("[", LiveUpdatePlugin.tag, "] Fetching latest bundle: ", url)
@@ -539,7 +582,7 @@ import CommonCrypto
539
582
  }
540
583
  }
541
584
 
542
- private func getBundleIds() -> [String] {
585
+ private func getDownloadedBundleIds() -> [String] {
543
586
  let url = libraryDirectoryUrl.appendingPathComponent(bundlesDirectory)
544
587
  do {
545
588
  let pathExists = FileManager.default.fileExists(atPath: url.path)
@@ -553,6 +596,13 @@ import CommonCrypto
553
596
  }
554
597
  }
555
598
 
599
+ private func getAppId() -> String? {
600
+ if let appId = preferences.getAppId() {
601
+ return appId
602
+ }
603
+ return config.appId
604
+ }
605
+
556
606
  private func getChannel() -> String? {
557
607
  var channel: String?
558
608
  if let _ = config.defaultChannel {
@@ -755,6 +805,8 @@ import CommonCrypto
755
805
  return
756
806
  }
757
807
  viewController.setServerBasePath(path: path)
808
+ // Notify listeners
809
+ notifyReloadedListeners()
758
810
  }
759
811
 
760
812
  /// - Parameter bundleId: The bundle ID to set as the next bundle. If `nil`, the default bundle will be used.
@@ -771,6 +823,10 @@ import CommonCrypto
771
823
  plugin.notifyNextBundleSetListeners(event)
772
824
  }
773
825
 
826
+ private func notifyReloadedListeners() {
827
+ plugin.notifyReloadedListeners()
828
+ }
829
+
774
830
  private func addBlockedBundleId(_ bundleId: String) {
775
831
  var blockedList: [String] = []
776
832
 
@@ -818,6 +874,23 @@ import CommonCrypto
818
874
  }
819
875
  }
820
876
 
877
+ private func checkAndResetConfigIfVersionChanged() {
878
+ let currentVersionCode = getVersionCode()
879
+ let currentVersionName = getVersionName()
880
+ let lastVersionCode = preferences.getLastVersionCode()
881
+ let lastVersionName = preferences.getLastVersionName()
882
+
883
+ if lastVersionCode == nil || lastVersionName == nil || lastVersionCode != currentVersionCode || lastVersionName != currentVersionName {
884
+ CAPLog.print(
885
+ "[", LiveUpdatePlugin.tag, "] ",
886
+ "App version changed (last: \(lastVersionName ?? "nil")/\(lastVersionCode ?? "nil"), current: \(currentVersionName)/\(currentVersionCode)), resetting config."
887
+ )
888
+ resetConfig()
889
+ preferences.setLastVersionCode(currentVersionCode)
890
+ preferences.setLastVersionName(currentVersionName)
891
+ }
892
+ }
893
+
821
894
  /// - Parameter bundleId: The bundle ID to save as the previous bundle ID. If `nil`, the value will be removed.
822
895
  private func setPreviousBundleId(bundleId: String?) {
823
896
  preferences.setPreviousBundleId(bundleId)
@@ -8,27 +8,34 @@ import Capacitor
8
8
  @objc(LiveUpdatePlugin)
9
9
  public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
10
10
  public static let tag = "LiveUpdate"
11
- public static let version = "7.3.0"
11
+ public static let version = "7.4.0"
12
12
  public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
13
13
 
14
14
  public let identifier = "LiveUpdatePlugin"
15
15
  public let jsName = "LiveUpdate"
16
16
  public let pluginMethods: [CAPPluginMethod] = [
17
+ CAPPluginMethod(name: "clearBlockedBundles", returnType: CAPPluginReturnPromise),
17
18
  CAPPluginMethod(name: "deleteBundle", returnType: CAPPluginReturnPromise),
18
19
  CAPPluginMethod(name: "downloadBundle", returnType: CAPPluginReturnPromise),
19
20
  CAPPluginMethod(name: "fetchLatestBundle", returnType: CAPPluginReturnPromise),
21
+ CAPPluginMethod(name: "getBlockedBundles", returnType: CAPPluginReturnPromise),
20
22
  CAPPluginMethod(name: "getBundles", returnType: CAPPluginReturnPromise),
21
23
  CAPPluginMethod(name: "getChannel", returnType: CAPPluginReturnPromise),
24
+ CAPPluginMethod(name: "getConfig", returnType: CAPPluginReturnPromise),
25
+ CAPPluginMethod(name: "getDownloadedBundles", returnType: CAPPluginReturnPromise),
22
26
  CAPPluginMethod(name: "getCurrentBundle", returnType: CAPPluginReturnPromise),
23
27
  CAPPluginMethod(name: "getCustomId", returnType: CAPPluginReturnPromise),
24
28
  CAPPluginMethod(name: "getDeviceId", returnType: CAPPluginReturnPromise),
25
29
  CAPPluginMethod(name: "getNextBundle", returnType: CAPPluginReturnPromise),
26
30
  CAPPluginMethod(name: "getVersionCode", returnType: CAPPluginReturnPromise),
27
31
  CAPPluginMethod(name: "getVersionName", returnType: CAPPluginReturnPromise),
32
+ CAPPluginMethod(name: "isSyncing", returnType: CAPPluginReturnPromise),
28
33
  CAPPluginMethod(name: "ready", returnType: CAPPluginReturnPromise),
29
34
  CAPPluginMethod(name: "reload", returnType: CAPPluginReturnPromise),
30
35
  CAPPluginMethod(name: "reset", returnType: CAPPluginReturnPromise),
36
+ CAPPluginMethod(name: "resetConfig", returnType: CAPPluginReturnPromise),
31
37
  CAPPluginMethod(name: "setChannel", returnType: CAPPluginReturnPromise),
38
+ CAPPluginMethod(name: "setConfig", returnType: CAPPluginReturnPromise),
32
39
  CAPPluginMethod(name: "setCustomId", returnType: CAPPluginReturnPromise),
33
40
  CAPPluginMethod(name: "setNextBundle", returnType: CAPPluginReturnPromise),
34
41
  CAPPluginMethod(name: "sync", returnType: CAPPluginReturnPromise)
@@ -36,6 +43,7 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
36
43
 
37
44
  private let eventDownloadBundleProgess = "downloadBundleProgress"
38
45
  private let eventNextBundleSet = "nextBundleSet"
46
+ private let eventReloaded = "reloaded"
39
47
 
40
48
  private var config: LiveUpdateConfig?
41
49
  private var implementation: LiveUpdate?
@@ -56,6 +64,11 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
56
64
  )
57
65
  }
58
66
 
67
+ @objc func clearBlockedBundles(_ call: CAPPluginCall) {
68
+ implementation?.clearBlockedBundles()
69
+ resolveCall(call)
70
+ }
71
+
59
72
  @objc func deleteBundle(_ call: CAPPluginCall) {
60
73
  guard let bundleId = call.getString("bundleId") else {
61
74
  call.reject(CustomError.bundleIdMissing.localizedDescription)
@@ -117,6 +130,18 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
117
130
  }
118
131
  }
119
132
 
133
+ @objc func getBlockedBundles(_ call: CAPPluginCall) {
134
+ implementation?.getBlockedBundles(completion: { result, error in
135
+ if let error = error {
136
+ self.rejectCall(call, error)
137
+ return
138
+ }
139
+ if let result = result?.toJSObject() as? JSObject {
140
+ self.resolveCall(call, result)
141
+ }
142
+ })
143
+ }
144
+
120
145
  @objc func getBundles(_ call: CAPPluginCall) {
121
146
  implementation?.getBundles(completion: { result, error in
122
147
  if let error = error {
@@ -129,6 +154,18 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
129
154
  })
130
155
  }
131
156
 
157
+ @objc func getDownloadedBundles(_ call: CAPPluginCall) {
158
+ implementation?.getDownloadedBundles(completion: { result, error in
159
+ if let error = error {
160
+ self.rejectCall(call, error)
161
+ return
162
+ }
163
+ if let result = result?.toJSObject() as? JSObject {
164
+ self.resolveCall(call, result)
165
+ }
166
+ })
167
+ }
168
+
132
169
  @objc func getChannel(_ call: CAPPluginCall) {
133
170
  implementation?.getChannel(completion: { result, error in
134
171
  if let error = error {
@@ -141,6 +178,18 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
141
178
  })
142
179
  }
143
180
 
181
+ @objc func getConfig(_ call: CAPPluginCall) {
182
+ implementation?.getConfig(completion: { result, error in
183
+ if let error = error {
184
+ self.rejectCall(call, error)
185
+ return
186
+ }
187
+ if let result = result?.toJSObject() as? JSObject {
188
+ self.resolveCall(call, result)
189
+ }
190
+ })
191
+ }
192
+
144
193
  @objc func getCurrentBundle(_ call: CAPPluginCall) {
145
194
  implementation?.getCurrentBundle(completion: { result, error in
146
195
  if let error = error {
@@ -213,6 +262,18 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
213
262
  })
214
263
  }
215
264
 
265
+ @objc func isSyncing(_ call: CAPPluginCall) {
266
+ implementation?.isSyncing(completion: { result, error in
267
+ if let error = error {
268
+ self.rejectCall(call, error)
269
+ return
270
+ }
271
+ if let result = result?.toJSObject() as? JSObject {
272
+ self.resolveCall(call, result)
273
+ }
274
+ })
275
+ }
276
+
216
277
  @objc func ready(_ call: CAPPluginCall) {
217
278
  implementation?.ready(completion: { result, error in
218
279
  if let error = error {
@@ -235,6 +296,11 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
235
296
  resolveCall(call)
236
297
  }
237
298
 
299
+ @objc func resetConfig(_ call: CAPPluginCall) {
300
+ implementation?.resetConfig()
301
+ resolveCall(call)
302
+ }
303
+
238
304
  @objc func setChannel(_ call: CAPPluginCall) {
239
305
  let channel = call.getString("channel")
240
306
 
@@ -249,6 +315,12 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
249
315
  })
250
316
  }
251
317
 
318
+ @objc func setConfig(_ call: CAPPluginCall) {
319
+ let options = SetConfigOptions(call)
320
+ implementation?.setConfig(options)
321
+ resolveCall(call)
322
+ }
323
+
252
324
  @objc func setCustomId(_ call: CAPPluginCall) {
253
325
  guard let customId = call.getString("customId") else {
254
326
  call.reject(CustomError.customIdMissing.localizedDescription)
@@ -307,6 +379,11 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
307
379
  notifyListeners(eventNextBundleSet, data: event.toJSObject(), retainUntilConsumed: false)
308
380
  }
309
381
 
382
+ func notifyReloadedListeners() {
383
+ let event = JSObject()
384
+ notifyListeners(eventReloaded, data: event, retainUntilConsumed: true)
385
+ }
386
+
310
387
  @objc private func handleAppWillEnterForeground() {
311
388
  implementation?.handleAppWillEnterForeground()
312
389
  }
@@ -1,11 +1,22 @@
1
1
  import Foundation
2
2
 
3
3
  public class LiveUpdatePreferences: NSObject {
4
+ private let appIdKey = "appId" // DO NOT CHANGE
4
5
  private let blockedBundleIdsKey = "blockedBundleIds" // DO NOT CHANGE
5
6
  private let channelKey = "channel" // DO NOT CHANGE
6
7
  private let customIdKey = "customId" // DO NOT CHANGE
8
+ private let lastVersionCodeKey = "lastVersionCode" // DO NOT CHANGE
9
+ private let lastVersionNameKey = "lastVersionName" // DO NOT CHANGE
7
10
  private let previousBundleIdKey = "previousBundleIdKey" // DO NOT CHANGE
8
11
 
12
+ public func getAppId() -> String? {
13
+ return UserDefaults.standard.string(forKey: applyPrefix(to: appIdKey))
14
+ }
15
+
16
+ public func getBlockedBundleIds() -> String? {
17
+ return UserDefaults.standard.string(forKey: applyPrefix(to: blockedBundleIdsKey))
18
+ }
19
+
9
20
  public func getChannel() -> String? {
10
21
  return UserDefaults.standard.string(forKey: applyPrefix(to: channelKey))
11
22
  }
@@ -14,12 +25,25 @@ public class LiveUpdatePreferences: NSObject {
14
25
  return UserDefaults.standard.string(forKey: applyPrefix(to: customIdKey))
15
26
  }
16
27
 
28
+ public func getLastVersionCode() -> String? {
29
+ return UserDefaults.standard.string(forKey: applyPrefix(to: lastVersionCodeKey))
30
+ }
31
+
32
+ public func getLastVersionName() -> String? {
33
+ return UserDefaults.standard.string(forKey: applyPrefix(to: lastVersionNameKey))
34
+ }
35
+
17
36
  public func getPreviousBundleId() -> String? {
18
37
  return UserDefaults.standard.string(forKey: applyPrefix(to: previousBundleIdKey))
19
38
  }
20
39
 
21
- public func getBlockedBundleIds() -> String? {
22
- return UserDefaults.standard.string(forKey: applyPrefix(to: blockedBundleIdsKey))
40
+ public func setAppId(_ value: String?) {
41
+ if let value = value {
42
+ UserDefaults.standard.set(value, forKey: applyPrefix(to: appIdKey))
43
+ } else {
44
+ UserDefaults.standard.removeObject(forKey: applyPrefix(to: appIdKey))
45
+ }
46
+ UserDefaults.standard.synchronize()
23
47
  }
24
48
 
25
49
  public func setBlockedBundleIds(_ value: String?) {
@@ -45,6 +69,24 @@ public class LiveUpdatePreferences: NSObject {
45
69
  UserDefaults.standard.synchronize()
46
70
  }
47
71
 
72
+ public func setLastVersionCode(_ value: String?) {
73
+ if let value = value {
74
+ UserDefaults.standard.set(value, forKey: applyPrefix(to: lastVersionCodeKey))
75
+ } else {
76
+ UserDefaults.standard.removeObject(forKey: applyPrefix(to: lastVersionCodeKey))
77
+ }
78
+ UserDefaults.standard.synchronize()
79
+ }
80
+
81
+ public func setLastVersionName(_ value: String?) {
82
+ if let value = value {
83
+ UserDefaults.standard.set(value, forKey: applyPrefix(to: lastVersionNameKey))
84
+ } else {
85
+ UserDefaults.standard.removeObject(forKey: applyPrefix(to: lastVersionNameKey))
86
+ }
87
+ UserDefaults.standard.synchronize()
88
+ }
89
+
48
90
  public func setPreviousBundleId(_ value: String?) {
49
91
  if let value = value {
50
92
  UserDefaults.standard.set(value, forKey: applyPrefix(to: previousBundleIdKey))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capawesome/capacitor-live-update",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "description": "Capacitor plugin to update your app remotely in real-time.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",