@capgo/capacitor-webview-version-checker 8.0.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/CapgoCapacitorWebviewVersionChecker.podspec +17 -0
- package/LICENSE +373 -0
- package/Package.swift +28 -0
- package/README.md +393 -0
- package/android/build.gradle +61 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/app/capgo/webviewversionchecker/WebviewVersionChecker.java +75 -0
- package/android/src/main/java/app/capgo/webviewversionchecker/WebviewVersionCheckerPlugin.java +751 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +560 -0
- package/dist/esm/definitions.d.ts +294 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +18 -0
- package/dist/esm/web.js +159 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +173 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +176 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/WebviewVersionCheckerPlugin/WebviewVersionChecker.swift +142 -0
- package/ios/Sources/WebviewVersionCheckerPlugin/WebviewVersionCheckerPlugin.swift +394 -0
- package/ios/Tests/WebviewVersionCheckerPluginTests/WebviewVersionCheckerPluginTests.swift +22 -0
- package/package.json +89 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
@objc(WebviewVersionCheckerPlugin)
|
|
6
|
+
public class WebviewVersionCheckerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
7
|
+
public let identifier = "WebviewVersionCheckerPlugin"
|
|
8
|
+
public let jsName = "WebviewVersionChecker"
|
|
9
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
10
|
+
CAPPluginMethod(name: "check", returnType: CAPPluginReturnPromise),
|
|
11
|
+
CAPPluginMethod(name: "startMonitoring", returnType: CAPPluginReturnPromise),
|
|
12
|
+
CAPPluginMethod(name: "stopMonitoring", returnType: CAPPluginReturnPromise),
|
|
13
|
+
CAPPluginMethod(name: "getLastStatus", returnType: CAPPluginReturnPromise),
|
|
14
|
+
CAPPluginMethod(name: "showUpdatePrompt", returnType: CAPPluginReturnPromise),
|
|
15
|
+
CAPPluginMethod(name: "openUpdatePage", returnType: CAPPluginReturnPromise)
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
private let implementation = WebviewVersionChecker()
|
|
19
|
+
|
|
20
|
+
private var runtimeOptions = RuntimeOptions()
|
|
21
|
+
private var monitoringEnabled = false
|
|
22
|
+
private var checkOnResume = true
|
|
23
|
+
private var lastStatus: [String: Any]?
|
|
24
|
+
private var lastPromptFingerprint: String?
|
|
25
|
+
|
|
26
|
+
private var didBecomeActiveObserver: NSObjectProtocol?
|
|
27
|
+
|
|
28
|
+
override public func load() {
|
|
29
|
+
super.load()
|
|
30
|
+
|
|
31
|
+
runtimeOptions = RuntimeOptions(config: getConfig())
|
|
32
|
+
monitoringEnabled = runtimeOptions.autoCheckOnResume
|
|
33
|
+
checkOnResume = runtimeOptions.autoCheckOnResume
|
|
34
|
+
|
|
35
|
+
didBecomeActiveObserver = NotificationCenter.default.addObserver(
|
|
36
|
+
forName: UIApplication.didBecomeActiveNotification,
|
|
37
|
+
object: nil,
|
|
38
|
+
queue: .main
|
|
39
|
+
) { [weak self] _ in
|
|
40
|
+
guard let self else { return }
|
|
41
|
+
guard self.monitoringEnabled, self.checkOnResume else { return }
|
|
42
|
+
self.runCheck(source: "resume", options: self.runtimeOptions, forcePrompt: false, completion: nil)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if runtimeOptions.autoCheckOnLoad {
|
|
46
|
+
runCheck(source: "load", options: runtimeOptions, forcePrompt: false, completion: nil)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
deinit {
|
|
51
|
+
if let observer = didBecomeActiveObserver {
|
|
52
|
+
NotificationCenter.default.removeObserver(observer)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@objc func check(_ call: CAPPluginCall) {
|
|
57
|
+
let options = runtimeOptions.merged(with: call)
|
|
58
|
+
let source = call.getString("source") ?? "manual"
|
|
59
|
+
|
|
60
|
+
runCheck(source: source, options: options, forcePrompt: options.showPromptOnOutdated) { status in
|
|
61
|
+
call.resolve(status)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@objc func startMonitoring(_ call: CAPPluginCall) {
|
|
66
|
+
runtimeOptions = runtimeOptions.merged(with: call)
|
|
67
|
+
monitoringEnabled = true
|
|
68
|
+
checkOnResume = call.getBool("checkOnResume", runtimeOptions.autoCheckOnResume)
|
|
69
|
+
|
|
70
|
+
if call.getBool("checkOnStart", true) {
|
|
71
|
+
runCheck(source: "startMonitoring", options: runtimeOptions, forcePrompt: runtimeOptions.showPromptOnOutdated, completion: nil)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
call.resolve(monitoringStatePayload())
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@objc func stopMonitoring(_ call: CAPPluginCall) {
|
|
78
|
+
monitoringEnabled = false
|
|
79
|
+
call.resolve(monitoringStatePayload())
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@objc func getLastStatus(_ call: CAPPluginCall) {
|
|
83
|
+
if let lastStatus {
|
|
84
|
+
call.resolve(["status": lastStatus])
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
call.resolve(["status": NSNull()])
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@objc func showUpdatePrompt(_ call: CAPPluginCall) {
|
|
92
|
+
let promptOptions = PromptOptions(call: call, defaults: runtimeOptions)
|
|
93
|
+
showUpdatePrompt(promptOptions: promptOptions, force: true) { shown, opened in
|
|
94
|
+
call.resolve([
|
|
95
|
+
"shown": shown,
|
|
96
|
+
"openedUpdatePage": opened
|
|
97
|
+
])
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@objc func openUpdatePage(_ call: CAPPluginCall) {
|
|
102
|
+
let url = resolveUpdateUrl(explicitUpdateUrl: call.getString("updateUrl"), status: lastStatus)
|
|
103
|
+
|
|
104
|
+
openUpdatePageInternal(url: url) { opened in
|
|
105
|
+
call.resolve([
|
|
106
|
+
"opened": opened,
|
|
107
|
+
"url": url
|
|
108
|
+
])
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private func runCheck(
|
|
113
|
+
source: String,
|
|
114
|
+
options: RuntimeOptions,
|
|
115
|
+
forcePrompt: Bool,
|
|
116
|
+
completion: (([String: Any]) -> Void)?
|
|
117
|
+
) {
|
|
118
|
+
let status = implementation.buildStatus(
|
|
119
|
+
source: source,
|
|
120
|
+
latestVersion: options.latestVersion,
|
|
121
|
+
minimumMajorVersion: options.minimumMajorVersion,
|
|
122
|
+
updateUrl: options.updateUrl
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
lastStatus = status
|
|
126
|
+
|
|
127
|
+
DispatchQueue.main.async { [weak self] in
|
|
128
|
+
guard let self else {
|
|
129
|
+
completion?(status)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
self.notifyStatus(status)
|
|
134
|
+
self.maybeAutoPrompt(status: status, options: options, forcePrompt: forcePrompt)
|
|
135
|
+
completion?(status)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private func notifyStatus(_ status: [String: Any]) {
|
|
140
|
+
notifyListeners("statusChanged", data: status)
|
|
141
|
+
|
|
142
|
+
guard let state = status["state"] as? String else { return }
|
|
143
|
+
if state == "latest" {
|
|
144
|
+
notifyListeners("webViewLatest", data: status)
|
|
145
|
+
} else if state == "outdated" {
|
|
146
|
+
notifyListeners("webViewOutdated", data: status)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private func maybeAutoPrompt(status: [String: Any], options: RuntimeOptions, forcePrompt: Bool) {
|
|
151
|
+
guard let state = status["state"] as? String, state == "outdated" else {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
guard forcePrompt || options.autoPromptOnOutdated else {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
showUpdatePrompt(promptOptions: PromptOptions(defaults: options), force: forcePrompt, completion: nil)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private func showUpdatePrompt(
|
|
163
|
+
promptOptions: PromptOptions,
|
|
164
|
+
force: Bool,
|
|
165
|
+
completion: ((Bool, Bool) -> Void)?
|
|
166
|
+
) {
|
|
167
|
+
let resolvedUrl = resolveUpdateUrl(explicitUpdateUrl: promptOptions.updateUrl, status: lastStatus)
|
|
168
|
+
|
|
169
|
+
let fingerprint = implementation.promptFingerprint(status: lastStatus, updateUrl: resolvedUrl)
|
|
170
|
+
if !force, fingerprint == lastPromptFingerprint {
|
|
171
|
+
completion?(false, false)
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
lastPromptFingerprint = fingerprint
|
|
176
|
+
|
|
177
|
+
let title = promptOptions.title ?? "WebView update available"
|
|
178
|
+
let message = promptOptions.message ?? implementation.defaultPromptMessage(status: lastStatus)
|
|
179
|
+
let updateButtonText = promptOptions.updateButtonText ?? "Update"
|
|
180
|
+
let cancelButtonText = promptOptions.cancelButtonText ?? "Later"
|
|
181
|
+
|
|
182
|
+
DispatchQueue.main.async {
|
|
183
|
+
guard let presenter = self.topViewController(from: self.bridge?.viewController) else {
|
|
184
|
+
completion?(false, false)
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
|
189
|
+
alert.addAction(UIAlertAction(title: cancelButtonText, style: .cancel) { _ in
|
|
190
|
+
completion?(true, false)
|
|
191
|
+
})
|
|
192
|
+
alert.addAction(UIAlertAction(title: updateButtonText, style: .default) { _ in
|
|
193
|
+
self.openUpdatePageInternal(url: resolvedUrl) { opened in
|
|
194
|
+
completion?(true, opened)
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
presenter.present(alert, animated: true)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private func monitoringStatePayload() -> [String: Any] {
|
|
203
|
+
[
|
|
204
|
+
"monitoring": monitoringEnabled,
|
|
205
|
+
"checkOnResume": checkOnResume,
|
|
206
|
+
"autoPromptOnOutdated": runtimeOptions.autoPromptOnOutdated
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private func resolveUpdateUrl(explicitUpdateUrl: String?, status: [String: Any]?) -> String {
|
|
211
|
+
if let explicitUpdateUrl, !explicitUpdateUrl.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
212
|
+
return explicitUpdateUrl
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if let statusUpdateUrl = status?["updateUrl"] as? String,
|
|
216
|
+
!statusUpdateUrl.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
217
|
+
return statusUpdateUrl
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return implementation.normalizedUpdateUrl(runtimeOptions.updateUrl)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private func openUpdatePageInternal(url: String, completion: @escaping (Bool) -> Void) {
|
|
224
|
+
guard let parsedUrl = URL(string: url) else {
|
|
225
|
+
completion(false)
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
DispatchQueue.main.async {
|
|
230
|
+
guard UIApplication.shared.canOpenURL(parsedUrl) else {
|
|
231
|
+
completion(false)
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
UIApplication.shared.open(parsedUrl, options: [:]) { opened in
|
|
236
|
+
completion(opened)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private func topViewController(from controller: UIViewController?) -> UIViewController? {
|
|
242
|
+
if let navigationController = controller as? UINavigationController {
|
|
243
|
+
return topViewController(from: navigationController.visibleViewController)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if let tabController = controller as? UITabBarController,
|
|
247
|
+
let selected = tabController.selectedViewController {
|
|
248
|
+
return topViewController(from: selected)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if let presented = controller?.presentedViewController {
|
|
252
|
+
return topViewController(from: presented)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return controller
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private struct PromptOptions {
|
|
260
|
+
var title: String?
|
|
261
|
+
var message: String?
|
|
262
|
+
var updateButtonText: String?
|
|
263
|
+
var cancelButtonText: String?
|
|
264
|
+
var updateUrl: String?
|
|
265
|
+
|
|
266
|
+
init(defaults: RuntimeOptions) {
|
|
267
|
+
title = defaults.promptTitle
|
|
268
|
+
message = defaults.promptMessage
|
|
269
|
+
updateButtonText = defaults.promptUpdateButtonText
|
|
270
|
+
cancelButtonText = defaults.promptCancelButtonText
|
|
271
|
+
updateUrl = defaults.updateUrl
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
init(call: CAPPluginCall, defaults: RuntimeOptions) {
|
|
275
|
+
self.init(defaults: defaults)
|
|
276
|
+
|
|
277
|
+
if Self.hasValue(call, key: "title") {
|
|
278
|
+
title = call.getString("title")
|
|
279
|
+
}
|
|
280
|
+
if Self.hasValue(call, key: "message") {
|
|
281
|
+
message = call.getString("message")
|
|
282
|
+
}
|
|
283
|
+
if Self.hasValue(call, key: "updateButtonText") {
|
|
284
|
+
updateButtonText = call.getString("updateButtonText")
|
|
285
|
+
}
|
|
286
|
+
if Self.hasValue(call, key: "cancelButtonText") {
|
|
287
|
+
cancelButtonText = call.getString("cancelButtonText")
|
|
288
|
+
}
|
|
289
|
+
if Self.hasValue(call, key: "updateUrl") {
|
|
290
|
+
updateUrl = call.getString("updateUrl")
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private static func hasValue(_ call: CAPPluginCall, key: String) -> Bool {
|
|
295
|
+
guard let value = call.options[key] else {
|
|
296
|
+
return false
|
|
297
|
+
}
|
|
298
|
+
return !(value is NSNull)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private struct RuntimeOptions {
|
|
303
|
+
var autoCheckOnLoad = true
|
|
304
|
+
var autoCheckOnResume = true
|
|
305
|
+
var autoPromptOnOutdated = false
|
|
306
|
+
var showPromptOnOutdated = false
|
|
307
|
+
|
|
308
|
+
var latestVersion: String?
|
|
309
|
+
var minimumMajorVersion: Int?
|
|
310
|
+
var latestVersionApiUrl: String?
|
|
311
|
+
var updateUrl: String?
|
|
312
|
+
|
|
313
|
+
var promptTitle: String?
|
|
314
|
+
var promptMessage: String?
|
|
315
|
+
var promptUpdateButtonText: String?
|
|
316
|
+
var promptCancelButtonText: String?
|
|
317
|
+
|
|
318
|
+
init() {}
|
|
319
|
+
|
|
320
|
+
init(config: PluginConfig) {
|
|
321
|
+
autoCheckOnLoad = config.getBoolean("autoCheckOnLoad", true)
|
|
322
|
+
autoCheckOnResume = config.getBoolean("autoCheckOnResume", true)
|
|
323
|
+
autoPromptOnOutdated = config.getBoolean("autoPromptOnOutdated", false)
|
|
324
|
+
latestVersion = trimToNil(config.getString("latestVersion"))
|
|
325
|
+
minimumMajorVersion = config.getConfigJSON()["minimumMajorVersion"] as? Int
|
|
326
|
+
latestVersionApiUrl = trimToNil(config.getString("latestVersionApiUrl"))
|
|
327
|
+
updateUrl = trimToNil(config.getString("updateUrl"))
|
|
328
|
+
promptTitle = trimToNil(config.getString("promptTitle"))
|
|
329
|
+
promptMessage = trimToNil(config.getString("promptMessage"))
|
|
330
|
+
promptUpdateButtonText = trimToNil(config.getString("promptUpdateButtonText"))
|
|
331
|
+
promptCancelButtonText = trimToNil(config.getString("promptCancelButtonText"))
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
func merged(with call: CAPPluginCall) -> RuntimeOptions {
|
|
335
|
+
var out = self
|
|
336
|
+
|
|
337
|
+
if Self.hasValue(call, key: "autoCheckOnLoad") {
|
|
338
|
+
out.autoCheckOnLoad = call.getBool("autoCheckOnLoad", out.autoCheckOnLoad)
|
|
339
|
+
}
|
|
340
|
+
if Self.hasValue(call, key: "autoCheckOnResume") {
|
|
341
|
+
out.autoCheckOnResume = call.getBool("autoCheckOnResume", out.autoCheckOnResume)
|
|
342
|
+
}
|
|
343
|
+
if Self.hasValue(call, key: "autoPromptOnOutdated") {
|
|
344
|
+
out.autoPromptOnOutdated = call.getBool("autoPromptOnOutdated", out.autoPromptOnOutdated)
|
|
345
|
+
}
|
|
346
|
+
if Self.hasValue(call, key: "showPromptOnOutdated") {
|
|
347
|
+
out.showPromptOnOutdated = call.getBool("showPromptOnOutdated", out.showPromptOnOutdated)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if Self.hasValue(call, key: "latestVersion") {
|
|
351
|
+
out.latestVersion = trimToNil(call.getString("latestVersion"))
|
|
352
|
+
}
|
|
353
|
+
if Self.hasValue(call, key: "minimumMajorVersion") {
|
|
354
|
+
out.minimumMajorVersion = call.getInt("minimumMajorVersion")
|
|
355
|
+
}
|
|
356
|
+
if Self.hasValue(call, key: "latestVersionApiUrl") {
|
|
357
|
+
out.latestVersionApiUrl = trimToNil(call.getString("latestVersionApiUrl"))
|
|
358
|
+
}
|
|
359
|
+
if Self.hasValue(call, key: "updateUrl") {
|
|
360
|
+
out.updateUrl = trimToNil(call.getString("updateUrl"))
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if Self.hasValue(call, key: "promptTitle") {
|
|
364
|
+
out.promptTitle = trimToNil(call.getString("promptTitle"))
|
|
365
|
+
}
|
|
366
|
+
if Self.hasValue(call, key: "promptMessage") {
|
|
367
|
+
out.promptMessage = trimToNil(call.getString("promptMessage"))
|
|
368
|
+
}
|
|
369
|
+
if Self.hasValue(call, key: "promptUpdateButtonText") {
|
|
370
|
+
out.promptUpdateButtonText = trimToNil(call.getString("promptUpdateButtonText"))
|
|
371
|
+
}
|
|
372
|
+
if Self.hasValue(call, key: "promptCancelButtonText") {
|
|
373
|
+
out.promptCancelButtonText = trimToNil(call.getString("promptCancelButtonText"))
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return out
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private static func hasValue(_ call: CAPPluginCall, key: String) -> Bool {
|
|
380
|
+
guard let value = call.options[key] else {
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
return !(value is NSNull)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private func trimToNil(_ value: String?) -> String? {
|
|
387
|
+
guard let value else {
|
|
388
|
+
return nil
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
392
|
+
return trimmed.isEmpty ? nil : trimmed
|
|
393
|
+
}
|
|
394
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import WebviewVersionCheckerPlugin
|
|
3
|
+
|
|
4
|
+
class WebviewVersionCheckerPluginTests: XCTestCase {
|
|
5
|
+
func testBuildStatusWithMinimumMajorVersion() {
|
|
6
|
+
let implementation = WebviewVersionChecker()
|
|
7
|
+
let status = implementation.buildStatus(source: "unit-test", latestVersion: nil, minimumMajorVersion: 1, updateUrl: nil)
|
|
8
|
+
|
|
9
|
+
XCTAssertEqual(status["platform"] as? String, "ios")
|
|
10
|
+
XCTAssertEqual(status["state"] as? String, "latest")
|
|
11
|
+
XCTAssertEqual(status["isLatest"] as? Bool, true)
|
|
12
|
+
XCTAssertNotNil(status["currentVersion"] as? String)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func testBuildStatusWithoutPolicyIsUnknown() {
|
|
16
|
+
let implementation = WebviewVersionChecker()
|
|
17
|
+
let status = implementation.buildStatus(source: "unit-test", latestVersion: nil, minimumMajorVersion: nil, updateUrl: nil)
|
|
18
|
+
|
|
19
|
+
XCTAssertEqual(status["state"] as? String, "unknown")
|
|
20
|
+
XCTAssertEqual(status["isLatest"] as? Bool, false)
|
|
21
|
+
}
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capgo/capacitor-webview-version-checker",
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Capacitor plugin to detect outdated WebView engines, emit status events, and present native update prompts.",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Sources",
|
|
14
|
+
"ios/Tests",
|
|
15
|
+
"Package.swift",
|
|
16
|
+
"CapgoCapacitorWebviewVersionChecker.podspec"
|
|
17
|
+
],
|
|
18
|
+
"author": "Martin Donadieu <martin@capgo.app>",
|
|
19
|
+
"license": "MPL-2.0",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/Cap-go/capacitor-webview-version-checker.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/Cap-go/capacitor-webview-version-checker/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://capgo.app/docs/plugins/webview-version-checker/",
|
|
28
|
+
"keywords": [
|
|
29
|
+
"capacitor",
|
|
30
|
+
"plugin",
|
|
31
|
+
"webview",
|
|
32
|
+
"version",
|
|
33
|
+
"update"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
|
|
37
|
+
"verify:ios": "xcodebuild -scheme CapgoCapacitorWebviewVersionChecker -destination generic/platform=iOS",
|
|
38
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
39
|
+
"verify:web": "bun run build",
|
|
40
|
+
"lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
|
|
41
|
+
"fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format",
|
|
42
|
+
"eslint": "eslint . --ext .ts",
|
|
43
|
+
"prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
44
|
+
"swiftlint": "node-swiftlint",
|
|
45
|
+
"docgen": "docgen --api WebviewVersionCheckerPlugin --output-readme README.md --output-json dist/docs.json",
|
|
46
|
+
"build": "bun run clean && bun run docgen && tsc && rollup -c rollup.config.mjs",
|
|
47
|
+
"clean": "rimraf ./dist",
|
|
48
|
+
"watch": "tsc --watch",
|
|
49
|
+
"prepublishOnly": "bun run build",
|
|
50
|
+
"check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@capacitor/android": "^8.0.0",
|
|
54
|
+
"@capacitor/cli": "^8.0.0",
|
|
55
|
+
"@capacitor/core": "^8.0.0",
|
|
56
|
+
"@capacitor/docgen": "^0.3.1",
|
|
57
|
+
"@capacitor/ios": "^8.0.0",
|
|
58
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
59
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
60
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
61
|
+
"@types/node": "^24.10.1",
|
|
62
|
+
"eslint": "^8.57.1",
|
|
63
|
+
"eslint-plugin-import": "^2.31.0",
|
|
64
|
+
"husky": "^9.1.7",
|
|
65
|
+
"prettier": "^3.6.2",
|
|
66
|
+
"prettier-pretty-check": "^0.2.0",
|
|
67
|
+
"prettier-plugin-java": "^2.7.7",
|
|
68
|
+
"rimraf": "^6.1.0",
|
|
69
|
+
"rollup": "^4.53.2",
|
|
70
|
+
"swiftlint": "^2.0.0",
|
|
71
|
+
"typescript": "^5.9.3"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@capacitor/core": ">=8.0.0"
|
|
75
|
+
},
|
|
76
|
+
"prettier": "@ionic/prettier-config",
|
|
77
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
78
|
+
"eslintConfig": {
|
|
79
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
80
|
+
},
|
|
81
|
+
"capacitor": {
|
|
82
|
+
"ios": {
|
|
83
|
+
"src": "ios"
|
|
84
|
+
},
|
|
85
|
+
"android": {
|
|
86
|
+
"src": "android"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|