@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,286 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import WebKit
|
|
3
|
+
|
|
4
|
+
/// Serves files from the active live-update bundle directory in response to
|
|
5
|
+
/// WebKit URL scheme tasks. When no bundle is active (or the requested file is
|
|
6
|
+
/// not in the active bundle) `handle(task:)` returns `false`, allowing Cordova's
|
|
7
|
+
/// default scheme handler to fall back to the app's bundled `www/` folder.
|
|
8
|
+
public class LiveUpdateSchemeHandler: NSObject {
|
|
9
|
+
private let activeBundleDirLock = NSLock()
|
|
10
|
+
private var _activeBundleDir: URL?
|
|
11
|
+
|
|
12
|
+
private let activeTasksQueue = DispatchQueue(label: "io.capawesome.cordova.liveupdate.schemeHandler")
|
|
13
|
+
private var activeTasks = Set<URLSchemeTaskWrapper>()
|
|
14
|
+
|
|
15
|
+
public var activeBundleDir: URL? {
|
|
16
|
+
get {
|
|
17
|
+
activeBundleDirLock.lock()
|
|
18
|
+
defer { activeBundleDirLock.unlock() }
|
|
19
|
+
return _activeBundleDir
|
|
20
|
+
}
|
|
21
|
+
set {
|
|
22
|
+
activeBundleDirLock.lock()
|
|
23
|
+
_activeBundleDir = newValue
|
|
24
|
+
activeBundleDirLock.unlock()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Called from `CDVPlugin.overrideSchemeTask`. Returns `true` if we serve
|
|
29
|
+
/// the resource ourselves, `false` to fall through to the default handler.
|
|
30
|
+
public func handle(task: WKURLSchemeTask) -> Bool {
|
|
31
|
+
guard let baseDir = activeBundleDir else {
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
guard let requestURL = task.request.url else {
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Map the request path to a file inside the active bundle directory.
|
|
39
|
+
var relativePath = requestURL.path
|
|
40
|
+
if relativePath.hasPrefix("/") {
|
|
41
|
+
relativePath = String(relativePath.dropFirst())
|
|
42
|
+
}
|
|
43
|
+
if relativePath.isEmpty || relativePath.hasSuffix("/") {
|
|
44
|
+
relativePath += "index.html"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let fileURL = baseDir.appendingPathComponent(relativePath).standardizedFileURL
|
|
48
|
+
|
|
49
|
+
// Defense-in-depth against path traversal.
|
|
50
|
+
let canonicalBase = baseDir.standardizedFileURL.path
|
|
51
|
+
guard fileURL.path == canonicalBase || fileURL.path.hasPrefix(canonicalBase + "/") else {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var isDirectory: ObjCBool = false
|
|
56
|
+
guard FileManager.default.fileExists(atPath: fileURL.path, isDirectory: &isDirectory), !isDirectory.boolValue else {
|
|
57
|
+
// File not in the active bundle — let the default handler try.
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let wrapper = URLSchemeTaskWrapper(task: task)
|
|
62
|
+
activeTasksQueue.sync { _ = activeTasks.insert(wrapper) }
|
|
63
|
+
|
|
64
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
65
|
+
self?.serve(task: task, wrapper: wrapper, fileURL: fileURL, requestURL: requestURL, request: task.request)
|
|
66
|
+
}
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public func stop(task: WKURLSchemeTask) {
|
|
71
|
+
activeTasksQueue.sync {
|
|
72
|
+
activeTasks = activeTasks.filter { $0.task !== task }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private func isActive(_ wrapper: URLSchemeTaskWrapper) -> Bool {
|
|
77
|
+
return activeTasksQueue.sync { activeTasks.contains(wrapper) }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private func removeActive(_ wrapper: URLSchemeTaskWrapper) {
|
|
81
|
+
activeTasksQueue.sync { _ = activeTasks.remove(wrapper) }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private func serve(task: WKURLSchemeTask, wrapper: URLSchemeTaskWrapper, fileURL: URL, requestURL: URL, request: URLRequest) {
|
|
85
|
+
let fileHandle: FileHandle
|
|
86
|
+
do {
|
|
87
|
+
fileHandle = try FileHandle(forReadingFrom: fileURL)
|
|
88
|
+
} catch {
|
|
89
|
+
if isActive(wrapper) {
|
|
90
|
+
task.didFailWithError(error)
|
|
91
|
+
}
|
|
92
|
+
removeActive(wrapper)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
defer { try? fileHandle.close() }
|
|
96
|
+
|
|
97
|
+
let fileSize: UInt64
|
|
98
|
+
do {
|
|
99
|
+
let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.path)
|
|
100
|
+
fileSize = (attributes[.size] as? NSNumber)?.uint64Value ?? 0
|
|
101
|
+
} catch {
|
|
102
|
+
if isActive(wrapper) {
|
|
103
|
+
task.didFailWithError(error)
|
|
104
|
+
}
|
|
105
|
+
removeActive(wrapper)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
var statusCode = 200
|
|
110
|
+
let mimeType = mimeType(for: fileURL)
|
|
111
|
+
var headers: [String: String] = [
|
|
112
|
+
"Content-Type": mimeType,
|
|
113
|
+
"Cache-Control": "no-cache"
|
|
114
|
+
]
|
|
115
|
+
var responseSize = fileSize
|
|
116
|
+
var responseSent: UInt64 = 0
|
|
117
|
+
|
|
118
|
+
// Range request handling
|
|
119
|
+
if let rangeHeader = request.value(forHTTPHeaderField: "Range"), rangeHeader.hasPrefix("bytes=") {
|
|
120
|
+
let byteRange = rangeHeader.dropFirst("bytes=".count)
|
|
121
|
+
let parts = byteRange.split(separator: "-", maxSplits: 1, omittingEmptySubsequences: false)
|
|
122
|
+
let start: UInt64 = UInt64(parts.first.map(String.init) ?? "") ?? 0
|
|
123
|
+
var end: UInt64
|
|
124
|
+
if parts.count > 1, !parts[1].isEmpty, let parsed = UInt64(parts[1]) {
|
|
125
|
+
end = parsed
|
|
126
|
+
} else {
|
|
127
|
+
end = fileSize > 0 ? fileSize - 1 : 0
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Clamp the end to the last valid byte so an over-large range does
|
|
131
|
+
// not produce an invalid Content-Length or read past EOF.
|
|
132
|
+
if fileSize > 0 {
|
|
133
|
+
end = min(end, fileSize - 1)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// An unsatisfiable range (start past EOF, or end before start)
|
|
137
|
+
// must be answered with 416 rather than underflowing `end - start`.
|
|
138
|
+
if start >= fileSize || end < start {
|
|
139
|
+
headers["Content-Range"] = "bytes */\(fileSize)"
|
|
140
|
+
let response = HTTPURLResponse(
|
|
141
|
+
url: requestURL,
|
|
142
|
+
statusCode: 416,
|
|
143
|
+
httpVersion: "HTTP/1.1",
|
|
144
|
+
headerFields: headers
|
|
145
|
+
)
|
|
146
|
+
if isActive(wrapper), let response = response {
|
|
147
|
+
task.didReceive(response)
|
|
148
|
+
task.didFinish()
|
|
149
|
+
}
|
|
150
|
+
removeActive(wrapper)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
do {
|
|
155
|
+
try fileHandle.seek(toOffset: start)
|
|
156
|
+
} catch {
|
|
157
|
+
if isActive(wrapper) {
|
|
158
|
+
task.didFailWithError(error)
|
|
159
|
+
}
|
|
160
|
+
removeActive(wrapper)
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
let length = end - start + 1
|
|
164
|
+
responseSize = length
|
|
165
|
+
statusCode = 206
|
|
166
|
+
headers["Content-Range"] = "bytes \(start)-\(end)/\(fileSize)"
|
|
167
|
+
headers["Content-Length"] = String(length)
|
|
168
|
+
} else {
|
|
169
|
+
headers["Content-Length"] = String(fileSize)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
guard let response = HTTPURLResponse(
|
|
173
|
+
url: requestURL,
|
|
174
|
+
statusCode: statusCode,
|
|
175
|
+
httpVersion: "HTTP/1.1",
|
|
176
|
+
headerFields: headers
|
|
177
|
+
) else {
|
|
178
|
+
removeActive(wrapper)
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if isActive(wrapper) {
|
|
183
|
+
task.didReceive(response)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let bufferSize = 64 * 1024
|
|
187
|
+
while isActive(wrapper) && responseSent < responseSize {
|
|
188
|
+
var reachedEOF = false
|
|
189
|
+
autoreleasepool {
|
|
190
|
+
let chunkSize = min(UInt64(bufferSize), responseSize - responseSent)
|
|
191
|
+
let data: Data
|
|
192
|
+
if #available(iOS 13.4, *) {
|
|
193
|
+
data = (try? fileHandle.read(upToCount: Int(chunkSize))) ?? Data()
|
|
194
|
+
} else {
|
|
195
|
+
data = fileHandle.readData(ofLength: Int(chunkSize))
|
|
196
|
+
}
|
|
197
|
+
if data.isEmpty {
|
|
198
|
+
// `return` only exits the autoreleasepool closure; flag EOF
|
|
199
|
+
// so the enclosing loop terminates instead of spinning.
|
|
200
|
+
reachedEOF = true
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
if isActive(wrapper) {
|
|
204
|
+
task.didReceive(data)
|
|
205
|
+
}
|
|
206
|
+
responseSent += UInt64(data.count)
|
|
207
|
+
}
|
|
208
|
+
if reachedEOF {
|
|
209
|
+
break
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if isActive(wrapper) {
|
|
214
|
+
task.didFinish()
|
|
215
|
+
}
|
|
216
|
+
removeActive(wrapper)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private func mimeType(for url: URL) -> String {
|
|
220
|
+
let ext = url.pathExtension.lowercased()
|
|
221
|
+
switch ext {
|
|
222
|
+
case "js", "mjs":
|
|
223
|
+
return "application/javascript"
|
|
224
|
+
case "html", "htm":
|
|
225
|
+
return "text/html"
|
|
226
|
+
case "css":
|
|
227
|
+
return "text/css"
|
|
228
|
+
case "json":
|
|
229
|
+
return "application/json"
|
|
230
|
+
case "wasm":
|
|
231
|
+
return "application/wasm"
|
|
232
|
+
case "svg":
|
|
233
|
+
return "image/svg+xml"
|
|
234
|
+
case "png":
|
|
235
|
+
return "image/png"
|
|
236
|
+
case "jpg", "jpeg":
|
|
237
|
+
return "image/jpeg"
|
|
238
|
+
case "gif":
|
|
239
|
+
return "image/gif"
|
|
240
|
+
case "webp":
|
|
241
|
+
return "image/webp"
|
|
242
|
+
case "ico":
|
|
243
|
+
return "image/x-icon"
|
|
244
|
+
case "woff":
|
|
245
|
+
return "font/woff"
|
|
246
|
+
case "woff2":
|
|
247
|
+
return "font/woff2"
|
|
248
|
+
case "ttf":
|
|
249
|
+
return "font/ttf"
|
|
250
|
+
case "otf":
|
|
251
|
+
return "font/otf"
|
|
252
|
+
case "mp4":
|
|
253
|
+
return "video/mp4"
|
|
254
|
+
case "mp3":
|
|
255
|
+
return "audio/mpeg"
|
|
256
|
+
case "wav":
|
|
257
|
+
return "audio/wav"
|
|
258
|
+
case "txt":
|
|
259
|
+
return "text/plain"
|
|
260
|
+
case "xml":
|
|
261
|
+
return "application/xml"
|
|
262
|
+
case "pdf":
|
|
263
|
+
return "application/pdf"
|
|
264
|
+
default:
|
|
265
|
+
return "application/octet-stream"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/// Identity wrapper around `WKURLSchemeTask` so we can store tasks in a `Set`
|
|
271
|
+
/// using reference identity (the protocol itself isn't `Hashable`).
|
|
272
|
+
private final class URLSchemeTaskWrapper: Hashable {
|
|
273
|
+
let task: WKURLSchemeTask
|
|
274
|
+
|
|
275
|
+
init(task: WKURLSchemeTask) {
|
|
276
|
+
self.task = task
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
static func == (lhs: URLSchemeTaskWrapper, rhs: URLSchemeTaskWrapper) -> Bool {
|
|
280
|
+
return lhs.task === rhs.task
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
func hash(into hasher: inout Hasher) {
|
|
284
|
+
hasher.combine(ObjectIdentifier(task as AnyObject))
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class LiveUpdateSetNextBundleOptions: NSObject {
|
|
4
|
+
private var bundleId: String?
|
|
5
|
+
|
|
6
|
+
init(_ options: [String: Any]) {
|
|
7
|
+
self.bundleId = options["bundleId"] as? String
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
func getBundleId() -> String? {
|
|
11
|
+
return bundleId
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class LiveUpdateSyncOptions: NSObject {
|
|
4
|
+
private var channel: String?
|
|
5
|
+
|
|
6
|
+
init(_ options: [String: Any]) {
|
|
7
|
+
self.channel = options["channel"] as? String
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
init(channel: String?) {
|
|
11
|
+
self.channel = channel
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
func getChannel() -> String? {
|
|
15
|
+
return channel
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc public class LiveUpdateSyncResult: NSObject, LiveUpdateResult {
|
|
4
|
+
let nextBundleId: String?
|
|
5
|
+
|
|
6
|
+
init(nextBundleId: String?) {
|
|
7
|
+
self.nextBundleId = nextBundleId
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public func toJSObject() -> [String: Any] {
|
|
11
|
+
var result: [String: Any] = [:]
|
|
12
|
+
result["nextBundleId"] = nextBundleId == nil ? NSNull() : nextBundleId
|
|
13
|
+
return result
|
|
14
|
+
}
|
|
15
|
+
}
|