@capgo/capacitor-updater 8.0.0 → 8.1.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/CapgoCapacitorUpdater.podspec +7 -5
- package/Package.swift +37 -0
- package/README.md +1461 -231
- package/android/build.gradle +29 -12
- package/android/proguard-rules.pro +45 -0
- package/android/src/main/AndroidManifest.xml +0 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +223 -195
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleStatus.java +23 -23
- package/android/src/main/java/ee/forgr/capacitor_updater/Callback.java +13 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +2159 -1234
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +1507 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +330 -121
- package/android/src/main/java/ee/forgr/capacitor_updater/DataManager.java +28 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayCondition.java +43 -49
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayUntilNext.java +4 -4
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayUpdateUtils.java +260 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/DeviceIdHelper.java +221 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +808 -117
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadWorkerManager.java +156 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/InternalUtils.java +32 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/Logger.java +338 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeDetector.java +72 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +169 -0
- package/dist/docs.json +2187 -625
- package/dist/esm/definitions.d.ts +1286 -249
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/history.d.ts +1 -0
- package/dist/esm/history.js +283 -0
- package/dist/esm/history.js.map +1 -0
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +5 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +36 -41
- package/dist/esm/web.js +94 -35
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +376 -35
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +376 -35
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/AES.swift +69 -0
- package/ios/Sources/CapacitorUpdaterPlugin/BigInt.swift +55 -0
- package/ios/{Plugin → Sources/CapacitorUpdaterPlugin}/BundleInfo.swift +37 -10
- package/ios/{Plugin → Sources/CapacitorUpdaterPlugin}/BundleStatus.swift +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +1605 -0
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +1526 -0
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +267 -0
- package/ios/Sources/CapacitorUpdaterPlugin/DelayUpdateUtils.swift +220 -0
- package/ios/Sources/CapacitorUpdaterPlugin/DeviceIdHelper.swift +120 -0
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +311 -0
- package/ios/Sources/CapacitorUpdaterPlugin/Logger.swift +310 -0
- package/ios/Sources/CapacitorUpdaterPlugin/RSA.swift +274 -0
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +112 -0
- package/ios/{Plugin → Sources/CapacitorUpdaterPlugin}/UserDefaultsExtension.swift +0 -2
- package/package.json +41 -35
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +0 -1130
- package/ios/Plugin/CapacitorUpdater.swift +0 -858
- package/ios/Plugin/CapacitorUpdaterPlugin.h +0 -10
- package/ios/Plugin/CapacitorUpdaterPlugin.m +0 -27
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +0 -675
- package/ios/Plugin/CryptoCipher.swift +0 -240
- /package/{LICENCE → LICENSE} +0 -0
- /package/ios/{Plugin → Sources/CapacitorUpdaterPlugin}/DelayCondition.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorUpdaterPlugin}/DelayUntilNext.swift +0 -0
- /package/ios/{Plugin → Sources/CapacitorUpdaterPlugin}/Info.plist +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import BigInt
|
|
2
|
+
import Foundation
|
|
3
|
+
import CommonCrypto
|
|
4
|
+
import CryptoKit
|
|
5
|
+
|
|
6
|
+
///
|
|
7
|
+
/// Constants
|
|
8
|
+
///
|
|
9
|
+
private enum RSAConstants {
|
|
10
|
+
static let rsaKeySizeInBits: NSNumber = 2048
|
|
11
|
+
static let rsaAlgorithm: SecKeyAlgorithm = .rsaEncryptionOAEPSHA256
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// We do all this stuff because ios is shit and open source libraries allow to do decryption with public key
|
|
15
|
+
// So we have to do it manually, while in nodejs or Java it's ok and done at language level.
|
|
16
|
+
|
|
17
|
+
///
|
|
18
|
+
/// The RSA public key.
|
|
19
|
+
///
|
|
20
|
+
public struct RSAPublicKey {
|
|
21
|
+
private let manualKey: ManualRSAPublicKey
|
|
22
|
+
|
|
23
|
+
fileprivate init(manualKey: ManualRSAPublicKey) {
|
|
24
|
+
self.manualKey = manualKey
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
///
|
|
28
|
+
/// Takes the data and uses the public key to decrypt it.
|
|
29
|
+
/// Returns the decrypted data.
|
|
30
|
+
///
|
|
31
|
+
public func decrypt(data: Data) -> Data? {
|
|
32
|
+
return manualKey.decrypt(data)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
///
|
|
36
|
+
/// Allows you to load an RSA public key (i.e. one downloaded from the net).
|
|
37
|
+
///
|
|
38
|
+
public static func load(rsaPublicKey: String) -> RSAPublicKey? {
|
|
39
|
+
// Clean up the key string
|
|
40
|
+
var pubKey: String = rsaPublicKey
|
|
41
|
+
pubKey = pubKey.replacingOccurrences(of: "-----BEGIN RSA PUBLIC KEY-----", with: "")
|
|
42
|
+
pubKey = pubKey.replacingOccurrences(of: "-----END RSA PUBLIC KEY-----", with: "")
|
|
43
|
+
pubKey = pubKey.replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----", with: "")
|
|
44
|
+
pubKey = pubKey.replacingOccurrences(of: "-----END PUBLIC KEY-----", with: "")
|
|
45
|
+
pubKey = pubKey.replacingOccurrences(of: "\\n+", with: "", options: .regularExpression)
|
|
46
|
+
pubKey = pubKey.replacingOccurrences(of: "\n", with: "")
|
|
47
|
+
pubKey = pubKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
48
|
+
|
|
49
|
+
do {
|
|
50
|
+
guard let rsaPublicKeyData: Data = Data(base64Encoded: String(pubKey)) else {
|
|
51
|
+
throw CustomError.cannotDecode
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Try parsing as PKCS#1
|
|
55
|
+
if let manualKey = ManualRSAPublicKey.fromPKCS1(rsaPublicKeyData) {
|
|
56
|
+
return RSAPublicKey(manualKey: manualKey)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Most common public exponent is 65537 (0x010001)
|
|
60
|
+
let commonExponent = Data([0x01, 0x00, 0x01]) // 65537 in big-endian
|
|
61
|
+
|
|
62
|
+
// Assume the entire key data is the modulus
|
|
63
|
+
let lastResortKey = ManualRSAPublicKey(modulus: rsaPublicKeyData, exponent: commonExponent)
|
|
64
|
+
return RSAPublicKey(manualKey: lastResortKey)
|
|
65
|
+
} catch {
|
|
66
|
+
return nil
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Manual RSA Public Key Implementation using the BigInt library
|
|
72
|
+
struct ManualRSAPublicKey {
|
|
73
|
+
let modulus: BigInt
|
|
74
|
+
let exponent: BigInt
|
|
75
|
+
|
|
76
|
+
init(modulus: Data, exponent: Data) {
|
|
77
|
+
// Create positive BigInts from Data
|
|
78
|
+
let modulusBytes = [UInt8](modulus)
|
|
79
|
+
var modulusValue = BigUInt(0)
|
|
80
|
+
for byte in modulusBytes {
|
|
81
|
+
modulusValue = (modulusValue << 8) | BigUInt(byte)
|
|
82
|
+
}
|
|
83
|
+
self.modulus = BigInt(modulusValue)
|
|
84
|
+
let exponentBytes = [UInt8](exponent)
|
|
85
|
+
var exponentValue = BigUInt(0)
|
|
86
|
+
for byte in exponentBytes {
|
|
87
|
+
exponentValue = (exponentValue << 8) | BigUInt(byte)
|
|
88
|
+
}
|
|
89
|
+
self.exponent = BigInt(exponentValue)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Parse PKCS#1 format public key
|
|
93
|
+
static func fromPKCS1(_ publicKeyData: Data) -> ManualRSAPublicKey? {
|
|
94
|
+
// Parse ASN.1 DER encoded RSA public key
|
|
95
|
+
// Format: RSAPublicKey ::= SEQUENCE { modulus INTEGER, publicExponent INTEGER }
|
|
96
|
+
|
|
97
|
+
guard publicKeyData.count > 0 else {
|
|
98
|
+
return nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let bytes = [UInt8](publicKeyData)
|
|
102
|
+
|
|
103
|
+
// Check for sequence tag (0x30)
|
|
104
|
+
guard bytes[0] == 0x30 else {
|
|
105
|
+
// Try direct modulus/exponent approach as fallback
|
|
106
|
+
if publicKeyData.count >= 3 {
|
|
107
|
+
// Assume this is a raw RSA public key with modulus + exponent
|
|
108
|
+
// Most common: modulus is 256 bytes (2048 bits), exponent is 3 bytes (0x010001 = 65537)
|
|
109
|
+
let modulusSize = publicKeyData.count - 3
|
|
110
|
+
if modulusSize > 0 {
|
|
111
|
+
let modulusData = publicKeyData.prefix(modulusSize)
|
|
112
|
+
let exponentData = publicKeyData.suffix(3)
|
|
113
|
+
return ManualRSAPublicKey(modulus: modulusData, exponent: exponentData)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return nil
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var index = 1
|
|
121
|
+
|
|
122
|
+
// Skip length
|
|
123
|
+
if bytes[index] & 0x80 != 0 {
|
|
124
|
+
let lenBytes = Int(bytes[index] & 0x7F)
|
|
125
|
+
if (index + 1 + lenBytes) >= bytes.count {
|
|
126
|
+
return nil
|
|
127
|
+
}
|
|
128
|
+
index += 1 + lenBytes
|
|
129
|
+
} else {
|
|
130
|
+
index += 1
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check for INTEGER tag for modulus (0x02)
|
|
134
|
+
if index >= bytes.count {
|
|
135
|
+
return nil
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
guard bytes[index] == 0x02 else {
|
|
139
|
+
return nil
|
|
140
|
+
}
|
|
141
|
+
index += 1
|
|
142
|
+
|
|
143
|
+
// Get modulus length
|
|
144
|
+
if index >= bytes.count {
|
|
145
|
+
return nil
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
var modulusLength = 0
|
|
149
|
+
if bytes[index] & 0x80 != 0 {
|
|
150
|
+
let lenBytes = Int(bytes[index] & 0x7F)
|
|
151
|
+
if (index + 1 + lenBytes) >= bytes.count {
|
|
152
|
+
return nil
|
|
153
|
+
}
|
|
154
|
+
index += 1
|
|
155
|
+
for i in 0..<lenBytes {
|
|
156
|
+
modulusLength = (modulusLength << 8) | Int(bytes[index + i])
|
|
157
|
+
}
|
|
158
|
+
index += lenBytes
|
|
159
|
+
} else {
|
|
160
|
+
modulusLength = Int(bytes[index])
|
|
161
|
+
index += 1
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Skip any leading zero in modulus (for unsigned integer)
|
|
165
|
+
if index < bytes.count && bytes[index] == 0x00 {
|
|
166
|
+
index += 1
|
|
167
|
+
modulusLength -= 1
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Extract modulus
|
|
171
|
+
if (index + modulusLength) > bytes.count {
|
|
172
|
+
return nil
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let modulusData = Data(bytes[index..<(index + modulusLength)])
|
|
176
|
+
index += modulusLength
|
|
177
|
+
|
|
178
|
+
// Check for INTEGER tag for exponent
|
|
179
|
+
if index >= bytes.count {
|
|
180
|
+
return nil
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
guard bytes[index] == 0x02 else {
|
|
184
|
+
return nil
|
|
185
|
+
}
|
|
186
|
+
index += 1
|
|
187
|
+
|
|
188
|
+
// Get exponent length
|
|
189
|
+
if index >= bytes.count {
|
|
190
|
+
return nil
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var exponentLength = 0
|
|
194
|
+
if bytes[index] & 0x80 != 0 {
|
|
195
|
+
let lenBytes = Int(bytes[index] & 0x7F)
|
|
196
|
+
if (index + 1 + lenBytes) >= bytes.count {
|
|
197
|
+
return nil
|
|
198
|
+
}
|
|
199
|
+
index += 1
|
|
200
|
+
for i in 0..<lenBytes {
|
|
201
|
+
exponentLength = (exponentLength << 8) | Int(bytes[index + i])
|
|
202
|
+
}
|
|
203
|
+
index += lenBytes
|
|
204
|
+
} else {
|
|
205
|
+
exponentLength = Int(bytes[index])
|
|
206
|
+
index += 1
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Extract exponent
|
|
210
|
+
if (index + exponentLength) > bytes.count {
|
|
211
|
+
return nil
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let exponentData = Data(bytes[index..<(index + exponentLength)])
|
|
215
|
+
return ManualRSAPublicKey(modulus: modulusData, exponent: exponentData)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Decrypt data using raw RSA operation (c^d mod n)
|
|
219
|
+
func decrypt(_ encryptedData: Data) -> Data? {
|
|
220
|
+
// Create positive BigInt from encrypted data
|
|
221
|
+
let encryptedBytes = [UInt8](encryptedData)
|
|
222
|
+
var encryptedValue = BigUInt(0)
|
|
223
|
+
for byte in encryptedBytes {
|
|
224
|
+
encryptedValue = (encryptedValue << 8) | BigUInt(byte)
|
|
225
|
+
}
|
|
226
|
+
let encrypted = BigInt(encryptedValue)
|
|
227
|
+
|
|
228
|
+
// In Node.js:
|
|
229
|
+
// privateEncrypt uses the private key (d) to encrypt
|
|
230
|
+
// publicDecrypt uses the public key (e) to decrypt
|
|
231
|
+
// The operation we want is: ciphertext^e mod n
|
|
232
|
+
|
|
233
|
+
// RSA operation: c^e mod n
|
|
234
|
+
let decrypted = encrypted.manualPower(exponent, modulus: modulus)
|
|
235
|
+
|
|
236
|
+
// Convert to bytes with proper padding
|
|
237
|
+
guard let bigUIntValue = decrypted.magnitude as? BigUInt else {
|
|
238
|
+
return nil
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Convert BigUInt to bytes with padding
|
|
242
|
+
var resultBytes = [UInt8]()
|
|
243
|
+
var tempValue = bigUIntValue
|
|
244
|
+
while tempValue > 0 {
|
|
245
|
+
let byte = UInt8(tempValue & 0xFF)
|
|
246
|
+
resultBytes.insert(byte, at: 0) // Prepend to get big-endian
|
|
247
|
+
tempValue >>= 8
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Ensure we have at least 256 bytes (2048 bits) with leading zeros
|
|
251
|
+
let paddedBytes = [UInt8](repeating: 0, count: max(0, 256 - resultBytes.count)) + resultBytes
|
|
252
|
+
|
|
253
|
+
// For PKCS1 padding from Node.js privateEncrypt, the format is:
|
|
254
|
+
// 0x00 || 0x01 || PS || 0x00 || actual data
|
|
255
|
+
// where PS is a string of 0xFF bytes
|
|
256
|
+
|
|
257
|
+
// Check for privateEncrypt padding format (0x00 || 0x01 || PS || 0x00)
|
|
258
|
+
var startIndex = 0
|
|
259
|
+
if paddedBytes.count > 2 && paddedBytes[0] == 0x00 && paddedBytes[1] == 0x01 {
|
|
260
|
+
for i in 2..<paddedBytes.count {
|
|
261
|
+
if paddedBytes[i] == 0x00 {
|
|
262
|
+
startIndex = i + 1
|
|
263
|
+
break
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if startIndex < paddedBytes.count {
|
|
268
|
+
let result = Data(paddedBytes[startIndex...])
|
|
269
|
+
return result
|
|
270
|
+
} else {
|
|
271
|
+
return Data(paddedBytes)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import UIKit
|
|
8
|
+
import Capacitor
|
|
9
|
+
|
|
10
|
+
extension UIApplication {
|
|
11
|
+
public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
|
|
12
|
+
if let nav = base as? UINavigationController {
|
|
13
|
+
return topViewController(nav.visibleViewController)
|
|
14
|
+
}
|
|
15
|
+
if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
|
|
16
|
+
return topViewController(selected)
|
|
17
|
+
}
|
|
18
|
+
if let presented = base?.presentedViewController {
|
|
19
|
+
return topViewController(presented)
|
|
20
|
+
}
|
|
21
|
+
return base
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
extension UIWindow {
|
|
26
|
+
override open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
|
|
27
|
+
if motion == .motionShake {
|
|
28
|
+
// Find the CapacitorUpdaterPlugin instance
|
|
29
|
+
guard let bridge = (rootViewController as? CAPBridgeProtocol),
|
|
30
|
+
let plugin = bridge.plugin(withName: "CapacitorUpdaterPlugin") as? CapacitorUpdaterPlugin else {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check if shake menu is enabled
|
|
35
|
+
if !plugin.shakeMenuEnabled {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
showShakeMenu(plugin: plugin, bridge: bridge)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private func showShakeMenu(plugin: CapacitorUpdaterPlugin, bridge: CAPBridgeProtocol) {
|
|
44
|
+
// Prevent multiple alerts from showing
|
|
45
|
+
if let topVC = UIApplication.topViewController(),
|
|
46
|
+
topVC.isKind(of: UIAlertController.self) {
|
|
47
|
+
plugin.logger.info("UIAlertController is already presented")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "App"
|
|
52
|
+
let title = "Preview \(appName) Menu"
|
|
53
|
+
let message = "What would you like to do?"
|
|
54
|
+
let okButtonTitle = "Go Home"
|
|
55
|
+
let reloadButtonTitle = "Reload app"
|
|
56
|
+
let cancelButtonTitle = "Close menu"
|
|
57
|
+
|
|
58
|
+
let updater = plugin.implementation
|
|
59
|
+
|
|
60
|
+
func resetBuiltin() {
|
|
61
|
+
updater.reset()
|
|
62
|
+
bridge.setServerBasePath("")
|
|
63
|
+
DispatchQueue.main.async {
|
|
64
|
+
if let vc = (self.rootViewController as? CAPBridgeViewController) {
|
|
65
|
+
vc.loadView()
|
|
66
|
+
vc.viewDidLoad()
|
|
67
|
+
}
|
|
68
|
+
_ = updater.delete(id: updater.getCurrentBundleId())
|
|
69
|
+
plugin.logger.info("Reset to builtin version")
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let bundleId = updater.getCurrentBundleId()
|
|
74
|
+
if let vc = (self.rootViewController as? CAPBridgeViewController) {
|
|
75
|
+
plugin.logger.info("getServerBasePath: \(vc.getServerBasePath())")
|
|
76
|
+
}
|
|
77
|
+
plugin.logger.info("bundleId: \(bundleId)")
|
|
78
|
+
|
|
79
|
+
let alertShake = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
|
80
|
+
|
|
81
|
+
alertShake.addAction(UIAlertAction(title: okButtonTitle, style: .default) { _ in
|
|
82
|
+
guard let next = updater.getNextBundle() else {
|
|
83
|
+
resetBuiltin()
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
if !next.isBuiltin() {
|
|
87
|
+
plugin.logger.info("Resetting to: \(next.toString())")
|
|
88
|
+
_ = updater.set(bundle: next)
|
|
89
|
+
let destHot = updater.getBundleDirectory(id: next.getId())
|
|
90
|
+
plugin.logger.info("Reloading \(next.toString())")
|
|
91
|
+
bridge.setServerBasePath(destHot.path)
|
|
92
|
+
} else {
|
|
93
|
+
resetBuiltin()
|
|
94
|
+
}
|
|
95
|
+
plugin.logger.info("Reload app done")
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
alertShake.addAction(UIAlertAction(title: cancelButtonTitle, style: .default))
|
|
99
|
+
|
|
100
|
+
alertShake.addAction(UIAlertAction(title: reloadButtonTitle, style: .default) { _ in
|
|
101
|
+
DispatchQueue.main.async {
|
|
102
|
+
bridge.webView?.reload()
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
DispatchQueue.main.async {
|
|
107
|
+
if let topVC = UIApplication.topViewController() {
|
|
108
|
+
topVC.present(alertShake, animated: true)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -34,9 +34,7 @@ extension UserDefaults: ObjectSavable {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
func getObj<Object>(forKey: String, castTo type: Object.Type) throws -> Object where Object: Decodable {
|
|
37
|
-
// print("forKey", forKey)
|
|
38
37
|
guard let data: Data = data(forKey: forKey) else { throw ObjectSavableError.noValue }
|
|
39
|
-
// print("data", data)
|
|
40
38
|
let decoder: JSONDecoder = JSONDecoder()
|
|
41
39
|
do {
|
|
42
40
|
let object: Object = try decoder.decode(type, from: data)
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-updater",
|
|
3
|
-
"version": "8.
|
|
4
|
-
"packageManager": "pnpm@8.5.1",
|
|
3
|
+
"version": "8.1.0",
|
|
5
4
|
"license": "MPL-2.0",
|
|
6
5
|
"description": "Live update for capacitor apps",
|
|
7
6
|
"main": "dist/plugin.cjs.js",
|
|
@@ -10,12 +9,14 @@
|
|
|
10
9
|
"unpkg": "dist/plugin.js",
|
|
11
10
|
"files": [
|
|
12
11
|
"android/src/main/",
|
|
12
|
+
"android/proguard-rules.pro",
|
|
13
13
|
"android/build.gradle",
|
|
14
14
|
"dist/",
|
|
15
|
-
"ios/
|
|
16
|
-
"CapgoCapacitorUpdater.podspec"
|
|
15
|
+
"ios/Sources/",
|
|
16
|
+
"CapgoCapacitorUpdater.podspec",
|
|
17
|
+
"Package.swift"
|
|
17
18
|
],
|
|
18
|
-
"author": "Martin Donadieu",
|
|
19
|
+
"author": "Martin Donadieu <martin@capgo.app>",
|
|
19
20
|
"repository": {
|
|
20
21
|
"type": "git",
|
|
21
22
|
"url": "git+https://github.com/Cap-go/capacitor-updater.git"
|
|
@@ -25,56 +26,61 @@
|
|
|
25
26
|
},
|
|
26
27
|
"keywords": [
|
|
27
28
|
"capacitor",
|
|
28
|
-
"
|
|
29
|
-
"OTA",
|
|
30
|
-
"manual update",
|
|
29
|
+
"live updates",
|
|
31
30
|
"live update",
|
|
31
|
+
"updates",
|
|
32
32
|
"auto update",
|
|
33
|
+
"manual update",
|
|
34
|
+
"capgo",
|
|
35
|
+
"plugin",
|
|
36
|
+
"OTA",
|
|
33
37
|
"ionic",
|
|
34
38
|
"appflow alternative",
|
|
35
|
-
"
|
|
39
|
+
"capawesome alternative",
|
|
40
|
+
"@capawesome/capacitor-live-update",
|
|
36
41
|
"native"
|
|
37
42
|
],
|
|
38
43
|
"scripts": {
|
|
39
44
|
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
40
|
-
"verify:ios": "
|
|
45
|
+
"verify:ios": "xcodebuild -scheme CapgoCapacitorUpdater -destination generic/platform=iOS",
|
|
41
46
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
42
47
|
"verify:web": "npm run build",
|
|
48
|
+
"test": "npm run test:ios && npm run test:android",
|
|
49
|
+
"test:ios": "./scripts/test-ios.sh",
|
|
50
|
+
"test:android": "cd android && ./gradlew test && cd ..",
|
|
43
51
|
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
44
|
-
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --
|
|
45
|
-
"eslint": "eslint . --ext ts",
|
|
46
|
-
"prettier": "prettier
|
|
52
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
53
|
+
"eslint": "eslint . --ext .ts",
|
|
54
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
47
55
|
"swiftlint": "node-swiftlint",
|
|
48
|
-
"docgen": "
|
|
49
|
-
"docgen:api": "docgen --api CapacitorUpdaterPlugin --output-readme api.md --output-json dist/docs.json && awk '{sub(/###/,\"##\")}1' api.md > temp.txt && mv temp.txt api.md",
|
|
56
|
+
"docgen": "node scripts/generate-docs.js",
|
|
50
57
|
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
51
58
|
"clean": "rimraf ./dist",
|
|
52
59
|
"watch": "tsc --watch",
|
|
53
60
|
"prepublishOnly": "npm run build"
|
|
54
61
|
},
|
|
55
62
|
"devDependencies": {
|
|
56
|
-
"@capacitor/android": "^
|
|
57
|
-
"@capacitor/cli": "^
|
|
58
|
-
"@capacitor/core": "^
|
|
59
|
-
"@capacitor/docgen": "^0.
|
|
60
|
-
"@capacitor/ios": "^
|
|
61
|
-
"@ionic/eslint-config": "^0.
|
|
62
|
-
"@ionic/prettier-config": "^
|
|
63
|
-
"@ionic/swiftlint-config": "^
|
|
64
|
-
"@types/node": "^
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"prettier": "^2.
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"typescript": "^5.0.4"
|
|
63
|
+
"@capacitor/android": "^8.0.0",
|
|
64
|
+
"@capacitor/cli": "^8.0.0",
|
|
65
|
+
"@capacitor/core": "^8.0.0",
|
|
66
|
+
"@capacitor/docgen": "^0.3.0",
|
|
67
|
+
"@capacitor/ios": "^8.0.0",
|
|
68
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
69
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
70
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
71
|
+
"@types/node": "^24.3.0",
|
|
72
|
+
"eslint": "^8.57.0",
|
|
73
|
+
"eslint-plugin-import": "^2.32.0",
|
|
74
|
+
"husky": "^9.1.7",
|
|
75
|
+
"prettier": "^3.6.2",
|
|
76
|
+
"prettier-plugin-java": "^2.7.4",
|
|
77
|
+
"rimraf": "^6.0.1",
|
|
78
|
+
"rollup": "^4.50.0",
|
|
79
|
+
"swiftlint": "^2.0.0",
|
|
80
|
+
"typescript": "^5.9.2"
|
|
75
81
|
},
|
|
76
82
|
"peerDependencies": {
|
|
77
|
-
"@capacitor/core": "^
|
|
83
|
+
"@capacitor/core": "^8.0.0"
|
|
78
84
|
},
|
|
79
85
|
"prettier": "@ionic/prettier-config",
|
|
80
86
|
"swiftlint": "@ionic/swiftlint-config",
|