@capgo/capacitor-updater 3.3.12 → 4.0.0-alpha.1
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/LICENCE +656 -160
- package/README.md +200 -137
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +130 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleStatus.java +36 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +316 -198
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +454 -244
- package/dist/docs.json +509 -121
- package/dist/esm/definitions.d.ts +201 -76
- package/dist/esm/web.d.ts +18 -16
- package/dist/esm/web.js +26 -24
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +26 -24
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +26 -24
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/BundleInfo.swift +94 -0
- package/ios/Plugin/BundleStatus.swift +41 -0
- package/ios/Plugin/CapacitorUpdater.swift +298 -82
- package/ios/Plugin/CapacitorUpdaterPlugin.m +3 -2
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +270 -163
- package/ios/Plugin/ObjectPreferences.swift +97 -0
- package/package.json +3 -2
|
@@ -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,9 +41,43 @@ 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
|
+
|
|
39
75
|
enum CustomError: Error {
|
|
40
76
|
// Throw when an unzip fail
|
|
41
77
|
case cannotUnzip
|
|
78
|
+
case cannotUnflat
|
|
79
|
+
case cannotCreateDirectory
|
|
80
|
+
case cannotDeleteDirectory
|
|
42
81
|
|
|
43
82
|
// Throw in all other cases
|
|
44
83
|
case unexpected(code: Int)
|
|
@@ -52,6 +91,21 @@ extension CustomError: LocalizedError {
|
|
|
52
91
|
"The file cannot be unzip",
|
|
53
92
|
comment: "Invalid zip"
|
|
54
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
|
+
)
|
|
55
109
|
case .unexpected(_):
|
|
56
110
|
return NSLocalizedString(
|
|
57
111
|
"An unexpected error occurred.",
|
|
@@ -63,21 +117,29 @@ extension CustomError: LocalizedError {
|
|
|
63
117
|
|
|
64
118
|
@objc public class CapacitorUpdater: NSObject {
|
|
65
119
|
|
|
66
|
-
private
|
|
67
|
-
private
|
|
68
|
-
private
|
|
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
|
+
|
|
69
132
|
private var lastPathHot = ""
|
|
70
133
|
private var lastPathPersist = ""
|
|
71
|
-
private let basePathHot = "versions"
|
|
72
|
-
private let basePathPersist = "NoCloud/ionic_built_snapshots"
|
|
73
|
-
private let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
|
74
|
-
private let libraryUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
|
|
75
134
|
|
|
135
|
+
public let TAG = "✨ Capacitor-updater:";
|
|
136
|
+
public let CAP_SERVER_PATH = "serverBasePath"
|
|
137
|
+
public let pluginVersion = "4.0.0-alpha.1"
|
|
76
138
|
public var statsUrl = ""
|
|
77
139
|
public var appId = ""
|
|
78
140
|
public var deviceID = UIDevice.current.identifierForVendor?.uuidString ?? ""
|
|
79
|
-
|
|
80
|
-
public var
|
|
141
|
+
|
|
142
|
+
public var notifyDownload: (String, Int) -> Void = { _,_ in }
|
|
81
143
|
|
|
82
144
|
private func calcTotalPercent(percent: Int, min: Int, max: Int) -> Int {
|
|
83
145
|
return (percent * (max - min)) / 100 + min;
|
|
@@ -92,25 +154,27 @@ extension CustomError: LocalizedError {
|
|
|
92
154
|
// Hot Reload path /var/mobile/Containers/Data/Application/8C0C07BE-0FD3-4FD4-B7DF-90A88E12B8C3/Documents/FOLDER
|
|
93
155
|
// Normal /private/var/containers/Bundle/Application/8C0C07BE-0FD3-4FD4-B7DF-90A88E12B8C3/App.app/public
|
|
94
156
|
|
|
95
|
-
private func prepareFolder(source: URL) {
|
|
157
|
+
private func prepareFolder(source: URL) throws {
|
|
96
158
|
if (!FileManager.default.fileExists(atPath: source.path)) {
|
|
97
159
|
do {
|
|
98
160
|
try FileManager.default.createDirectory(atPath: source.path, withIntermediateDirectories: true, attributes: nil)
|
|
99
161
|
} catch {
|
|
100
|
-
print("
|
|
162
|
+
print("\(self.TAG) Cannot createDirectory \(source.path)")
|
|
163
|
+
throw CustomError.cannotCreateDirectory
|
|
101
164
|
}
|
|
102
165
|
}
|
|
103
166
|
}
|
|
104
167
|
|
|
105
|
-
private func deleteFolder(source: URL) {
|
|
168
|
+
private func deleteFolder(source: URL) throws {
|
|
106
169
|
do {
|
|
107
170
|
try FileManager.default.removeItem(atPath: source.path)
|
|
108
171
|
} catch {
|
|
109
|
-
print("
|
|
172
|
+
print("\(self.TAG) File not removed. \(source.path)")
|
|
173
|
+
throw CustomError.cannotDeleteDirectory
|
|
110
174
|
}
|
|
111
175
|
}
|
|
112
176
|
|
|
113
|
-
private func unflatFolder(source: URL, dest: URL) -> Bool {
|
|
177
|
+
private func unflatFolder(source: URL, dest: URL) throws -> Bool {
|
|
114
178
|
let index = source.appendingPathComponent("index.html")
|
|
115
179
|
do {
|
|
116
180
|
let files = try FileManager.default.contentsOfDirectory(atPath: source.path)
|
|
@@ -122,37 +186,37 @@ extension CustomError: LocalizedError {
|
|
|
122
186
|
return false
|
|
123
187
|
}
|
|
124
188
|
} catch {
|
|
125
|
-
print("
|
|
126
|
-
|
|
189
|
+
print("\(self.TAG) File not moved. source: \(source.path) dest: \(dest.path)")
|
|
190
|
+
throw CustomError.cannotUnflat
|
|
127
191
|
}
|
|
128
192
|
}
|
|
129
193
|
|
|
130
|
-
private func saveDownloaded(sourceZip: URL,
|
|
131
|
-
prepareFolder(source: base)
|
|
132
|
-
let destHot = base.appendingPathComponent(
|
|
133
|
-
let 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))
|
|
134
198
|
if (!SSZipArchive.unzipFile(atPath: sourceZip.path, toDestination: destUnZip.path)) {
|
|
135
199
|
throw CustomError.cannotUnzip
|
|
136
200
|
}
|
|
137
|
-
if (unflatFolder(source: destUnZip, dest: destHot)) {
|
|
138
|
-
deleteFolder(source: destUnZip)
|
|
201
|
+
if (try unflatFolder(source: destUnZip, dest: destHot)) {
|
|
202
|
+
try deleteFolder(source: destUnZip)
|
|
139
203
|
}
|
|
140
204
|
}
|
|
141
205
|
|
|
142
206
|
public func getLatest(url: URL) -> AppVersion? {
|
|
143
207
|
let semaphore = DispatchSemaphore(value: 0)
|
|
144
208
|
let latest = AppVersion()
|
|
145
|
-
let
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
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()
|
|
154
218
|
]
|
|
155
|
-
let request = AF.request(url,
|
|
219
|
+
let request = AF.request(url, method: .post,parameters: parameters, encoder: JSONParameterEncoder.default)
|
|
156
220
|
|
|
157
221
|
request.validate().responseDecodable(of: AppVersionDec.self) { response in
|
|
158
222
|
switch response.result {
|
|
@@ -168,9 +232,10 @@ extension CustomError: LocalizedError {
|
|
|
168
232
|
}
|
|
169
233
|
if let message = response.value?.message {
|
|
170
234
|
latest.message = message
|
|
235
|
+
print("\(self.TAG) Auto-update message: \(message)")
|
|
171
236
|
}
|
|
172
237
|
case let .failure(error):
|
|
173
|
-
print("
|
|
238
|
+
print("\(self.TAG) Error getting Latest", error )
|
|
174
239
|
}
|
|
175
240
|
semaphore.signal()
|
|
176
241
|
}
|
|
@@ -178,9 +243,15 @@ extension CustomError: LocalizedError {
|
|
|
178
243
|
return latest.url != "" ? latest : nil
|
|
179
244
|
}
|
|
180
245
|
|
|
181
|
-
|
|
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 {
|
|
182
253
|
let semaphore = DispatchSemaphore(value: 0)
|
|
183
|
-
|
|
254
|
+
let id: String = self.randomString(length: 10)
|
|
184
255
|
var mainError: NSError? = nil
|
|
185
256
|
let destination: DownloadRequest.Destination = { _, _ in
|
|
186
257
|
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
|
@@ -192,112 +263,143 @@ extension CustomError: LocalizedError {
|
|
|
192
263
|
|
|
193
264
|
request.downloadProgress { progress in
|
|
194
265
|
let percent = self.calcTotalPercent(percent: Int(progress.fractionCompleted * 100), min: 10, max: 70)
|
|
195
|
-
self.notifyDownload(percent)
|
|
266
|
+
self.notifyDownload(id, percent)
|
|
196
267
|
}
|
|
197
268
|
request.responseURL { (response) in
|
|
198
269
|
if let fileURL = response.fileURL {
|
|
199
270
|
switch response.result {
|
|
200
271
|
case .success:
|
|
201
|
-
self.notifyDownload(71)
|
|
202
|
-
version = self.randomString(length: 10)
|
|
272
|
+
self.notifyDownload(id, 71)
|
|
203
273
|
do {
|
|
204
|
-
try self.saveDownloaded(sourceZip: fileURL,
|
|
205
|
-
self.notifyDownload(85)
|
|
206
|
-
try self.saveDownloaded(sourceZip: fileURL,
|
|
207
|
-
self.notifyDownload(100)
|
|
208
|
-
self.deleteFolder(source: fileURL)
|
|
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)
|
|
209
279
|
} catch {
|
|
210
|
-
print("
|
|
280
|
+
print("\(self.TAG) download unzip error", error)
|
|
211
281
|
mainError = error as NSError
|
|
212
282
|
}
|
|
213
283
|
case let .failure(error):
|
|
214
|
-
print("
|
|
284
|
+
print("\(self.TAG) download error", error)
|
|
215
285
|
mainError = error as NSError
|
|
216
286
|
}
|
|
217
287
|
}
|
|
218
288
|
semaphore.signal()
|
|
219
289
|
}
|
|
220
|
-
self.
|
|
290
|
+
self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.DOWNLOADING, downloaded: Date()))
|
|
291
|
+
self.notifyDownload(id, 0)
|
|
221
292
|
semaphore.wait()
|
|
222
293
|
if (mainError != nil) {
|
|
223
294
|
throw mainError!
|
|
224
295
|
}
|
|
225
|
-
|
|
296
|
+
let info: BundleInfo = BundleInfo(id: id, version: version, status: BundleStatus.PENDING, downloaded: Date())
|
|
297
|
+
self.saveBundleInfo(id: id, bundle: info)
|
|
298
|
+
return info
|
|
226
299
|
}
|
|
227
300
|
|
|
228
|
-
public func list() -> [
|
|
229
|
-
let dest =
|
|
301
|
+
public func list() -> [BundleInfo] {
|
|
302
|
+
let dest = documentsDir.appendingPathComponent(bundleDirectoryHot)
|
|
230
303
|
do {
|
|
231
304
|
let files = try FileManager.default.contentsOfDirectory(atPath: dest.path)
|
|
232
|
-
|
|
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
|
|
233
313
|
} catch {
|
|
234
|
-
print("
|
|
314
|
+
print("\(self.TAG) No version available \(dest.path)")
|
|
235
315
|
return []
|
|
236
316
|
}
|
|
237
317
|
}
|
|
238
318
|
|
|
239
|
-
public func delete(
|
|
240
|
-
let
|
|
241
|
-
let
|
|
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)
|
|
242
323
|
do {
|
|
243
324
|
try FileManager.default.removeItem(atPath: destHot.path)
|
|
244
325
|
} catch {
|
|
245
|
-
print("
|
|
326
|
+
print("\(self.TAG) Hot Folder \(destHot.path), not removed.")
|
|
246
327
|
}
|
|
247
328
|
do {
|
|
248
329
|
try FileManager.default.removeItem(atPath: destPersist.path)
|
|
249
330
|
} catch {
|
|
250
|
-
print("
|
|
331
|
+
print("\(self.TAG) Folder \(destPersist.path), not removed.")
|
|
251
332
|
return false
|
|
252
333
|
}
|
|
253
|
-
|
|
334
|
+
self.removeBundleInfo(id: id)
|
|
335
|
+
self.sendStats(action: "delete", bundle: deleted)
|
|
254
336
|
return true
|
|
255
337
|
}
|
|
256
338
|
|
|
257
|
-
public func
|
|
258
|
-
|
|
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)
|
|
259
350
|
let indexHot = destHot.appendingPathComponent("index.html")
|
|
260
|
-
let destHotPersist = libraryUrl.appendingPathComponent(basePathPersist).appendingPathComponent(version)
|
|
261
351
|
let indexPersist = destHotPersist.appendingPathComponent("index.html")
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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)
|
|
267
359
|
return true
|
|
268
360
|
}
|
|
269
|
-
sendStats(action: "set_fail",
|
|
361
|
+
sendStats(action: "set_fail", bundle: existing)
|
|
270
362
|
return false
|
|
271
363
|
}
|
|
272
364
|
|
|
273
|
-
public func
|
|
274
|
-
return
|
|
365
|
+
public func getPathHot(id: String) -> URL {
|
|
366
|
+
return documentsDir.appendingPathComponent(self.bundleDirectoryHot).appendingPathComponent(id)
|
|
275
367
|
}
|
|
276
368
|
|
|
277
|
-
public func
|
|
278
|
-
return
|
|
369
|
+
public func getPathPersist(id: String) -> URL {
|
|
370
|
+
return libraryDir.appendingPathComponent(self.bundleDirectory).appendingPathComponent(id)
|
|
279
371
|
}
|
|
280
372
|
|
|
281
|
-
public func
|
|
282
|
-
|
|
373
|
+
public func reset() {
|
|
374
|
+
self.reset(isInternal: false)
|
|
283
375
|
}
|
|
284
376
|
|
|
285
|
-
public func reset() {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
UserDefaults.standard.set("", forKey: "lastPathPersist")
|
|
290
|
-
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)
|
|
291
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);
|
|
292
394
|
}
|
|
293
395
|
|
|
294
|
-
func sendStats(action: String,
|
|
396
|
+
func sendStats(action: String, bundle: BundleInfo) {
|
|
295
397
|
if (statsUrl == "") { return }
|
|
296
398
|
let parameters: [String: String] = [
|
|
297
399
|
"platform": "ios",
|
|
298
400
|
"action": action,
|
|
299
401
|
"device_id": self.deviceID,
|
|
300
|
-
"version_name":
|
|
402
|
+
"version_name": bundle.getVersionName(),
|
|
301
403
|
"version_build": self.versionBuild,
|
|
302
404
|
"version_code": self.versionCode,
|
|
303
405
|
"version_os": self.versionOs,
|
|
@@ -307,8 +409,122 @@ extension CustomError: LocalizedError {
|
|
|
307
409
|
|
|
308
410
|
DispatchQueue.global(qos: .background).async {
|
|
309
411
|
let _ = AF.request(self.statsUrl, method: .post,parameters: parameters, encoder: JSONParameterEncoder.default)
|
|
310
|
-
print("
|
|
412
|
+
print("\(self.TAG) Stats send for \(action), version \(bundle.getVersionName())")
|
|
311
413
|
}
|
|
312
414
|
}
|
|
313
|
-
|
|
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
|
+
}
|
|
314
530
|
}
|
|
@@ -11,9 +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(
|
|
15
|
+
CAP_PLUGIN_METHOD(setDelay, CAPPluginReturnPromise);
|
|
17
16
|
CAP_PLUGIN_METHOD(getId, CAPPluginReturnPromise);
|
|
18
17
|
CAP_PLUGIN_METHOD(getPluginVersion, CAPPluginReturnPromise);
|
|
18
|
+
CAP_PLUGIN_METHOD(next, CAPPluginReturnPromise);
|
|
19
|
+
CAP_PLUGIN_METHOD(isAutoUpdateEnabled, CAPPluginReturnPromise);
|
|
19
20
|
)
|