@capawesome/cordova-live-update 0.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/LICENSE +21 -0
- package/README.md +1113 -0
- package/dist/docs.json +1654 -0
- package/dist/esm/definitions.d.ts +788 -0
- package/dist/esm/definitions.js +7 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/exec.d.ts +1 -0
- package/dist/esm/exec.js +8 -0
- package/dist/esm/exec.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +46 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/plugin.js +56 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +93 -0
- package/plugin.xml +268 -0
- package/src/android/capawesome-cordova-live-update.gradle +12 -0
- package/src/android/capawesome-live-update.xml +5 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdate.java +1480 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdateConfig.java +105 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdateHttpClient.java +114 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdatePathHandler.java +96 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdatePlugin.java +550 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdatePreferences.java +151 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/Manifest.java +58 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/ManifestItem.java +37 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/api/GetChannelsResponseItem.java +28 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/api/GetLatestBundleResponse.java +74 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/events/DownloadBundleProgressEvent.java +33 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/events/NextBundleSetEvent.java +26 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/DeleteBundleOptions.java +18 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/DownloadBundleOptions.java +66 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/FetchChannelsOptions.java +39 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/FetchLatestBundleOptions.java +25 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetChannelOptions.java +18 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetConfigOptions.java +20 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetCustomIdOptions.java +18 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetNextBundleOptions.java +21 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SyncOptions.java +25 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/ChannelResult.java +29 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/FetchChannelsResult.java +29 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/FetchLatestBundleResult.java +69 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetBlockedBundlesResult.java +28 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetBundlesResult.java +28 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetChannelResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetConfigResult.java +40 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetCurrentBundleResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetCustomIdResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetDeviceIdResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetDownloadedBundlesResult.java +28 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetNextBundleResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetVersionCodeResult.java +21 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetVersionNameResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/IsSyncingResult.java +27 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/ReadyResult.java +32 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/SyncResult.java +22 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/enums/ArtifactType.java +6 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/Callback.java +5 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/DownloadProgressCallback.java +5 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/EmptyCallback.java +5 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/NonEmptyCallback.java +7 -0
- package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/Result.java +8 -0
- package/src/ios/LiveUpdate.swift +895 -0
- package/src/ios/LiveUpdateArtifactType.swift +4 -0
- package/src/ios/LiveUpdateChannelResult.swift +18 -0
- package/src/ios/LiveUpdateConfig.swift +11 -0
- package/src/ios/LiveUpdateDeleteBundleOptions.swift +13 -0
- package/src/ios/LiveUpdateDownloadBundleOptions.swift +41 -0
- package/src/ios/LiveUpdateDownloadBundleProgressEvent.swift +24 -0
- package/src/ios/LiveUpdateError.swift +62 -0
- package/src/ios/LiveUpdateFetchChannelsOptions.swift +25 -0
- package/src/ios/LiveUpdateFetchChannelsResult.swift +15 -0
- package/src/ios/LiveUpdateFetchLatestBundleOptions.swift +17 -0
- package/src/ios/LiveUpdateFetchLatestBundleResult.swift +42 -0
- package/src/ios/LiveUpdateGetBlockedBundlesResult.swift +15 -0
- package/src/ios/LiveUpdateGetBundlesResult.swift +15 -0
- package/src/ios/LiveUpdateGetChannelResult.swift +15 -0
- package/src/ios/LiveUpdateGetChannelsResponseItem.swift +4 -0
- package/src/ios/LiveUpdateGetConfigResult.swift +18 -0
- package/src/ios/LiveUpdateGetCurrentBundleResult.swift +15 -0
- package/src/ios/LiveUpdateGetCustomIdResult.swift +15 -0
- package/src/ios/LiveUpdateGetDeviceIdResult.swift +15 -0
- package/src/ios/LiveUpdateGetDownloadedBundlesResult.swift +15 -0
- package/src/ios/LiveUpdateGetLatestBundleResponse.swift +8 -0
- package/src/ios/LiveUpdateGetNextBundleResult.swift +15 -0
- package/src/ios/LiveUpdateGetVersionCodeResult.swift +15 -0
- package/src/ios/LiveUpdateGetVersionNameResult.swift +15 -0
- package/src/ios/LiveUpdateHttpClient.swift +58 -0
- package/src/ios/LiveUpdateIsSyncingResult.swift +15 -0
- package/src/ios/LiveUpdateManifest.swift +19 -0
- package/src/ios/LiveUpdateManifestItem.swift +5 -0
- package/src/ios/LiveUpdateNextBundleSetEvent.swift +15 -0
- package/src/ios/LiveUpdatePlugin.swift +521 -0
- package/src/ios/LiveUpdatePreferences.swift +116 -0
- package/src/ios/LiveUpdateReadyResult.swift +21 -0
- package/src/ios/LiveUpdateResult.swift +5 -0
- package/src/ios/LiveUpdateSchemeHandler.swift +286 -0
- package/src/ios/LiveUpdateSetChannelOptions.swift +13 -0
- package/src/ios/LiveUpdateSetConfigOptions.swift +13 -0
- package/src/ios/LiveUpdateSetCustomIdOptions.swift +13 -0
- package/src/ios/LiveUpdateSetNextBundleOptions.swift +13 -0
- package/src/ios/LiveUpdateSyncOptions.swift +17 -0
- package/src/ios/LiveUpdateSyncResult.swift +15 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import Cordova
|
|
2
|
+
import Foundation
|
|
3
|
+
import UIKit
|
|
4
|
+
import WebKit
|
|
5
|
+
|
|
6
|
+
@objc(CapawesomeLiveUpdatePlugin)
|
|
7
|
+
public class LiveUpdatePlugin: CDVPlugin, CDVPluginSchemeHandler {
|
|
8
|
+
public static let tag = "LiveUpdate"
|
|
9
|
+
public static let version = "0.1.0"
|
|
10
|
+
public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
|
|
11
|
+
|
|
12
|
+
private let eventDownloadBundleProgress = "downloadBundleProgress"
|
|
13
|
+
private let eventNextBundleSet = "nextBundleSet"
|
|
14
|
+
|
|
15
|
+
private static let errorAppIdMissing = "appId must be configured."
|
|
16
|
+
private static let errorBundleIdMissing = "bundleId must be provided."
|
|
17
|
+
private static let errorCustomIdMissing = "customId must be provided."
|
|
18
|
+
private static let errorUrlMissing = "url must be provided."
|
|
19
|
+
private static let errorListenerIdMissing = "listenerId must be provided."
|
|
20
|
+
private static let errorPluginNotInitialized = "LiveUpdate plugin failed to initialize."
|
|
21
|
+
private static let errorHttpTimeout = "Request timed out."
|
|
22
|
+
|
|
23
|
+
private var config: LiveUpdateConfig?
|
|
24
|
+
private var implementation: LiveUpdate?
|
|
25
|
+
private var schemeHandler: LiveUpdateSchemeHandler?
|
|
26
|
+
|
|
27
|
+
private struct ListenerRegistration {
|
|
28
|
+
let eventName: String
|
|
29
|
+
let callbackId: String
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private let listenersLock = NSLock()
|
|
33
|
+
private var listeners: [String: ListenerRegistration] = [:]
|
|
34
|
+
|
|
35
|
+
public override func pluginInitialize() {
|
|
36
|
+
super.pluginInitialize()
|
|
37
|
+
let cfg = loadConfig()
|
|
38
|
+
let handler = LiveUpdateSchemeHandler()
|
|
39
|
+
let impl = LiveUpdate(config: cfg, plugin: self, schemeHandler: handler)
|
|
40
|
+
self.config = cfg
|
|
41
|
+
self.schemeHandler = handler
|
|
42
|
+
self.implementation = impl
|
|
43
|
+
impl.handleLoad()
|
|
44
|
+
|
|
45
|
+
NotificationCenter.default.addObserver(
|
|
46
|
+
self,
|
|
47
|
+
selector: #selector(handleAppWillEnterForeground),
|
|
48
|
+
name: UIApplication.willEnterForegroundNotification,
|
|
49
|
+
object: nil
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// MARK: - CDVPluginSchemeHandler conformance
|
|
54
|
+
|
|
55
|
+
public func overrideSchemeTask(_ task: WKURLSchemeTask) -> Bool {
|
|
56
|
+
return schemeHandler?.handle(task: task) ?? false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public func stop(_ task: WKURLSchemeTask) {
|
|
60
|
+
schemeHandler?.stop(task: task)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// MARK: - Plugin → JS notify methods (called by LiveUpdate)
|
|
64
|
+
|
|
65
|
+
func notifyDownloadBundleProgressListeners(_ event: LiveUpdateDownloadBundleProgressEvent) {
|
|
66
|
+
notifyJSListeners(eventName: eventDownloadBundleProgress, data: event.toJSObject())
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func notifyNextBundleSetListeners(_ event: LiveUpdateNextBundleSetEvent) {
|
|
70
|
+
notifyJSListeners(eventName: eventNextBundleSet, data: event.toJSObject())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public func reloadWebView() {
|
|
74
|
+
DispatchQueue.main.async { [weak self] in
|
|
75
|
+
guard let webView = self?.webViewEngine?.engineWebView as? WKWebView else {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
webView.reload()
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@objc private func handleAppWillEnterForeground() {
|
|
83
|
+
implementation?.handleAppWillEnterForeground()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// MARK: - Action methods
|
|
87
|
+
|
|
88
|
+
@objc(clearBlockedBundles:)
|
|
89
|
+
func clearBlockedBundles(_ command: CDVInvokedUrlCommand) {
|
|
90
|
+
guard let impl = implementation else {
|
|
91
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
impl.clearBlockedBundles()
|
|
95
|
+
resolve(command)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@objc(deleteBundle:)
|
|
99
|
+
func deleteBundle(_ command: CDVInvokedUrlCommand) {
|
|
100
|
+
guard let impl = implementation else {
|
|
101
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
let options = optionsDict(from: command)
|
|
105
|
+
guard let bundleId = string(options, "bundleId") else {
|
|
106
|
+
reject(command, message: Self.errorBundleIdMissing)
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
impl.deleteBundle(LiveUpdateDeleteBundleOptions(bundleId: bundleId)) { [weak self] error in
|
|
110
|
+
self?.completeEmpty(command, error: error)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@objc(downloadBundle:)
|
|
115
|
+
func downloadBundle(_ command: CDVInvokedUrlCommand) {
|
|
116
|
+
guard let impl = implementation else {
|
|
117
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
let options = optionsDict(from: command)
|
|
121
|
+
let artifactType = (options["artifactType"] as? String) ?? "zip"
|
|
122
|
+
guard let bundleId = string(options, "bundleId") else {
|
|
123
|
+
reject(command, message: Self.errorBundleIdMissing)
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
let checksum = string(options, "checksum")
|
|
127
|
+
let signature = string(options, "signature")
|
|
128
|
+
guard let url = string(options, "url") else {
|
|
129
|
+
reject(command, message: Self.errorUrlMissing)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
Task {
|
|
133
|
+
do {
|
|
134
|
+
try await impl.downloadBundle(LiveUpdateDownloadBundleOptions(
|
|
135
|
+
artifactType: artifactType,
|
|
136
|
+
bundleId: bundleId,
|
|
137
|
+
checksum: checksum,
|
|
138
|
+
signature: signature,
|
|
139
|
+
url: url
|
|
140
|
+
))
|
|
141
|
+
resolve(command)
|
|
142
|
+
} catch {
|
|
143
|
+
reject(command, error: error)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@objc(fetchChannels:)
|
|
149
|
+
func fetchChannels(_ command: CDVInvokedUrlCommand) {
|
|
150
|
+
guard let impl = implementation, let cfg = config else {
|
|
151
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
guard let appId = cfg.appId, !appId.isEmpty else {
|
|
155
|
+
reject(command, message: Self.errorAppIdMissing)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
let options = optionsDict(from: command)
|
|
159
|
+
Task {
|
|
160
|
+
do {
|
|
161
|
+
let result = try await impl.fetchChannels(LiveUpdateFetchChannelsOptions(options))
|
|
162
|
+
resolve(command, data: result.toJSObject())
|
|
163
|
+
} catch {
|
|
164
|
+
reject(command, error: error)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@objc(fetchLatestBundle:)
|
|
170
|
+
func fetchLatestBundle(_ command: CDVInvokedUrlCommand) {
|
|
171
|
+
guard let impl = implementation, let cfg = config else {
|
|
172
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
guard let appId = cfg.appId, !appId.isEmpty else {
|
|
176
|
+
reject(command, message: Self.errorAppIdMissing)
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
let options = optionsDict(from: command)
|
|
180
|
+
Task {
|
|
181
|
+
do {
|
|
182
|
+
let result = try await impl.fetchLatestBundle(LiveUpdateFetchLatestBundleOptions(options))
|
|
183
|
+
resolve(command, data: result.toJSObject())
|
|
184
|
+
} catch {
|
|
185
|
+
reject(command, error: error)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@objc(getBlockedBundles:)
|
|
191
|
+
func getBlockedBundles(_ command: CDVInvokedUrlCommand) {
|
|
192
|
+
completeResult(command) { impl, completion in impl.getBlockedBundles(completion: completion) }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@objc(getBundles:)
|
|
196
|
+
func getBundles(_ command: CDVInvokedUrlCommand) {
|
|
197
|
+
completeResult(command) { impl, completion in impl.getBundles(completion: completion) }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@objc(getChannel:)
|
|
201
|
+
func getChannel(_ command: CDVInvokedUrlCommand) {
|
|
202
|
+
completeResult(command) { impl, completion in impl.getChannel(completion: completion) }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@objc(getConfig:)
|
|
206
|
+
func getConfig(_ command: CDVInvokedUrlCommand) {
|
|
207
|
+
completeResult(command) { impl, completion in impl.getConfig(completion: completion) }
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@objc(getCurrentBundle:)
|
|
211
|
+
func getCurrentBundle(_ command: CDVInvokedUrlCommand) {
|
|
212
|
+
completeResult(command) { impl, completion in impl.getCurrentBundle(completion: completion) }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@objc(getCustomId:)
|
|
216
|
+
func getCustomId(_ command: CDVInvokedUrlCommand) {
|
|
217
|
+
completeResult(command) { impl, completion in impl.getCustomId(completion: completion) }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@objc(getDeviceId:)
|
|
221
|
+
func getDeviceId(_ command: CDVInvokedUrlCommand) {
|
|
222
|
+
completeResult(command) { impl, completion in impl.getDeviceId(completion: completion) }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@objc(getDownloadedBundles:)
|
|
226
|
+
func getDownloadedBundles(_ command: CDVInvokedUrlCommand) {
|
|
227
|
+
completeResult(command) { impl, completion in impl.getDownloadedBundles(completion: completion) }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@objc(getNextBundle:)
|
|
231
|
+
func getNextBundle(_ command: CDVInvokedUrlCommand) {
|
|
232
|
+
completeResult(command) { impl, completion in impl.getNextBundle(completion: completion) }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@objc(getVersionCode:)
|
|
236
|
+
func getVersionCode(_ command: CDVInvokedUrlCommand) {
|
|
237
|
+
completeResult(command) { impl, completion in impl.getVersionCode(completion: completion) }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@objc(getVersionName:)
|
|
241
|
+
func getVersionName(_ command: CDVInvokedUrlCommand) {
|
|
242
|
+
completeResult(command) { impl, completion in impl.getVersionName(completion: completion) }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@objc(isSyncing:)
|
|
246
|
+
func isSyncing(_ command: CDVInvokedUrlCommand) {
|
|
247
|
+
completeResult(command) { impl, completion in impl.isSyncing(completion: completion) }
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@objc(ready:)
|
|
251
|
+
func ready(_ command: CDVInvokedUrlCommand) {
|
|
252
|
+
completeResult(command) { impl, completion in impl.ready(completion: completion) }
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@objc(reload:)
|
|
256
|
+
func reload(_ command: CDVInvokedUrlCommand) {
|
|
257
|
+
guard let impl = implementation else {
|
|
258
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
impl.reload()
|
|
262
|
+
resolve(command)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@objc(reset:)
|
|
266
|
+
func reset(_ command: CDVInvokedUrlCommand) {
|
|
267
|
+
guard let impl = implementation else {
|
|
268
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
impl.reset()
|
|
272
|
+
resolve(command)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@objc(resetConfig:)
|
|
276
|
+
func resetConfig(_ command: CDVInvokedUrlCommand) {
|
|
277
|
+
guard let impl = implementation else {
|
|
278
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
impl.resetConfig()
|
|
282
|
+
resolve(command)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@objc(setChannel:)
|
|
286
|
+
func setChannel(_ command: CDVInvokedUrlCommand) {
|
|
287
|
+
guard let impl = implementation else {
|
|
288
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
let options = optionsDict(from: command)
|
|
292
|
+
let channel = string(options, "channel")
|
|
293
|
+
impl.setChannel(LiveUpdateSetChannelOptions(channel: channel)) { [weak self] error in
|
|
294
|
+
self?.completeEmpty(command, error: error)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@objc(setConfig:)
|
|
299
|
+
func setConfig(_ command: CDVInvokedUrlCommand) {
|
|
300
|
+
guard let impl = implementation else {
|
|
301
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
let options = optionsDict(from: command)
|
|
305
|
+
impl.setConfig(LiveUpdateSetConfigOptions(options))
|
|
306
|
+
resolve(command)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@objc(setCustomId:)
|
|
310
|
+
func setCustomId(_ command: CDVInvokedUrlCommand) {
|
|
311
|
+
guard let impl = implementation else {
|
|
312
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
let options = optionsDict(from: command)
|
|
316
|
+
guard let customId = string(options, "customId") else {
|
|
317
|
+
reject(command, message: Self.errorCustomIdMissing)
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
impl.setCustomId(LiveUpdateSetCustomIdOptions(customId: customId)) { [weak self] error in
|
|
321
|
+
self?.completeEmpty(command, error: error)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@objc(setNextBundle:)
|
|
326
|
+
func setNextBundle(_ command: CDVInvokedUrlCommand) {
|
|
327
|
+
guard let impl = implementation else {
|
|
328
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
let options = optionsDict(from: command)
|
|
332
|
+
impl.setNextBundle(LiveUpdateSetNextBundleOptions(options)) { [weak self] error in
|
|
333
|
+
self?.completeEmpty(command, error: error)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
@objc(sync:)
|
|
338
|
+
func sync(_ command: CDVInvokedUrlCommand) {
|
|
339
|
+
guard let impl = implementation, let cfg = config else {
|
|
340
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
341
|
+
return
|
|
342
|
+
}
|
|
343
|
+
guard let appId = cfg.appId, !appId.isEmpty else {
|
|
344
|
+
reject(command, message: Self.errorAppIdMissing)
|
|
345
|
+
return
|
|
346
|
+
}
|
|
347
|
+
let options = optionsDict(from: command)
|
|
348
|
+
Task {
|
|
349
|
+
do {
|
|
350
|
+
let result = try await impl.sync(LiveUpdateSyncOptions(options))
|
|
351
|
+
resolve(command, data: result.toJSObject())
|
|
352
|
+
} catch {
|
|
353
|
+
reject(command, error: error)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
@objc(addListener:)
|
|
359
|
+
func addListener(_ command: CDVInvokedUrlCommand) {
|
|
360
|
+
guard let eventName = command.argument(at: 0) as? String,
|
|
361
|
+
let listenerId = command.argument(at: 1) as? String else {
|
|
362
|
+
reject(command, message: Self.errorListenerIdMissing)
|
|
363
|
+
return
|
|
364
|
+
}
|
|
365
|
+
listenersLock.lock()
|
|
366
|
+
listeners[listenerId] = ListenerRegistration(eventName: eventName, callbackId: command.callbackId)
|
|
367
|
+
listenersLock.unlock()
|
|
368
|
+
// Keep the callback alive so we can deliver future events to it.
|
|
369
|
+
let result = CDVPluginResult(status: .noResult)
|
|
370
|
+
result.keepCallback = NSNumber(value: true)
|
|
371
|
+
commandDelegate.send(result, callbackId: command.callbackId)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
@objc(removeListener:)
|
|
375
|
+
func removeListener(_ command: CDVInvokedUrlCommand) {
|
|
376
|
+
let options = optionsDict(from: command)
|
|
377
|
+
guard let listenerId = string(options, "listenerId") else {
|
|
378
|
+
reject(command, message: Self.errorListenerIdMissing)
|
|
379
|
+
return
|
|
380
|
+
}
|
|
381
|
+
listenersLock.lock()
|
|
382
|
+
let removed = listeners.removeValue(forKey: listenerId)
|
|
383
|
+
listenersLock.unlock()
|
|
384
|
+
if let removed = removed {
|
|
385
|
+
// Release the JS callback that was kept alive by addListener.
|
|
386
|
+
let release = CDVPluginResult(status: .noResult)
|
|
387
|
+
release.keepCallback = NSNumber(value: false)
|
|
388
|
+
commandDelegate.send(release, callbackId: removed.callbackId)
|
|
389
|
+
}
|
|
390
|
+
resolve(command)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@objc(removeAllListeners:)
|
|
394
|
+
func removeAllListeners(_ command: CDVInvokedUrlCommand) {
|
|
395
|
+
listenersLock.lock()
|
|
396
|
+
let toRelease = Array(listeners.values)
|
|
397
|
+
listeners.removeAll()
|
|
398
|
+
listenersLock.unlock()
|
|
399
|
+
for entry in toRelease {
|
|
400
|
+
let release = CDVPluginResult(status: .noResult)
|
|
401
|
+
release.keepCallback = NSNumber(value: false)
|
|
402
|
+
commandDelegate.send(release, callbackId: entry.callbackId)
|
|
403
|
+
}
|
|
404
|
+
resolve(command)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// MARK: - Helpers
|
|
408
|
+
|
|
409
|
+
private func notifyJSListeners(eventName: String, data: [String: Any]) {
|
|
410
|
+
listenersLock.lock()
|
|
411
|
+
let recipients = listeners.values.filter { $0.eventName == eventName }
|
|
412
|
+
listenersLock.unlock()
|
|
413
|
+
for entry in recipients {
|
|
414
|
+
let result = CDVPluginResult(status: .ok, messageAs: data)
|
|
415
|
+
result.keepCallback = NSNumber(value: true)
|
|
416
|
+
commandDelegate.send(result, callbackId: entry.callbackId)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private func optionsDict(from command: CDVInvokedUrlCommand) -> [String: Any] {
|
|
421
|
+
return (command.argument(at: 0) as? [String: Any]) ?? [:]
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private func string(_ options: [String: Any], _ key: String) -> String? {
|
|
425
|
+
guard let value = options[key] as? String, !value.isEmpty else { return nil }
|
|
426
|
+
return value
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
private func completeEmpty(_ command: CDVInvokedUrlCommand, error: Error?) {
|
|
430
|
+
if let error = error {
|
|
431
|
+
reject(command, error: error)
|
|
432
|
+
} else {
|
|
433
|
+
resolve(command)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private func completeResult(
|
|
438
|
+
_ command: CDVInvokedUrlCommand,
|
|
439
|
+
_ invoke: (LiveUpdate, @escaping (LiveUpdateResult?, Error?) -> Void) -> Void
|
|
440
|
+
) {
|
|
441
|
+
guard let impl = implementation else {
|
|
442
|
+
reject(command, message: Self.errorPluginNotInitialized)
|
|
443
|
+
return
|
|
444
|
+
}
|
|
445
|
+
invoke(impl) { [weak self] result, error in
|
|
446
|
+
if let error = error {
|
|
447
|
+
self?.reject(command, error: error)
|
|
448
|
+
return
|
|
449
|
+
}
|
|
450
|
+
if let result = result {
|
|
451
|
+
self?.resolve(command, data: result.toJSObject())
|
|
452
|
+
} else {
|
|
453
|
+
self?.resolve(command)
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private func resolve(_ command: CDVInvokedUrlCommand) {
|
|
459
|
+
let result = CDVPluginResult(status: .ok)
|
|
460
|
+
commandDelegate.send(result, callbackId: command.callbackId)
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
private func resolve(_ command: CDVInvokedUrlCommand, data: [String: Any]) {
|
|
464
|
+
let result = CDVPluginResult(status: .ok, messageAs: data)
|
|
465
|
+
commandDelegate.send(result, callbackId: command.callbackId)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private func reject(_ command: CDVInvokedUrlCommand, message: String) {
|
|
469
|
+
let result = CDVPluginResult(status: .error, messageAs: message)
|
|
470
|
+
commandDelegate.send(result, callbackId: command.callbackId)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
private func reject(_ command: CDVInvokedUrlCommand, error: Error) {
|
|
474
|
+
var message = error.localizedDescription
|
|
475
|
+
if let urlError = error as? URLError, urlError.code == .timedOut {
|
|
476
|
+
message = Self.errorHttpTimeout
|
|
477
|
+
}
|
|
478
|
+
NSLog("[\(Self.tag)] \(message)")
|
|
479
|
+
reject(command, message: message)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
private func loadConfig() -> LiveUpdateConfig {
|
|
483
|
+
var cfg = LiveUpdateConfig()
|
|
484
|
+
let info = Bundle.main.infoDictionary ?? [:]
|
|
485
|
+
// Note: plist keys keep the `CapawesomeLiveUpdate` prefix because that
|
|
486
|
+
// is the external contract injected by plugin.xml `<config-file>`
|
|
487
|
+
// entries. Cordova-lib's `default=" "` sentinel becomes a single-space
|
|
488
|
+
// string in the host app's Info.plist; we trim and treat whitespace-only
|
|
489
|
+
// as unset.
|
|
490
|
+
if let appId = trimmed(info["CapawesomeLiveUpdateAppId"]) { cfg.appId = appId }
|
|
491
|
+
if let defaultChannel = trimmed(info["CapawesomeLiveUpdateDefaultChannel"]) { cfg.defaultChannel = defaultChannel }
|
|
492
|
+
if let strategy = trimmed(info["CapawesomeLiveUpdateAutoUpdateStrategy"]) { cfg.autoUpdateStrategy = strategy }
|
|
493
|
+
if let timeout = parseInt(info["CapawesomeLiveUpdateHttpTimeout"]) { cfg.httpTimeout = timeout }
|
|
494
|
+
if let publicKey = trimmed(info["CapawesomeLiveUpdatePublicKey"]) { cfg.publicKey = publicKey }
|
|
495
|
+
if let timeout = parseInt(info["CapawesomeLiveUpdateReadyTimeout"]) { cfg.readyTimeout = timeout }
|
|
496
|
+
if let domain = trimmed(info["CapawesomeLiveUpdateServerDomain"]) { cfg.serverDomain = domain }
|
|
497
|
+
if let value = parseBool(info["CapawesomeLiveUpdateAutoDeleteBundles"]) { cfg.autoDeleteBundles = value }
|
|
498
|
+
if let value = parseBool(info["CapawesomeLiveUpdateAutoBlockRolledBackBundles"]) { cfg.autoBlockRolledBackBundles = value }
|
|
499
|
+
return cfg
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private func trimmed(_ value: Any?) -> String? {
|
|
503
|
+
guard let string = value as? String else { return nil }
|
|
504
|
+
let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
505
|
+
return trimmed.isEmpty ? nil : trimmed
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private func parseInt(_ value: Any?) -> Int? {
|
|
509
|
+
if let s = value as? String, let i = Int(s) { return i }
|
|
510
|
+
if let i = value as? Int { return i }
|
|
511
|
+
if let n = value as? NSNumber { return n.intValue }
|
|
512
|
+
return nil
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private func parseBool(_ value: Any?) -> Bool? {
|
|
516
|
+
if let s = value as? String { return (s as NSString).boolValue }
|
|
517
|
+
if let b = value as? Bool { return b }
|
|
518
|
+
if let n = value as? NSNumber { return n.boolValue }
|
|
519
|
+
return nil
|
|
520
|
+
}
|
|
521
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
public class LiveUpdatePreferences: NSObject {
|
|
4
|
+
private let appIdKey = "appId" // DO NOT CHANGE
|
|
5
|
+
private let blockedBundleIdsKey = "blockedBundleIds" // DO NOT CHANGE
|
|
6
|
+
private let channelKey = "channel" // DO NOT CHANGE
|
|
7
|
+
private let customIdKey = "customId" // DO NOT CHANGE
|
|
8
|
+
private let lastVersionCodeKey = "lastVersionCode" // DO NOT CHANGE
|
|
9
|
+
private let lastVersionNameKey = "lastVersionName" // DO NOT CHANGE
|
|
10
|
+
private let nextBundleIdKey = "nextBundleId" // DO NOT CHANGE
|
|
11
|
+
private let previousBundleIdKey = "previousBundleIdKey" // DO NOT CHANGE
|
|
12
|
+
|
|
13
|
+
public func getAppId() -> String? {
|
|
14
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: appIdKey))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public func getBlockedBundleIds() -> String? {
|
|
18
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: blockedBundleIdsKey))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public func getChannel() -> String? {
|
|
22
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: channelKey))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public func getCustomId() -> String? {
|
|
26
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: customIdKey))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public func getLastVersionCode() -> String? {
|
|
30
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: lastVersionCodeKey))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public func getLastVersionName() -> String? {
|
|
34
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: lastVersionNameKey))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public func getNextBundleId() -> String? {
|
|
38
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: nextBundleIdKey))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public func getPreviousBundleId() -> String? {
|
|
42
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: previousBundleIdKey))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public func setAppId(_ value: String?) {
|
|
46
|
+
if let value = value {
|
|
47
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: appIdKey))
|
|
48
|
+
} else {
|
|
49
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: appIdKey))
|
|
50
|
+
}
|
|
51
|
+
UserDefaults.standard.synchronize()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public func setBlockedBundleIds(_ value: String?) {
|
|
55
|
+
if let value = value {
|
|
56
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: blockedBundleIdsKey))
|
|
57
|
+
} else {
|
|
58
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: blockedBundleIdsKey))
|
|
59
|
+
}
|
|
60
|
+
UserDefaults.standard.synchronize()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public func setChannel(_ value: String?) {
|
|
64
|
+
if let value = value {
|
|
65
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: channelKey))
|
|
66
|
+
} else {
|
|
67
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: channelKey))
|
|
68
|
+
}
|
|
69
|
+
UserDefaults.standard.synchronize()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public func setCustomId(_ value: String) {
|
|
73
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: customIdKey))
|
|
74
|
+
UserDefaults.standard.synchronize()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public func setLastVersionCode(_ value: String?) {
|
|
78
|
+
if let value = value {
|
|
79
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: lastVersionCodeKey))
|
|
80
|
+
} else {
|
|
81
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: lastVersionCodeKey))
|
|
82
|
+
}
|
|
83
|
+
UserDefaults.standard.synchronize()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public func setLastVersionName(_ value: String?) {
|
|
87
|
+
if let value = value {
|
|
88
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: lastVersionNameKey))
|
|
89
|
+
} else {
|
|
90
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: lastVersionNameKey))
|
|
91
|
+
}
|
|
92
|
+
UserDefaults.standard.synchronize()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public func setNextBundleId(_ value: String?) {
|
|
96
|
+
if let value = value {
|
|
97
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: nextBundleIdKey))
|
|
98
|
+
} else {
|
|
99
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: nextBundleIdKey))
|
|
100
|
+
}
|
|
101
|
+
UserDefaults.standard.synchronize()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public func setPreviousBundleId(_ value: String?) {
|
|
105
|
+
if let value = value {
|
|
106
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: previousBundleIdKey))
|
|
107
|
+
} else {
|
|
108
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: previousBundleIdKey))
|
|
109
|
+
}
|
|
110
|
+
UserDefaults.standard.synchronize()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private func applyPrefix(to key: String) -> String {
|
|
114
|
+
return LiveUpdatePlugin.userDefaultsPrefix + "." + key
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class LiveUpdateReadyResult: NSObject, LiveUpdateResult {
|
|
4
|
+
let currentBundleId: String?
|
|
5
|
+
let previousBundleId: String?
|
|
6
|
+
let rollback: Bool
|
|
7
|
+
|
|
8
|
+
init(currentBundleId: String?, previousBundleId: String?, rollback: Bool) {
|
|
9
|
+
self.currentBundleId = currentBundleId
|
|
10
|
+
self.previousBundleId = previousBundleId
|
|
11
|
+
self.rollback = rollback
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public func toJSObject() -> [String: Any] {
|
|
15
|
+
var result: [String: Any] = [:]
|
|
16
|
+
result["currentBundleId"] = currentBundleId == nil ? NSNull() : currentBundleId
|
|
17
|
+
result["previousBundleId"] = previousBundleId == nil ? NSNull() : previousBundleId
|
|
18
|
+
result["rollback"] = rollback
|
|
19
|
+
return result
|
|
20
|
+
}
|
|
21
|
+
}
|