@capgo/capacitor-updater 3.1.0 → 3.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.
- package/README.md +4 -4
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +229 -225
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +188 -182
- package/ios/Plugin/CapacitorUpdater.swift +71 -26
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +13 -9
- package/package.json +1 -1
|
@@ -22,6 +22,11 @@ public class AppVersion: NSObject {
|
|
|
22
22
|
var message: String?
|
|
23
23
|
var major: Bool?
|
|
24
24
|
}
|
|
25
|
+
extension OperatingSystemVersion {
|
|
26
|
+
func getFullVersion(separator: String = ".") -> String {
|
|
27
|
+
return "\(majorVersion)\(separator)\(minorVersion)\(separator)\(patchVersion)"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
25
30
|
extension Bundle {
|
|
26
31
|
var releaseVersionNumber: String? {
|
|
27
32
|
return infoDictionary?["CFBundleShortVersionString"] as? String
|
|
@@ -31,15 +36,36 @@ extension Bundle {
|
|
|
31
36
|
}
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
enum CustomError: Error {
|
|
40
|
+
// Throw when an unzip fail
|
|
41
|
+
case cannotUnzip
|
|
42
|
+
|
|
43
|
+
// Throw in all other cases
|
|
44
|
+
case unexpected(code: Int)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
extension CustomError: LocalizedError {
|
|
48
|
+
public var errorDescription: String? {
|
|
49
|
+
switch self {
|
|
50
|
+
case .cannotUnzip:
|
|
51
|
+
return NSLocalizedString(
|
|
52
|
+
"The file cannot be unzip",
|
|
53
|
+
comment: "Invalid zip"
|
|
54
|
+
)
|
|
55
|
+
case .unexpected(_):
|
|
56
|
+
return NSLocalizedString(
|
|
57
|
+
"An unexpected error occurred.",
|
|
58
|
+
comment: "Unexpected Error"
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
34
64
|
@objc public class CapacitorUpdater: NSObject {
|
|
35
65
|
|
|
36
|
-
public var statsUrl = ""
|
|
37
|
-
public var appId = ""
|
|
38
|
-
public var deviceID = UIDevice.current.identifierForVendor?.uuidString ?? ""
|
|
39
|
-
public var notifyDownload: (Int) -> Void = { _ in }
|
|
40
|
-
public var pluginVersion = "3.1.0"
|
|
41
66
|
private var versionBuild = Bundle.main.releaseVersionNumber ?? ""
|
|
42
67
|
private var versionCode = Bundle.main.buildVersionNumber ?? ""
|
|
68
|
+
private var versionOs = ProcessInfo().operatingSystemVersion.getFullVersion()
|
|
43
69
|
private var lastPathHot = ""
|
|
44
70
|
private var lastPathPersist = ""
|
|
45
71
|
private let basePathHot = "versions"
|
|
@@ -47,11 +73,17 @@ extension Bundle {
|
|
|
47
73
|
private let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
|
48
74
|
private let libraryUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
|
|
49
75
|
|
|
50
|
-
|
|
76
|
+
public var statsUrl = ""
|
|
77
|
+
public var appId = ""
|
|
78
|
+
public var deviceID = UIDevice.current.identifierForVendor?.uuidString ?? ""
|
|
79
|
+
public var notifyDownload: (Int) -> Void = { _ in }
|
|
80
|
+
public var pluginVersion = "3.2.0"
|
|
81
|
+
|
|
82
|
+
private func calcTotalPercent(percent: Int, min: Int, max: Int) -> Int {
|
|
51
83
|
return (percent * (max - min)) / 100 + min;
|
|
52
84
|
}
|
|
53
85
|
|
|
54
|
-
|
|
86
|
+
private func randomString(length: Int) -> String {
|
|
55
87
|
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
56
88
|
return String((0..<length).map{ _ in letters.randomElement()! })
|
|
57
89
|
}
|
|
@@ -95,17 +127,19 @@ extension Bundle {
|
|
|
95
127
|
}
|
|
96
128
|
}
|
|
97
129
|
|
|
98
|
-
private func saveDownloaded(sourceZip: URL, version: String, base: URL) {
|
|
130
|
+
private func saveDownloaded(sourceZip: URL, version: String, base: URL) throws {
|
|
99
131
|
prepareFolder(source: base)
|
|
100
132
|
let destHot = base.appendingPathComponent(version)
|
|
101
133
|
let destUnZip = documentsUrl.appendingPathComponent(randomString(length: 10))
|
|
102
|
-
SSZipArchive.unzipFile(atPath: sourceZip.path, toDestination: destUnZip.path)
|
|
134
|
+
if (!SSZipArchive.unzipFile(atPath: sourceZip.path, toDestination: destUnZip.path)) {
|
|
135
|
+
throw CustomError.cannotUnzip
|
|
136
|
+
}
|
|
103
137
|
if (unflatFolder(source: destUnZip, dest: destHot)) {
|
|
104
138
|
deleteFolder(source: destUnZip)
|
|
105
139
|
}
|
|
106
140
|
}
|
|
107
141
|
|
|
108
|
-
|
|
142
|
+
public func getLatest(url: URL) -> AppVersion? {
|
|
109
143
|
let semaphore = DispatchSemaphore(value: 0)
|
|
110
144
|
let latest = AppVersion()
|
|
111
145
|
let headers: HTTPHeaders = [
|
|
@@ -114,6 +148,7 @@ extension Bundle {
|
|
|
114
148
|
"cap_app_id": self.appId,
|
|
115
149
|
"cap_version_build": self.versionBuild,
|
|
116
150
|
"cap_version_code": self.versionCode,
|
|
151
|
+
"cap_version_os": self.versionOs,
|
|
117
152
|
"cap_plugin_version": self.pluginVersion,
|
|
118
153
|
"cap_version_name": UserDefaults.standard.string(forKey: "versionName") ?? "builtin"
|
|
119
154
|
]
|
|
@@ -143,9 +178,10 @@ extension Bundle {
|
|
|
143
178
|
return latest.url != "" ? latest : nil
|
|
144
179
|
}
|
|
145
180
|
|
|
146
|
-
|
|
181
|
+
public func download(url: URL) throws -> String {
|
|
147
182
|
let semaphore = DispatchSemaphore(value: 0)
|
|
148
|
-
var version: String
|
|
183
|
+
var version: String = ""
|
|
184
|
+
var mainError: NSError? = nil
|
|
149
185
|
let destination: DownloadRequest.Destination = { _, _ in
|
|
150
186
|
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
|
151
187
|
let fileURL = documentsURL.appendingPathComponent(self.randomString(length: 10))
|
|
@@ -164,24 +200,32 @@ extension Bundle {
|
|
|
164
200
|
case .success:
|
|
165
201
|
self.notifyDownload(71);
|
|
166
202
|
version = self.randomString(length: 10)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
203
|
+
do {
|
|
204
|
+
try self.saveDownloaded(sourceZip: fileURL, version: version, base: self.documentsUrl.appendingPathComponent(self.basePathHot))
|
|
205
|
+
self.notifyDownload(85);
|
|
206
|
+
try self.saveDownloaded(sourceZip: fileURL, version: version, base: self.libraryUrl.appendingPathComponent(self.basePathPersist))
|
|
207
|
+
self.notifyDownload(100);
|
|
208
|
+
self.deleteFolder(source: fileURL)
|
|
209
|
+
} catch {
|
|
210
|
+
print("✨ Capacitor-updater: download unzip error", error)
|
|
211
|
+
mainError = error as NSError
|
|
212
|
+
}
|
|
172
213
|
case let .failure(error):
|
|
173
214
|
print("✨ Capacitor-updater: download error", error)
|
|
174
|
-
|
|
215
|
+
mainError = error as NSError
|
|
175
216
|
}
|
|
176
217
|
}
|
|
177
218
|
semaphore.signal()
|
|
178
219
|
}
|
|
179
220
|
self.notifyDownload(0);
|
|
180
221
|
semaphore.wait()
|
|
222
|
+
if (mainError != nil) {
|
|
223
|
+
throw mainError!
|
|
224
|
+
}
|
|
181
225
|
return version
|
|
182
226
|
}
|
|
183
227
|
|
|
184
|
-
|
|
228
|
+
public func list() -> [String] {
|
|
185
229
|
let dest = documentsUrl.appendingPathComponent(basePathHot)
|
|
186
230
|
do {
|
|
187
231
|
let files = try FileManager.default.contentsOfDirectory(atPath: dest.path)
|
|
@@ -192,7 +236,7 @@ extension Bundle {
|
|
|
192
236
|
}
|
|
193
237
|
}
|
|
194
238
|
|
|
195
|
-
|
|
239
|
+
public func delete(version: String, versionName: String) -> Bool {
|
|
196
240
|
let destHot = documentsUrl.appendingPathComponent(basePathHot).appendingPathComponent(version)
|
|
197
241
|
let destPersist = libraryUrl.appendingPathComponent(basePathPersist).appendingPathComponent(version)
|
|
198
242
|
do {
|
|
@@ -210,7 +254,7 @@ extension Bundle {
|
|
|
210
254
|
return true
|
|
211
255
|
}
|
|
212
256
|
|
|
213
|
-
|
|
257
|
+
public func set(version: String, versionName: String) -> Bool {
|
|
214
258
|
let destHot = documentsUrl.appendingPathComponent(basePathHot).appendingPathComponent(version)
|
|
215
259
|
let indexHot = destHot.appendingPathComponent("index.html")
|
|
216
260
|
let destHotPersist = libraryUrl.appendingPathComponent(basePathPersist).appendingPathComponent(version)
|
|
@@ -226,19 +270,19 @@ extension Bundle {
|
|
|
226
270
|
return false
|
|
227
271
|
}
|
|
228
272
|
|
|
229
|
-
|
|
273
|
+
public func getLastPathHot() -> String {
|
|
230
274
|
return UserDefaults.standard.string(forKey: "lastPathHot") ?? ""
|
|
231
275
|
}
|
|
232
276
|
|
|
233
|
-
|
|
277
|
+
public func getVersionName() -> String {
|
|
234
278
|
return UserDefaults.standard.string(forKey: "versionName") ?? ""
|
|
235
279
|
}
|
|
236
280
|
|
|
237
|
-
|
|
281
|
+
public func getLastPathPersist() -> String {
|
|
238
282
|
return UserDefaults.standard.string(forKey: "lastPathPersist") ?? ""
|
|
239
283
|
}
|
|
240
284
|
|
|
241
|
-
|
|
285
|
+
public func reset() {
|
|
242
286
|
let version = UserDefaults.standard.string(forKey: "versionName") ?? ""
|
|
243
287
|
sendStats(action: "reset", version: version)
|
|
244
288
|
UserDefaults.standard.set("", forKey: "lastPathHot")
|
|
@@ -247,7 +291,7 @@ extension Bundle {
|
|
|
247
291
|
UserDefaults.standard.synchronize()
|
|
248
292
|
}
|
|
249
293
|
|
|
250
|
-
|
|
294
|
+
func sendStats(action: String, version: String) {
|
|
251
295
|
if (statsUrl == "") { return }
|
|
252
296
|
let parameters: [String: String] = [
|
|
253
297
|
"platform": "ios",
|
|
@@ -256,6 +300,7 @@ extension Bundle {
|
|
|
256
300
|
"version_name": version,
|
|
257
301
|
"version_build": self.versionBuild,
|
|
258
302
|
"version_code": self.versionCode,
|
|
303
|
+
"version_os": self.versionOs,
|
|
259
304
|
"plugin_version": self.pluginVersion,
|
|
260
305
|
"app_id": self.appId
|
|
261
306
|
]
|
|
@@ -65,16 +65,20 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
65
65
|
@objc func getId(_ call: CAPPluginCall) {
|
|
66
66
|
call.resolve(["id": implementation.deviceID])
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
@objc func getPluginVersion(_ call: CAPPluginCall) {
|
|
70
|
+
call.resolve(["version": implementation.pluginVersion])
|
|
71
|
+
}
|
|
68
72
|
|
|
69
73
|
@objc func download(_ call: CAPPluginCall) {
|
|
70
74
|
let url = URL(string: call.getString("url") ?? "")
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
do {
|
|
76
|
+
let res = try implementation.download(url: url!)
|
|
73
77
|
call.resolve([
|
|
74
|
-
"version": res
|
|
78
|
+
"version": res
|
|
75
79
|
])
|
|
76
|
-
}
|
|
77
|
-
call.reject("download failed")
|
|
80
|
+
} catch {
|
|
81
|
+
call.reject("download failed", error.localizedDescription)
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
|
|
@@ -221,14 +225,14 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
221
225
|
print("✨ Capacitor-updater: Cannot get version \(failingVersion) \(newVersion)")
|
|
222
226
|
}
|
|
223
227
|
if (newVersion != "0.0.0" && newVersion != failingVersion) {
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
do {
|
|
229
|
+
let dl = try self.implementation.download(url: downloadUrl)
|
|
226
230
|
print("✨ Capacitor-updater: New version: \(newVersion) found. Current is \(currentVersion == "" ? "builtin" : currentVersion), next backgrounding will trigger update")
|
|
227
231
|
UserDefaults.standard.set(dl, forKey: "nextVersion")
|
|
228
232
|
UserDefaults.standard.set(newVersion.description, forKey: "nextVersionName")
|
|
229
233
|
self.notifyListeners("updateAvailable", data: ["version": newVersion])
|
|
230
|
-
}
|
|
231
|
-
print("✨ Capacitor-updater: Download version \(newVersion) fail")
|
|
234
|
+
} catch {
|
|
235
|
+
print("✨ Capacitor-updater: Download version \(newVersion) fail", error.localizedDescription)
|
|
232
236
|
}
|
|
233
237
|
} else {
|
|
234
238
|
print("✨ Capacitor-updater: No need to update, \(currentVersion) is the latest")
|