@capgo/capacitor-updater 3.2.0 → 3.2.1-alpha.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.
@@ -10,6 +10,11 @@ extension URL {
10
10
  return FileManager().fileExists(atPath: self.path)
11
11
  }
12
12
  }
13
+ extension Date {
14
+ func adding(minutes: Int) -> Date {
15
+ return Calendar.current.date(byAdding: .minute, value: minutes, to: self)!
16
+ }
17
+ }
13
18
  struct AppVersionDec: Decodable {
14
19
  let version: String?
15
20
  let url: String?
@@ -36,28 +41,111 @@ extension Bundle {
36
41
  }
37
42
  }
38
43
 
44
+ extension ISO8601DateFormatter {
45
+ convenience init(_ formatOptions: Options) {
46
+ self.init()
47
+ self.formatOptions = formatOptions
48
+ }
49
+ }
50
+ extension Formatter {
51
+ static let iso8601withFractionalSeconds = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])
52
+ }
53
+ extension Date {
54
+ var iso8601withFractionalSeconds: String { return Formatter.iso8601withFractionalSeconds.string(from: self) }
55
+ }
56
+ extension String {
57
+
58
+ var fileURL: URL {
59
+ return URL(fileURLWithPath: self)
60
+ }
61
+
62
+ var lastPathComponent:String {
63
+ get {
64
+ return fileURL.lastPathComponent
65
+ }
66
+ }
67
+ var iso8601withFractionalSeconds: Date? {
68
+ return Formatter.iso8601withFractionalSeconds.date(from: self)
69
+ }
70
+ func trim(using characterSet: CharacterSet = .whitespacesAndNewlines) -> String {
71
+ return trimmingCharacters(in: characterSet)
72
+ }
73
+ }
74
+
75
+ enum CustomError: Error {
76
+ // Throw when an unzip fail
77
+ case cannotUnzip
78
+ case cannotUnflat
79
+ case cannotCreateDirectory
80
+ case cannotDeleteDirectory
81
+
82
+ // Throw in all other cases
83
+ case unexpected(code: Int)
84
+ }
85
+
86
+ extension CustomError: LocalizedError {
87
+ public var errorDescription: String? {
88
+ switch self {
89
+ case .cannotUnzip:
90
+ return NSLocalizedString(
91
+ "The file cannot be unzip",
92
+ comment: "Invalid zip"
93
+ )
94
+ case .cannotCreateDirectory:
95
+ return NSLocalizedString(
96
+ "The folder cannot be created",
97
+ comment: "Invalid folder"
98
+ )
99
+ case .cannotDeleteDirectory:
100
+ return NSLocalizedString(
101
+ "The folder cannot be deleted",
102
+ comment: "Invalid folder"
103
+ )
104
+ case .cannotUnflat:
105
+ return NSLocalizedString(
106
+ "The file cannot be unflat",
107
+ comment: "Invalid folder"
108
+ )
109
+ case .unexpected(_):
110
+ return NSLocalizedString(
111
+ "An unexpected error occurred.",
112
+ comment: "Unexpected Error"
113
+ )
114
+ }
115
+ }
116
+ }
117
+
39
118
  @objc public class CapacitorUpdater: NSObject {
40
119
 
120
+ private let versionBuild = Bundle.main.releaseVersionNumber ?? ""
121
+ private let versionCode = Bundle.main.buildVersionNumber ?? ""
122
+ private let versionOs = ProcessInfo().operatingSystemVersion.getFullVersion()
123
+ private let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
124
+ private let libraryDir = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
125
+ private let bundleDirectoryHot = "versions"
126
+ private let DEFAULT_FOLDER = ""
127
+ private let bundleDirectory = "NoCloud/ionic_built_snapshots"
128
+ private let INFO_SUFFIX = "_info"
129
+ private let FALLBACK_VERSION = "pastVersion"
130
+ private let NEXT_VERSION = "nextVersion"
131
+
132
+ private var lastPathHot = ""
133
+ private var lastPathPersist = ""
134
+
135
+ public let TAG = "✨ Capacitor-updater:";
136
+ public let CAP_SERVER_PATH = "serverBasePath"
137
+ public let pluginVersion = "3.2.1-alpha.0"
41
138
  public var statsUrl = ""
42
139
  public var appId = ""
43
140
  public var deviceID = UIDevice.current.identifierForVendor?.uuidString ?? ""
44
- public var notifyDownload: (Int) -> Void = { _ in }
45
- public var pluginVersion = "3.2.0"
46
- private var versionBuild = Bundle.main.releaseVersionNumber ?? ""
47
- private var versionCode = Bundle.main.buildVersionNumber ?? ""
48
- private var versionOs = ProcessInfo().operatingSystemVersion.getFullVersion()
49
- private var lastPathHot = ""
50
- private var lastPathPersist = ""
51
- private let basePathHot = "versions"
52
- private let basePathPersist = "NoCloud/ionic_built_snapshots"
53
- private let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
54
- private let libraryUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
55
141
 
56
- @objc private func calcTotalPercent(percent: Int, min: Int, max: Int) -> Int {
142
+ public var notifyDownload: (String, Int) -> Void = { _,_ in }
143
+
144
+ private func calcTotalPercent(percent: Int, min: Int, max: Int) -> Int {
57
145
  return (percent * (max - min)) / 100 + min;
58
146
  }
59
147
 
60
- @objc private func randomString(length: Int) -> String {
148
+ private func randomString(length: Int) -> String {
61
149
  let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
62
150
  return String((0..<length).map{ _ in letters.randomElement()! })
63
151
  }
@@ -66,25 +154,27 @@ extension Bundle {
66
154
  // Hot Reload path /var/mobile/Containers/Data/Application/8C0C07BE-0FD3-4FD4-B7DF-90A88E12B8C3/Documents/FOLDER
67
155
  // Normal /private/var/containers/Bundle/Application/8C0C07BE-0FD3-4FD4-B7DF-90A88E12B8C3/App.app/public
68
156
 
69
- private func prepareFolder(source: URL) {
157
+ private func prepareFolder(source: URL) throws {
70
158
  if (!FileManager.default.fileExists(atPath: source.path)) {
71
159
  do {
72
160
  try FileManager.default.createDirectory(atPath: source.path, withIntermediateDirectories: true, attributes: nil)
73
161
  } catch {
74
- print("✨ Capacitor-updater: Cannot createDirectory \(source.path)")
162
+ print("\(self.TAG) Cannot createDirectory \(source.path)")
163
+ throw CustomError.cannotCreateDirectory
75
164
  }
76
165
  }
77
166
  }
78
167
 
79
- private func deleteFolder(source: URL) {
168
+ private func deleteFolder(source: URL) throws {
80
169
  do {
81
170
  try FileManager.default.removeItem(atPath: source.path)
82
171
  } catch {
83
- print("✨ Capacitor-updater: File not removed. \(source.path)")
172
+ print("\(self.TAG) File not removed. \(source.path)")
173
+ throw CustomError.cannotDeleteDirectory
84
174
  }
85
175
  }
86
176
 
87
- private func unflatFolder(source: URL, dest: URL) -> Bool {
177
+ private func unflatFolder(source: URL, dest: URL) throws -> Bool {
88
178
  let index = source.appendingPathComponent("index.html")
89
179
  do {
90
180
  let files = try FileManager.default.contentsOfDirectory(atPath: source.path)
@@ -96,35 +186,37 @@ extension Bundle {
96
186
  return false
97
187
  }
98
188
  } catch {
99
- print("✨ Capacitor-updater: File not moved. source: \(source.path) dest: \(dest.path)")
100
- return true
189
+ print("\(self.TAG) File not moved. source: \(source.path) dest: \(dest.path)")
190
+ throw CustomError.cannotUnflat
101
191
  }
102
192
  }
103
193
 
104
- private func saveDownloaded(sourceZip: URL, version: String, base: URL) {
105
- prepareFolder(source: base)
106
- let destHot = base.appendingPathComponent(version)
107
- let destUnZip = documentsUrl.appendingPathComponent(randomString(length: 10))
108
- SSZipArchive.unzipFile(atPath: sourceZip.path, toDestination: destUnZip.path)
109
- if (unflatFolder(source: destUnZip, dest: destHot)) {
110
- deleteFolder(source: destUnZip)
194
+ private func saveDownloaded(sourceZip: URL, id: String, base: URL) throws {
195
+ try prepareFolder(source: base)
196
+ let destHot = base.appendingPathComponent(id)
197
+ let destUnZip = documentsDir.appendingPathComponent(randomString(length: 10))
198
+ if (!SSZipArchive.unzipFile(atPath: sourceZip.path, toDestination: destUnZip.path)) {
199
+ throw CustomError.cannotUnzip
200
+ }
201
+ if (try unflatFolder(source: destUnZip, dest: destHot)) {
202
+ try deleteFolder(source: destUnZip)
111
203
  }
112
204
  }
113
205
 
114
- @objc public func getLatest(url: URL) -> AppVersion? {
206
+ public func getLatest(url: URL) -> AppVersion? {
115
207
  let semaphore = DispatchSemaphore(value: 0)
116
208
  let latest = AppVersion()
117
- let headers: HTTPHeaders = [
118
- "cap_platform": "ios",
119
- "cap_device_id": self.deviceID,
120
- "cap_app_id": self.appId,
121
- "cap_version_build": self.versionBuild,
122
- "cap_version_code": self.versionCode,
123
- "cap_version_os": self.versionOs,
124
- "cap_plugin_version": self.pluginVersion,
125
- "cap_version_name": UserDefaults.standard.string(forKey: "versionName") ?? "builtin"
209
+ let parameters: [String: String] = [
210
+ "platform": "ios",
211
+ "device_id": self.deviceID,
212
+ "app_id": self.appId,
213
+ "version_build": self.versionBuild,
214
+ "version_code": self.versionCode,
215
+ "version_os": self.versionOs,
216
+ "plugin_version": self.pluginVersion,
217
+ "version_name": self.getCurrentBundle().getVersionName()
126
218
  ]
127
- let request = AF.request(url, headers: headers)
219
+ let request = AF.request(url, method: .post,parameters: parameters, encoder: JSONParameterEncoder.default)
128
220
 
129
221
  request.validate().responseDecodable(of: AppVersionDec.self) { response in
130
222
  switch response.result {
@@ -140,9 +232,10 @@ extension Bundle {
140
232
  }
141
233
  if let message = response.value?.message {
142
234
  latest.message = message
235
+ print("\(self.TAG) Auto-update message: \(message)")
143
236
  }
144
237
  case let .failure(error):
145
- print("✨ Capacitor-updater: Error getting Latest", error )
238
+ print("\(self.TAG) Error getting Latest", error )
146
239
  }
147
240
  semaphore.signal()
148
241
  }
@@ -150,9 +243,16 @@ extension Bundle {
150
243
  return latest.url != "" ? latest : nil
151
244
  }
152
245
 
153
- @objc public func download(url: URL) -> String? {
246
+ private func setCurrentBundle(bundle: String) {
247
+ UserDefaults.standard.set(bundle, forKey: self.CAP_SERVER_PATH)
248
+ print("\(self.TAG) Current bundle set to: \(bundle)")
249
+ UserDefaults.standard.synchronize()
250
+ }
251
+
252
+ public func download(url: URL, version: String) throws -> BundleInfo {
154
253
  let semaphore = DispatchSemaphore(value: 0)
155
- var version: String? = nil
254
+ let id: String = self.randomString(length: 10)
255
+ var mainError: NSError? = nil
156
256
  let destination: DownloadRequest.Destination = { _, _ in
157
257
  let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
158
258
  let fileURL = documentsURL.appendingPathComponent(self.randomString(length: 10))
@@ -163,104 +263,143 @@ extension Bundle {
163
263
 
164
264
  request.downloadProgress { progress in
165
265
  let percent = self.calcTotalPercent(percent: Int(progress.fractionCompleted * 100), min: 10, max: 70)
166
- self.notifyDownload(percent)
266
+ self.notifyDownload(id, percent)
167
267
  }
168
268
  request.responseURL { (response) in
169
269
  if let fileURL = response.fileURL {
170
270
  switch response.result {
171
271
  case .success:
172
- self.notifyDownload(71);
173
- version = self.randomString(length: 10)
174
- self.saveDownloaded(sourceZip: fileURL, version: version!, base: self.documentsUrl.appendingPathComponent(self.basePathHot))
175
- self.notifyDownload(85);
176
- self.saveDownloaded(sourceZip: fileURL, version: version!, base: self.libraryUrl.appendingPathComponent(self.basePathPersist))
177
- self.notifyDownload(100);
178
- self.deleteFolder(source: fileURL)
272
+ self.notifyDownload(id, 71)
273
+ do {
274
+ try self.saveDownloaded(sourceZip: fileURL, id: id, base: self.documentsDir.appendingPathComponent(self.bundleDirectoryHot))
275
+ self.notifyDownload(id, 85)
276
+ try self.saveDownloaded(sourceZip: fileURL, id: id, base: self.libraryDir.appendingPathComponent(self.bundleDirectory))
277
+ self.notifyDownload(id, 100)
278
+ try self.deleteFolder(source: fileURL)
279
+ } catch {
280
+ print("\(self.TAG) download unzip error", error)
281
+ mainError = error as NSError
282
+ }
179
283
  case let .failure(error):
180
- print("✨ Capacitor-updater: download error", error)
181
- version = nil
284
+ print("\(self.TAG) download error", error)
285
+ mainError = error as NSError
182
286
  }
183
287
  }
184
288
  semaphore.signal()
185
289
  }
186
- self.notifyDownload(0);
290
+ self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.DOWNLOADING, downloaded: Date()))
291
+ self.notifyDownload(id, 0)
187
292
  semaphore.wait()
188
- return version
293
+ if (mainError != nil) {
294
+ throw mainError!
295
+ }
296
+ let info: BundleInfo = BundleInfo(id: id, version: version, status: BundleStatus.PENDING, downloaded: Date())
297
+ self.saveBundleInfo(id: id, bundle: info)
298
+ return info
189
299
  }
190
300
 
191
- @objc public func list() -> [String] {
192
- let dest = documentsUrl.appendingPathComponent(basePathHot)
301
+ public func list() -> [BundleInfo] {
302
+ let dest = documentsDir.appendingPathComponent(bundleDirectoryHot)
193
303
  do {
194
304
  let files = try FileManager.default.contentsOfDirectory(atPath: dest.path)
195
- return files
305
+ var res: [BundleInfo] = []
306
+ print("\(self.TAG) list File : \(dest.path)")
307
+ if (dest.exist) {
308
+ for id in files {
309
+ res.append(self.getBundleInfo(id: id));
310
+ }
311
+ }
312
+ return res
196
313
  } catch {
197
- print("✨ Capacitor-updater: No version available \(dest.path)")
314
+ print("\(self.TAG) No version available \(dest.path)")
198
315
  return []
199
316
  }
200
317
  }
201
318
 
202
- @objc public func delete(version: String, versionName: String) -> Bool {
203
- let destHot = documentsUrl.appendingPathComponent(basePathHot).appendingPathComponent(version)
204
- let destPersist = libraryUrl.appendingPathComponent(basePathPersist).appendingPathComponent(version)
319
+ public func delete(id: String) -> Bool {
320
+ let deleted: BundleInfo = self.getBundleInfo(id: id)
321
+ let destHot = documentsDir.appendingPathComponent(bundleDirectoryHot).appendingPathComponent(id)
322
+ let destPersist = libraryDir.appendingPathComponent(bundleDirectory).appendingPathComponent(id)
205
323
  do {
206
324
  try FileManager.default.removeItem(atPath: destHot.path)
207
325
  } catch {
208
- print("✨ Capacitor-updater: Hot Folder \(destHot.path), not removed.")
326
+ print("\(self.TAG) Hot Folder \(destHot.path), not removed.")
209
327
  }
210
328
  do {
211
329
  try FileManager.default.removeItem(atPath: destPersist.path)
212
330
  } catch {
213
- print("✨ Capacitor-updater: Folder \(destPersist.path), not removed.")
331
+ print("\(self.TAG) Folder \(destPersist.path), not removed.")
214
332
  return false
215
333
  }
216
- sendStats(action: "delete", version: versionName)
334
+ self.removeBundleInfo(id: id)
335
+ self.sendStats(action: "delete", bundle: deleted)
217
336
  return true
218
337
  }
219
338
 
220
- @objc public func set(version: String, versionName: String) -> Bool {
221
- let destHot = documentsUrl.appendingPathComponent(basePathHot).appendingPathComponent(version)
339
+ public func getBundleDirectory(id: String) -> URL {
340
+ return libraryDir.appendingPathComponent(self.bundleDirectory).appendingPathComponent(id)
341
+ }
342
+
343
+ public func set(bundle: BundleInfo) -> Bool {
344
+ return self.set(id: bundle.getId());
345
+ }
346
+
347
+ public func set(id: String) -> Bool {
348
+ let destHot = self.getPathHot(id: id)
349
+ let destHotPersist = self.getPathPersist(id: id)
222
350
  let indexHot = destHot.appendingPathComponent("index.html")
223
- let destHotPersist = libraryUrl.appendingPathComponent(basePathPersist).appendingPathComponent(version)
224
351
  let indexPersist = destHotPersist.appendingPathComponent("index.html")
225
- if (destHot.isDirectory && destHotPersist.isDirectory && indexHot.exist && indexPersist.exist) {
226
- UserDefaults.standard.set(destHot.path, forKey: "lastPathHot")
227
- UserDefaults.standard.set(destHotPersist.path, forKey: "lastPathPersist")
228
- UserDefaults.standard.set(versionName, forKey: "versionName")
229
- sendStats(action: "set", version: versionName)
352
+ let existing: BundleInfo = self.getBundleInfo(id: id)
353
+ let bundle: URL = self.getBundleDirectory(id: id)
354
+ print("bundle", bundle.path)
355
+ if (bundle.isDirectory && destHotPersist.isDirectory && indexHot.exist && indexPersist.exist) {
356
+ self.setCurrentBundle(bundle: String(bundle.path.suffix(10)))
357
+ self.setBundleStatus(id: id, status: BundleStatus.PENDING)
358
+ sendStats(action: "set", bundle: existing)
230
359
  return true
231
360
  }
232
- sendStats(action: "set_fail", version: versionName)
361
+ sendStats(action: "set_fail", bundle: existing)
233
362
  return false
234
363
  }
235
364
 
236
- @objc public func getLastPathHot() -> String {
237
- return UserDefaults.standard.string(forKey: "lastPathHot") ?? ""
365
+ public func getPathHot(id: String) -> URL {
366
+ return documentsDir.appendingPathComponent(self.bundleDirectoryHot).appendingPathComponent(id)
238
367
  }
239
368
 
240
- @objc public func getVersionName() -> String {
241
- return UserDefaults.standard.string(forKey: "versionName") ?? ""
369
+ public func getPathPersist(id: String) -> URL {
370
+ return libraryDir.appendingPathComponent(self.bundleDirectory).appendingPathComponent(id)
242
371
  }
243
372
 
244
- @objc public func getLastPathPersist() -> String {
245
- return UserDefaults.standard.string(forKey: "lastPathPersist") ?? ""
373
+ public func reset() {
374
+ self.reset(isInternal: false)
246
375
  }
247
376
 
248
- @objc public func reset() {
249
- let version = UserDefaults.standard.string(forKey: "versionName") ?? ""
250
- sendStats(action: "reset", version: version)
251
- UserDefaults.standard.set("", forKey: "lastPathHot")
252
- UserDefaults.standard.set("", forKey: "lastPathPersist")
253
- UserDefaults.standard.set("", forKey: "versionName")
377
+ public func reset(isInternal: Bool) {
378
+ self.setCurrentBundle(bundle: "")
379
+ self.setFallbackVersion(fallback: Optional<BundleInfo>.none)
380
+ let _ = self.setNextVersion(next: Optional<String>.none)
254
381
  UserDefaults.standard.synchronize()
382
+ if(!isInternal) {
383
+ sendStats(action: "reset", bundle: self.getCurrentBundle())
384
+ }
385
+ }
386
+
387
+ public func commit(bundle: BundleInfo) {
388
+ self.setBundleStatus(id: bundle.getId(), status: BundleStatus.SUCCESS)
389
+ self.setFallbackVersion(fallback: bundle)
390
+ }
391
+
392
+ public func rollback(bundle: BundleInfo) {
393
+ self.setBundleStatus(id: bundle.getId(), status: BundleStatus.ERROR);
255
394
  }
256
395
 
257
- @objc func sendStats(action: String, version: String) {
396
+ func sendStats(action: String, bundle: BundleInfo) {
258
397
  if (statsUrl == "") { return }
259
398
  let parameters: [String: String] = [
260
399
  "platform": "ios",
261
400
  "action": action,
262
401
  "device_id": self.deviceID,
263
- "version_name": version,
402
+ "version_name": bundle.getVersionName(),
264
403
  "version_build": self.versionBuild,
265
404
  "version_code": self.versionCode,
266
405
  "version_os": self.versionOs,
@@ -270,8 +409,122 @@ extension Bundle {
270
409
 
271
410
  DispatchQueue.global(qos: .background).async {
272
411
  let _ = AF.request(self.statsUrl, method: .post,parameters: parameters, encoder: JSONParameterEncoder.default)
273
- print("✨ Capacitor-updater: Stats send for \(action), version \(version)")
412
+ print("\(self.TAG) Stats send for \(action), version \(bundle.getVersionName())")
274
413
  }
275
414
  }
276
-
415
+
416
+ public func getBundleInfo(id: String = BundleInfo.ID_BUILTIN) -> BundleInfo {
417
+ print("\(self.TAG) Getting info for bundle [\(id)]")
418
+ if(BundleInfo.ID_BUILTIN == id) {
419
+ return BundleInfo(id: id, version: "", status: BundleStatus.SUCCESS)
420
+ }
421
+ do {
422
+ let result: BundleInfo = try UserDefaults.standard.getObj(forKey: "\(id)\(self.INFO_SUFFIX)", castTo: BundleInfo.self)
423
+ print("\(self.TAG) Returning info bundle [\(id)]", result.toString())
424
+ return result
425
+ } catch {
426
+ print("\(self.TAG) Failed to parse info for bundle [\(id)]", error.localizedDescription)
427
+ return BundleInfo(id: id, version: "", status: BundleStatus.PENDING)
428
+ }
429
+ }
430
+
431
+ public func getBundleInfoByVersionName(version: String) -> BundleInfo? {
432
+ let installed : Array<BundleInfo> = self.list()
433
+ for i in installed {
434
+ if(i.getVersionName() == version) {
435
+ return i
436
+ }
437
+ }
438
+ return nil
439
+ }
440
+
441
+ private func removeBundleInfo(id: String) {
442
+ self.saveBundleInfo(id: id, bundle: nil)
443
+ }
444
+
445
+ private func saveBundleInfo(id: String, bundle: BundleInfo?) {
446
+ if (bundle != nil && (bundle!.isBuiltin() || bundle!.isUnknown())) {
447
+ print("\(self.TAG) Not saving info for bundle [\(id)]", bundle!.toString())
448
+ return
449
+ }
450
+ if(bundle == nil) {
451
+ print("\(self.TAG) Removing info for bundle [\(id)]")
452
+ UserDefaults.standard.removeObject(forKey: "\(id)\(self.INFO_SUFFIX)")
453
+ } else {
454
+ let update = bundle!.setId(id: id)
455
+ print("\(self.TAG) Storing info for bundle [\(id)]", update.toString())
456
+ do {
457
+ try UserDefaults.standard.setObj(update, forKey: "\(id)\(self.INFO_SUFFIX)")
458
+ } catch {
459
+ print("\(self.TAG) Failed to save info for bundle [\(id)]", error.localizedDescription)
460
+ }
461
+ }
462
+ UserDefaults.standard.synchronize()
463
+ }
464
+
465
+ public func setVersionName(id: String, version: String) {
466
+ print("\(self.TAG) Setting version for folder [\(id)] to \(version)")
467
+ let info = self.getBundleInfo(id: id)
468
+ self.saveBundleInfo(id: id, bundle: info.setVersionName(version: version))
469
+ }
470
+
471
+ private func setBundleStatus(id: String, status: BundleStatus) {
472
+ print("\(self.TAG) Setting status for bundle [\(id)] to \(status)")
473
+ let info = self.getBundleInfo(id: id)
474
+ self.saveBundleInfo(id: id, bundle: info.setStatus(status: status.localizedString))
475
+ }
476
+
477
+ private func getCurrentBundleVersion() -> String {
478
+ if(self.isUsingBuiltin()) {
479
+ return BundleInfo.ID_BUILTIN
480
+ } else {
481
+ let path: String = self.getCurrentBundleId()
482
+ return path.lastPathComponent
483
+ }
484
+ }
485
+
486
+ public func getCurrentBundle() -> BundleInfo {
487
+ return self.getBundleInfo(id: self.getCurrentBundleId());
488
+ }
489
+
490
+ public func getCurrentBundleId() -> String {
491
+ return UserDefaults.standard.string(forKey: self.CAP_SERVER_PATH) ?? self.DEFAULT_FOLDER
492
+ }
493
+
494
+ public func isUsingBuiltin() -> Bool {
495
+ return self.getCurrentBundleId() == self.DEFAULT_FOLDER
496
+ }
497
+
498
+ public func getFallbackVersion() -> BundleInfo {
499
+ let id: String = UserDefaults.standard.string(forKey: self.FALLBACK_VERSION) ?? BundleInfo.ID_BUILTIN
500
+ return self.getBundleInfo(id: id)
501
+ }
502
+
503
+ private func setFallbackVersion(fallback: BundleInfo?) {
504
+ UserDefaults.standard.set(fallback == nil ? BundleInfo.ID_BUILTIN : fallback!.getId(), forKey: self.FALLBACK_VERSION)
505
+ }
506
+
507
+ public func getNextVersion() -> BundleInfo? {
508
+ let id: String = UserDefaults.standard.string(forKey: self.NEXT_VERSION) ?? ""
509
+ if(id != "") {
510
+ return self.getBundleInfo(id: id)
511
+ } else {
512
+ return nil
513
+ }
514
+ }
515
+
516
+ public func setNextVersion(next: String?) -> Bool {
517
+ if (next == nil) {
518
+ UserDefaults.standard.removeObject(forKey: self.NEXT_VERSION)
519
+ } else {
520
+ let bundle: URL = self.getBundleDirectory(id: next!)
521
+ if (!bundle.exist) {
522
+ return false
523
+ }
524
+ UserDefaults.standard.set(next, forKey: self.NEXT_VERSION)
525
+ self.setBundleStatus(id: next!, status: BundleStatus.PENDING);
526
+ }
527
+ UserDefaults.standard.synchronize()
528
+ return true
529
+ }
277
530
  }
@@ -11,8 +11,10 @@ CAP_PLUGIN(CapacitorUpdaterPlugin, "CapacitorUpdater",
11
11
  CAP_PLUGIN_METHOD(reset, CAPPluginReturnPromise);
12
12
  CAP_PLUGIN_METHOD(current, CAPPluginReturnPromise);
13
13
  CAP_PLUGIN_METHOD(reload, CAPPluginReturnPromise);
14
- CAP_PLUGIN_METHOD(versionName, CAPPluginReturnPromise);
15
14
  CAP_PLUGIN_METHOD(notifyAppReady, CAPPluginReturnPromise);
16
- CAP_PLUGIN_METHOD(delayUpdate, CAPPluginReturnPromise);
15
+ CAP_PLUGIN_METHOD(setDelay, CAPPluginReturnPromise);
17
16
  CAP_PLUGIN_METHOD(getId, CAPPluginReturnPromise);
17
+ CAP_PLUGIN_METHOD(getPluginVersion, CAPPluginReturnPromise);
18
+ CAP_PLUGIN_METHOD(next, CAPPluginReturnPromise);
19
+ CAP_PLUGIN_METHOD(isAutoUpdateEnabled, CAPPluginReturnPromise);
18
20
  )