@capgo/capacitor-inappbrowser 8.6.35 → 8.7.0-beta.pr598.346.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CapgoInAppBrowserPlugin.java +194 -3
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +30 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +388 -8
- package/dist/docs.json +303 -4
- package/dist/esm/definitions.d.ts +127 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +10 -1
- package/dist/esm/web.js +16 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +16 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +16 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +429 -32
- package/ios/Sources/InAppBrowserPlugin/ProxySchemeHandler.swift +0 -1
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +59 -30
- package/package.json +1 -1
|
@@ -98,7 +98,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
98
98
|
case aware = "AWARE"
|
|
99
99
|
case fakeVisible = "FAKE_VISIBLE"
|
|
100
100
|
}
|
|
101
|
-
private let pluginVersion: String = "8.
|
|
101
|
+
private let pluginVersion: String = "8.7.0"
|
|
102
102
|
public let identifier = "CapgoInAppBrowserPlugin"
|
|
103
103
|
public let jsName = "CapgoInAppBrowser"
|
|
104
104
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -109,10 +109,14 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
109
109
|
CAPPluginMethod(name: "getCookies", returnType: CAPPluginReturnPromise),
|
|
110
110
|
CAPPluginMethod(name: "clearAllCookies", returnType: CAPPluginReturnPromise),
|
|
111
111
|
CAPPluginMethod(name: "clearCache", returnType: CAPPluginReturnPromise),
|
|
112
|
+
CAPPluginMethod(name: "clearAllBrowsingData", returnType: CAPPluginReturnPromise),
|
|
112
113
|
CAPPluginMethod(name: "reload", returnType: CAPPluginReturnPromise),
|
|
113
114
|
CAPPluginMethod(name: "setUrl", returnType: CAPPluginReturnPromise),
|
|
114
115
|
CAPPluginMethod(name: "show", returnType: CAPPluginReturnPromise),
|
|
115
116
|
CAPPluginMethod(name: "hide", returnType: CAPPluginReturnPromise),
|
|
117
|
+
CAPPluginMethod(name: "sendToBack", returnType: CAPPluginReturnPromise),
|
|
118
|
+
CAPPluginMethod(name: "bringToFront", returnType: CAPPluginReturnPromise),
|
|
119
|
+
CAPPluginMethod(name: "dispatchInputEvent", returnType: CAPPluginReturnPromise),
|
|
116
120
|
CAPPluginMethod(name: "close", returnType: CAPPluginReturnPromise),
|
|
117
121
|
CAPPluginMethod(name: "executeScript", returnType: CAPPluginReturnPromise),
|
|
118
122
|
CAPPluginMethod(name: "postMessage", returnType: CAPPluginReturnPromise),
|
|
@@ -140,6 +144,14 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
140
144
|
private var activeWebViewId: String?
|
|
141
145
|
private var hiddenWebViewContainers: [ObjectIdentifier: UIView] = [:]
|
|
142
146
|
private var closeModalTitle: String?
|
|
147
|
+
private var layeredWebViewIds = Set<String>()
|
|
148
|
+
private var transparentHostWebViewIds = Set<String>()
|
|
149
|
+
private var hasStoredHostWebViewAppearance = false
|
|
150
|
+
private var originalHostWebViewBackgroundColor: UIColor?
|
|
151
|
+
private var originalHostWebViewIsOpaque = true
|
|
152
|
+
private var originalHostSubviewBackgrounds: [(UIView, UIColor?, Bool)] = []
|
|
153
|
+
private var originalHostSuperviewBackgroundColor: UIColor?
|
|
154
|
+
private var originalHostSuperviewIsOpaque = true
|
|
143
155
|
private var closeModalDescription: String?
|
|
144
156
|
private var closeModalOk: String?
|
|
145
157
|
private var closeModalCancel: String?
|
|
@@ -186,6 +198,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
186
198
|
}
|
|
187
199
|
|
|
188
200
|
private func unregisterWebView(id: String) {
|
|
201
|
+
detachLayeredWebView(id: id)
|
|
189
202
|
if let webView = webViewControllers[id]?.capableWebView {
|
|
190
203
|
cleanupHiddenWebViewContainer(for: webView)
|
|
191
204
|
}
|
|
@@ -346,6 +359,26 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
346
359
|
return stores
|
|
347
360
|
}
|
|
348
361
|
|
|
362
|
+
private func allBrowsingDataStores() -> [WKWebsiteDataStore] {
|
|
363
|
+
var seen = Set<ObjectIdentifier>()
|
|
364
|
+
var stores: [WKWebsiteDataStore] = []
|
|
365
|
+
|
|
366
|
+
func append(_ store: WKWebsiteDataStore) {
|
|
367
|
+
let identifier = ObjectIdentifier(store)
|
|
368
|
+
if seen.insert(identifier).inserted {
|
|
369
|
+
stores.append(store)
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
append(WKWebsiteDataStore.default())
|
|
374
|
+
for controller in webViewControllers.values {
|
|
375
|
+
if let store = controller.websiteDataStore() {
|
|
376
|
+
append(store)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return stores
|
|
380
|
+
}
|
|
381
|
+
|
|
349
382
|
private func parseProxyRules(_ rawRules: [Any]) throws -> [NativeProxyRule] {
|
|
350
383
|
try rawRules.enumerated().map { index, item in
|
|
351
384
|
guard let dictionary = item as? [String: Any] else {
|
|
@@ -359,19 +392,155 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
359
392
|
}
|
|
360
393
|
}
|
|
361
394
|
|
|
362
|
-
|
|
395
|
+
@discardableResult
|
|
396
|
+
func presentView(webViewId: String? = nil, isAnimated: Bool = true) -> Bool {
|
|
363
397
|
let resolvedId = webViewId ?? activeWebViewId
|
|
364
398
|
let navigationController = resolvedId.flatMap { navigationControllers[$0] } ?? self.navigationWebViewController
|
|
365
399
|
guard let navigationController else {
|
|
366
400
|
self.currentPluginCall?.reject("Navigation controller is not initialized")
|
|
367
|
-
return
|
|
401
|
+
return false
|
|
368
402
|
}
|
|
369
403
|
|
|
404
|
+
if let resolvedId,
|
|
405
|
+
let webViewController = webViewControllers[resolvedId],
|
|
406
|
+
webViewController.isLayeredBehind {
|
|
407
|
+
if !sendNavigationControllerToBack(id: resolvedId, transparentBackground: webViewController.transparentHostBackground) {
|
|
408
|
+
self.currentPluginCall?.reject("Failed to send webview to back")
|
|
409
|
+
return false
|
|
410
|
+
}
|
|
411
|
+
return true
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if let resolvedId {
|
|
415
|
+
detachLayeredWebView(id: resolvedId)
|
|
416
|
+
}
|
|
370
417
|
dismissActiveKeyboard()
|
|
371
418
|
let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
|
|
372
419
|
presenter?.present(navigationController, animated: isAnimated, completion: {
|
|
373
420
|
self.currentPluginCall?.resolve()
|
|
374
421
|
})
|
|
422
|
+
return true
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
private func targetFrame(for webViewController: WKWebViewController, in hostWebView: UIView) -> CGRect {
|
|
426
|
+
return CustomWebViewFrameSupport.resolvedFrame(
|
|
427
|
+
width: webViewController.customWidth,
|
|
428
|
+
height: webViewController.customHeight,
|
|
429
|
+
x: webViewController.customX,
|
|
430
|
+
y: webViewController.customY,
|
|
431
|
+
fallbackSize: hostWebView.bounds.size
|
|
432
|
+
) ?? hostWebView.bounds
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
@discardableResult
|
|
436
|
+
private func sendNavigationControllerToBack(id: String, transparentBackground: Bool) -> Bool {
|
|
437
|
+
guard let navigationController = navigationControllers[id],
|
|
438
|
+
let webViewController = webViewControllers[id],
|
|
439
|
+
let hostWebView = self.bridge?.webView else {
|
|
440
|
+
return false
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if let webView = webViewController.capableWebView, webView.superview !== webViewController.view {
|
|
444
|
+
cleanupHiddenWebViewContainer(for: webView)
|
|
445
|
+
attachWebViewToController(webViewController, webView: webView)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
dismissActiveKeyboard()
|
|
449
|
+
dismissNavigationControllerIfPresented(navigationController)
|
|
450
|
+
navigationController.view.removeFromSuperview()
|
|
451
|
+
if transparentBackground {
|
|
452
|
+
makeHostWebViewTransparent(for: id)
|
|
453
|
+
} else {
|
|
454
|
+
restoreHostWebViewBackgroundIfNeeded(for: id)
|
|
455
|
+
}
|
|
456
|
+
navigationController.view.frame = targetFrame(for: webViewController, in: hostWebView)
|
|
457
|
+
navigationController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
458
|
+
navigationController.view.isUserInteractionEnabled = false
|
|
459
|
+
hostWebView.addSubview(navigationController.view)
|
|
460
|
+
hostWebView.sendSubviewToBack(navigationController.view)
|
|
461
|
+
navigationController.view.setNeedsLayout()
|
|
462
|
+
navigationController.view.layoutIfNeeded()
|
|
463
|
+
|
|
464
|
+
layeredWebViewIds.insert(id)
|
|
465
|
+
webViewController.isLayeredBehind = true
|
|
466
|
+
webViewController.transparentHostBackground = transparentBackground
|
|
467
|
+
return true
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private func detachLayeredWebView(id: String) {
|
|
471
|
+
if let navigationController = navigationControllers[id] {
|
|
472
|
+
if navigationController.view.superview === self.bridge?.webView {
|
|
473
|
+
navigationController.view.removeFromSuperview()
|
|
474
|
+
}
|
|
475
|
+
navigationController.view.isUserInteractionEnabled = true
|
|
476
|
+
}
|
|
477
|
+
layeredWebViewIds.remove(id)
|
|
478
|
+
restoreHostWebViewBackgroundIfNeeded(for: id)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
private func storeSubviewBackgrounds(from view: UIView) {
|
|
482
|
+
for subview in view.subviews {
|
|
483
|
+
originalHostSubviewBackgrounds.append((subview, subview.backgroundColor, subview.isOpaque))
|
|
484
|
+
storeSubviewBackgrounds(from: subview)
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private func clearBackgrounds(in view: UIView) {
|
|
489
|
+
view.isOpaque = false
|
|
490
|
+
view.backgroundColor = .clear
|
|
491
|
+
view.subviews.forEach { clearBackgrounds(in: $0) }
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
private func makeHostWebViewTransparent(for id: String) {
|
|
495
|
+
guard let hostWebView = self.bridge?.webView else {
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
transparentHostWebViewIds.insert(id)
|
|
500
|
+
if !hasStoredHostWebViewAppearance {
|
|
501
|
+
hasStoredHostWebViewAppearance = true
|
|
502
|
+
originalHostWebViewBackgroundColor = hostWebView.backgroundColor
|
|
503
|
+
originalHostWebViewIsOpaque = hostWebView.isOpaque
|
|
504
|
+
originalHostSuperviewBackgroundColor = hostWebView.superview?.backgroundColor
|
|
505
|
+
originalHostSuperviewIsOpaque = hostWebView.superview?.isOpaque ?? true
|
|
506
|
+
originalHostSubviewBackgrounds.removeAll()
|
|
507
|
+
storeSubviewBackgrounds(from: hostWebView)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
clearBackgrounds(in: hostWebView)
|
|
511
|
+
hostWebView.superview?.isOpaque = false
|
|
512
|
+
hostWebView.superview?.backgroundColor = .clear
|
|
513
|
+
hostWebView.setNeedsLayout()
|
|
514
|
+
hostWebView.layoutIfNeeded()
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
private func restoreHostWebViewBackgroundIfNeeded(for id: String? = nil) {
|
|
518
|
+
if let id {
|
|
519
|
+
transparentHostWebViewIds.remove(id)
|
|
520
|
+
} else {
|
|
521
|
+
transparentHostWebViewIds.removeAll()
|
|
522
|
+
}
|
|
523
|
+
guard transparentHostWebViewIds.isEmpty, hasStoredHostWebViewAppearance else {
|
|
524
|
+
return
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if let hostWebView = self.bridge?.webView {
|
|
528
|
+
hostWebView.backgroundColor = originalHostWebViewBackgroundColor
|
|
529
|
+
hostWebView.isOpaque = originalHostWebViewIsOpaque
|
|
530
|
+
hostWebView.superview?.backgroundColor = originalHostSuperviewBackgroundColor
|
|
531
|
+
hostWebView.superview?.isOpaque = originalHostSuperviewIsOpaque
|
|
532
|
+
for (view, backgroundColor, isOpaque) in originalHostSubviewBackgrounds {
|
|
533
|
+
view.backgroundColor = backgroundColor
|
|
534
|
+
view.isOpaque = isOpaque
|
|
535
|
+
}
|
|
536
|
+
hostWebView.setNeedsLayout()
|
|
537
|
+
hostWebView.layoutIfNeeded()
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
hasStoredHostWebViewAppearance = false
|
|
541
|
+
originalHostWebViewBackgroundColor = nil
|
|
542
|
+
originalHostSuperviewBackgroundColor = nil
|
|
543
|
+
originalHostSubviewBackgrounds.removeAll()
|
|
375
544
|
}
|
|
376
545
|
|
|
377
546
|
private func dismissActiveKeyboard() {
|
|
@@ -572,6 +741,24 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
572
741
|
}
|
|
573
742
|
}
|
|
574
743
|
|
|
744
|
+
@objc func clearAllBrowsingData(_ call: CAPPluginCall) {
|
|
745
|
+
DispatchQueue.main.async {
|
|
746
|
+
let dataStores = self.allBrowsingDataStores()
|
|
747
|
+
let dataTypes = WKWebsiteDataStore.allWebsiteDataTypes()
|
|
748
|
+
let group = DispatchGroup()
|
|
749
|
+
for dataStore in dataStores {
|
|
750
|
+
group.enter()
|
|
751
|
+
dataStore.removeData(ofTypes: dataTypes,
|
|
752
|
+
modifiedSince: Date(timeIntervalSince1970: 0)) {
|
|
753
|
+
group.leave()
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
group.notify(queue: .main) {
|
|
757
|
+
call.resolve()
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
575
762
|
@objc func clearCookies(_ call: CAPPluginCall) {
|
|
576
763
|
guard let url = call.getString("url"),
|
|
577
764
|
let host = URL(string: url)?.host else {
|
|
@@ -771,12 +958,15 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
771
958
|
let enabledSafeBottomMargin = call.getBool("enabledSafeBottomMargin", false)
|
|
772
959
|
let enabledSafeTopMargin = call.getBool("enabledSafeTopMargin", true)
|
|
773
960
|
let hidden = call.getBool("hidden", false)
|
|
961
|
+
let toBack = call.getBool("toBack", false)
|
|
962
|
+
let transparentBackground = call.getBool("transparentBackground", true)
|
|
774
963
|
self.isHidden = hidden
|
|
775
964
|
let hiddenPopupWindow = call.getBool("hiddenPopupWindow", false)
|
|
776
965
|
let allowWebViewJsVisibilityControl = self.getConfig().getBoolean("allowWebViewJsVisibilityControl", false)
|
|
777
966
|
let allowScreenshotsFromWebPage = call.getBool("allowScreenshotsFromWebPage", false)
|
|
778
967
|
let captureConsoleLogs = call.getBool("captureConsoleLogs", false)
|
|
779
968
|
let handleDownloads = call.getBool("handleDownloads", false)
|
|
969
|
+
let persistWebViewData = call.getBool("persistWebViewData", true)
|
|
780
970
|
let invisibilityModeRaw = call.getString("invisibilityMode", "AWARE")
|
|
781
971
|
self.invisibilityMode = InvisibilityMode(rawValue: invisibilityModeRaw.uppercased()) ?? .aware
|
|
782
972
|
|
|
@@ -918,38 +1108,36 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
918
1108
|
self.proxyBridges[webViewId] = proxyBridge
|
|
919
1109
|
}
|
|
920
1110
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1111
|
+
let webViewController = WKWebViewController()
|
|
1112
|
+
webViewController.blankNavigationTab = toolbarType == "blank"
|
|
1113
|
+
webViewController.enabledSafeBottomMargin = enabledSafeBottomMargin
|
|
1114
|
+
webViewController.enabledSafeTopMargin = enabledSafeTopMargin
|
|
1115
|
+
webViewController.source = .remote(url)
|
|
1116
|
+
webViewController.setCredentials(credentials: credentials)
|
|
1117
|
+
webViewController.allowWebViewJsVisibilityControl = allowWebViewJsVisibilityControl
|
|
1118
|
+
webViewController.allowScreenshotsFromWebPage = allowScreenshotsFromWebPage
|
|
1119
|
+
webViewController.captureConsoleLogs = captureConsoleLogs
|
|
1120
|
+
webViewController.proxyRequests = legacyProxyRequests.isEnabled
|
|
1121
|
+
webViewController.proxySchemeHandler = proxyHandler
|
|
1122
|
+
webViewController.proxyBridge = proxyBridge
|
|
1123
|
+
webViewController.proxyBridgeAccessToken = proxyBridgeAccessToken
|
|
1124
|
+
webViewController.legacyProxyRequestURLRegexPattern = legacyProxyRequests.urlRegex?.pattern
|
|
1125
|
+
webViewController.openBlankTargetInWebView = openBlankTargetInWebView
|
|
1126
|
+
webViewController.persistWebViewData = persistWebViewData
|
|
1127
|
+
webViewController.setHeaders(headers: headers)
|
|
1128
|
+
webViewController.setPreventDeeplink(preventDeeplink: preventDeeplink)
|
|
1129
|
+
webViewController.setBlockedHosts(blockedHosts: blockedHosts)
|
|
1130
|
+
webViewController.setAuthorizedAppLinks(authorizedAppLinks: authorizedAppLinks)
|
|
1131
|
+
webViewController.documentStartUserScripts = self.documentStartUserScripts(
|
|
931
1132
|
authorizedAppLinks: authorizedAppLinks,
|
|
932
|
-
allowWebViewJsVisibilityControl: allowWebViewJsVisibilityControl,
|
|
933
|
-
allowScreenshotsFromWebPage: allowScreenshotsFromWebPage,
|
|
934
|
-
captureConsoleLogs: captureConsoleLogs,
|
|
935
|
-
proxyRequests: legacyProxyRequests.isEnabled,
|
|
936
|
-
proxySchemeHandler: proxyHandler,
|
|
937
|
-
proxyBridge: proxyBridge,
|
|
938
|
-
proxyBridgeAccessToken: proxyBridgeAccessToken,
|
|
939
|
-
legacyProxyRequestURLRegexPattern: legacyProxyRequests.urlRegex?.pattern,
|
|
940
|
-
documentStartUserScripts: self.documentStartUserScripts(
|
|
941
|
-
authorizedAppLinks: authorizedAppLinks,
|
|
942
|
-
openBlankTargetInWebView: openBlankTargetInWebView
|
|
943
|
-
),
|
|
944
1133
|
openBlankTargetInWebView: openBlankTargetInWebView
|
|
945
1134
|
)
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
call.reject("Failed to initialize WebViewController")
|
|
949
|
-
return
|
|
950
|
-
}
|
|
1135
|
+
webViewController.initWebview(isInspectable: isInspectable)
|
|
1136
|
+
self.webViewController = webViewController
|
|
951
1137
|
|
|
952
1138
|
webViewController.instanceId = webViewId
|
|
1139
|
+
webViewController.isLayeredBehind = toBack
|
|
1140
|
+
webViewController.transparentHostBackground = transparentBackground
|
|
953
1141
|
|
|
954
1142
|
// Set HTTP method and body if provided
|
|
955
1143
|
if let method = httpMethod {
|
|
@@ -1182,7 +1370,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1182
1370
|
}
|
|
1183
1371
|
|
|
1184
1372
|
// Configure modal presentation for touch passthrough if custom dimensions are set
|
|
1185
|
-
if width != nil || height != nil {
|
|
1373
|
+
if (width != nil || height != nil) && !toBack {
|
|
1186
1374
|
self.navigationWebViewController?.modalPresentationStyle = .overFullScreen
|
|
1187
1375
|
|
|
1188
1376
|
// Create a pass-through container
|
|
@@ -1272,7 +1460,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1272
1460
|
return
|
|
1273
1461
|
}
|
|
1274
1462
|
} else if !self.isPresentAfterPageLoad {
|
|
1275
|
-
self.presentView(webViewId: webViewId, isAnimated: isAnimated)
|
|
1463
|
+
guard self.presentView(webViewId: webViewId, isAnimated: isAnimated) else {
|
|
1464
|
+
return
|
|
1465
|
+
}
|
|
1276
1466
|
}
|
|
1277
1467
|
call.resolve(["id": webViewId])
|
|
1278
1468
|
}
|
|
@@ -1338,6 +1528,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1338
1528
|
self.isHidden = hidden
|
|
1339
1529
|
|
|
1340
1530
|
if hidden {
|
|
1531
|
+
if let resolvedId {
|
|
1532
|
+
self.detachLayeredWebView(id: resolvedId)
|
|
1533
|
+
}
|
|
1341
1534
|
if !self.attachWebViewToWindow(webView) {
|
|
1342
1535
|
call?.reject("Failed to get active window for hidden webview")
|
|
1343
1536
|
return
|
|
@@ -1348,6 +1541,18 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1348
1541
|
self.attachWebViewToController(webViewController, webView: webView)
|
|
1349
1542
|
}
|
|
1350
1543
|
|
|
1544
|
+
if webViewController.isLayeredBehind, let resolvedId {
|
|
1545
|
+
if self.sendNavigationControllerToBack(id: resolvedId, transparentBackground: webViewController.transparentHostBackground) {
|
|
1546
|
+
if let navController = navigationController {
|
|
1547
|
+
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navController)
|
|
1548
|
+
}
|
|
1549
|
+
call?.resolve()
|
|
1550
|
+
} else {
|
|
1551
|
+
call?.reject("Failed to send webview to back")
|
|
1552
|
+
}
|
|
1553
|
+
return
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1351
1556
|
if let navController = navigationController {
|
|
1352
1557
|
if let resolvedId {
|
|
1353
1558
|
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navController)
|
|
@@ -1386,6 +1591,198 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1386
1591
|
self.setHiddenState(false, targetId: call.getString("id"), call: call)
|
|
1387
1592
|
}
|
|
1388
1593
|
|
|
1594
|
+
@objc func sendToBack(_ call: CAPPluginCall) {
|
|
1595
|
+
DispatchQueue.main.async {
|
|
1596
|
+
let targetId = call.getString("id") ?? self.activeWebViewId
|
|
1597
|
+
guard let resolvedId = targetId,
|
|
1598
|
+
let webViewController = self.resolveWebViewController(for: resolvedId),
|
|
1599
|
+
let navigationController = self.resolveNavigationController(for: resolvedId) else {
|
|
1600
|
+
call.reject("WebView is not initialized")
|
|
1601
|
+
return
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
let transparentBackground = call.getBool("transparentBackground", true)
|
|
1605
|
+
webViewController.isLayeredBehind = true
|
|
1606
|
+
webViewController.transparentHostBackground = transparentBackground
|
|
1607
|
+
guard self.sendNavigationControllerToBack(id: resolvedId, transparentBackground: transparentBackground) else {
|
|
1608
|
+
call.reject("Failed to send webview to back")
|
|
1609
|
+
return
|
|
1610
|
+
}
|
|
1611
|
+
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navigationController)
|
|
1612
|
+
call.resolve()
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
@objc func bringToFront(_ call: CAPPluginCall) {
|
|
1617
|
+
DispatchQueue.main.async {
|
|
1618
|
+
let targetId = call.getString("id") ?? self.activeWebViewId
|
|
1619
|
+
guard let resolvedId = targetId,
|
|
1620
|
+
let webViewController = self.resolveWebViewController(for: resolvedId),
|
|
1621
|
+
let navigationController = self.resolveNavigationController(for: resolvedId) else {
|
|
1622
|
+
call.reject("WebView is not initialized")
|
|
1623
|
+
return
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
webViewController.isLayeredBehind = false
|
|
1627
|
+
webViewController.transparentHostBackground = true
|
|
1628
|
+
self.detachLayeredWebView(id: resolvedId)
|
|
1629
|
+
if let webView = webViewController.capableWebView, webView.superview !== webViewController.view {
|
|
1630
|
+
self.attachWebViewToController(webViewController, webView: webView)
|
|
1631
|
+
}
|
|
1632
|
+
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navigationController)
|
|
1633
|
+
if navigationController.presentingViewController == nil {
|
|
1634
|
+
let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
|
|
1635
|
+
presenter?.present(navigationController, animated: true, completion: {
|
|
1636
|
+
call.resolve()
|
|
1637
|
+
})
|
|
1638
|
+
return
|
|
1639
|
+
}
|
|
1640
|
+
call.resolve()
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
private func jsNumber(_ value: Float?, fallback: String = "0") -> String {
|
|
1645
|
+
guard let value, value.isFinite else {
|
|
1646
|
+
return fallback
|
|
1647
|
+
}
|
|
1648
|
+
return String(Double(value))
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
private func dispatchInputScript(type: String, x: Float?, y: Float?, deltaX: Float?, deltaY: Float?) -> String? {
|
|
1652
|
+
if type == "scroll" {
|
|
1653
|
+
guard let x, let y, let deltaX, let deltaY,
|
|
1654
|
+
x.isFinite, y.isFinite, deltaX.isFinite, deltaY.isFinite else {
|
|
1655
|
+
return nil
|
|
1656
|
+
}
|
|
1657
|
+
let xLiteral = jsNumber(x)
|
|
1658
|
+
let yLiteral = jsNumber(y)
|
|
1659
|
+
let deltaXLiteral = jsNumber(deltaX)
|
|
1660
|
+
let deltaYLiteral = jsNumber(deltaY)
|
|
1661
|
+
return """
|
|
1662
|
+
(function() {
|
|
1663
|
+
const x = \(xLiteral);
|
|
1664
|
+
const y = \(yLiteral);
|
|
1665
|
+
const dx = \(deltaXLiteral);
|
|
1666
|
+
const dy = \(deltaYLiteral);
|
|
1667
|
+
let target = Number.isFinite(x) && Number.isFinite(y) ? document.elementFromPoint(x, y) : null;
|
|
1668
|
+
while (target && target !== document.body && target !== document.documentElement) {
|
|
1669
|
+
const style = window.getComputedStyle(target);
|
|
1670
|
+
const canScroll = /(auto|scroll)/.test(style.overflow + style.overflowX + style.overflowY) &&
|
|
1671
|
+
(target.scrollHeight > target.clientHeight || target.scrollWidth > target.clientWidth);
|
|
1672
|
+
if (canScroll && typeof target.scrollBy === 'function') {
|
|
1673
|
+
target.scrollBy(dx, dy);
|
|
1674
|
+
return true;
|
|
1675
|
+
}
|
|
1676
|
+
target = target.parentElement;
|
|
1677
|
+
}
|
|
1678
|
+
window.scrollBy(dx, dy);
|
|
1679
|
+
return true;
|
|
1680
|
+
})();
|
|
1681
|
+
"""
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
let pointerEvents: [String]
|
|
1685
|
+
let mouseEvents: [String]
|
|
1686
|
+
let touchEvents: [String]
|
|
1687
|
+
switch type {
|
|
1688
|
+
case "click":
|
|
1689
|
+
pointerEvents = ["pointerdown", "pointerup"]
|
|
1690
|
+
mouseEvents = ["mousedown", "mouseup", "click"]
|
|
1691
|
+
touchEvents = ["touchstart", "touchend"]
|
|
1692
|
+
case "touchstart":
|
|
1693
|
+
pointerEvents = ["pointerdown"]
|
|
1694
|
+
mouseEvents = ["mousedown"]
|
|
1695
|
+
touchEvents = ["touchstart"]
|
|
1696
|
+
case "touchmove":
|
|
1697
|
+
pointerEvents = ["pointermove"]
|
|
1698
|
+
mouseEvents = ["mousemove"]
|
|
1699
|
+
touchEvents = ["touchmove"]
|
|
1700
|
+
case "touchend":
|
|
1701
|
+
pointerEvents = ["pointerup"]
|
|
1702
|
+
mouseEvents = ["mouseup"]
|
|
1703
|
+
touchEvents = ["touchend"]
|
|
1704
|
+
case "touchcancel":
|
|
1705
|
+
pointerEvents = ["pointercancel"]
|
|
1706
|
+
mouseEvents = []
|
|
1707
|
+
touchEvents = ["touchcancel"]
|
|
1708
|
+
default:
|
|
1709
|
+
return nil
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
guard let x, let y, x.isFinite, y.isFinite else {
|
|
1713
|
+
return nil
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
let pointerEventsData = try? JSONSerialization.data(withJSONObject: pointerEvents)
|
|
1717
|
+
let mouseEventsData = try? JSONSerialization.data(withJSONObject: mouseEvents)
|
|
1718
|
+
let touchEventsData = try? JSONSerialization.data(withJSONObject: touchEvents)
|
|
1719
|
+
let pointerEventsJSON = pointerEventsData.flatMap { String(data: $0, encoding: .utf8) } ?? "[]"
|
|
1720
|
+
let mouseEventsJSON = mouseEventsData.flatMap { String(data: $0, encoding: .utf8) } ?? "[]"
|
|
1721
|
+
let touchEventsJSON = touchEventsData.flatMap { String(data: $0, encoding: .utf8) } ?? "[]"
|
|
1722
|
+
|
|
1723
|
+
return """
|
|
1724
|
+
(function() {
|
|
1725
|
+
const x = \(jsNumber(x));
|
|
1726
|
+
const y = \(jsNumber(y));
|
|
1727
|
+
const target = document.elementFromPoint(x, y);
|
|
1728
|
+
if (!target) return false;
|
|
1729
|
+
const base = { bubbles: true, cancelable: true, composed: true, clientX: x, clientY: y, screenX: x, screenY: y };
|
|
1730
|
+
for (const name of \(pointerEventsJSON)) {
|
|
1731
|
+
if (typeof PointerEvent === 'function') {
|
|
1732
|
+
target.dispatchEvent(new PointerEvent(name, Object.assign({}, base, { pointerId: 1, pointerType: 'touch', isPrimary: true })));
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
for (const name of \(mouseEventsJSON)) {
|
|
1736
|
+
target.dispatchEvent(new MouseEvent(name, base));
|
|
1737
|
+
}
|
|
1738
|
+
if (typeof TouchEvent === 'function' && typeof Touch === 'function') {
|
|
1739
|
+
for (const name of \(touchEventsJSON)) {
|
|
1740
|
+
try {
|
|
1741
|
+
const touch = new Touch({ identifier: 1, target: target, clientX: x, clientY: y, screenX: x, screenY: y });
|
|
1742
|
+
const activeTouches = name === 'touchend' || name === 'touchcancel' ? [] : [touch];
|
|
1743
|
+
target.dispatchEvent(new TouchEvent(name, {
|
|
1744
|
+
bubbles: true,
|
|
1745
|
+
cancelable: true,
|
|
1746
|
+
composed: true,
|
|
1747
|
+
touches: activeTouches,
|
|
1748
|
+
targetTouches: activeTouches,
|
|
1749
|
+
changedTouches: [touch]
|
|
1750
|
+
}));
|
|
1751
|
+
} catch (_) {}
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
return true;
|
|
1755
|
+
})();
|
|
1756
|
+
"""
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
@objc func dispatchInputEvent(_ call: CAPPluginCall) {
|
|
1760
|
+
guard let type = call.getString("type") else {
|
|
1761
|
+
call.reject("Input event type is required")
|
|
1762
|
+
return
|
|
1763
|
+
}
|
|
1764
|
+
guard let script = dispatchInputScript(
|
|
1765
|
+
type: type,
|
|
1766
|
+
x: call.getFloat("x"),
|
|
1767
|
+
y: call.getFloat("y"),
|
|
1768
|
+
deltaX: call.getFloat("deltaX"),
|
|
1769
|
+
deltaY: call.getFloat("deltaY")
|
|
1770
|
+
) else {
|
|
1771
|
+
call.reject("Unsupported input event type or invalid input payload: \(type)")
|
|
1772
|
+
return
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
DispatchQueue.main.async {
|
|
1776
|
+
let targetId = call.getString("id") ?? self.activeWebViewId
|
|
1777
|
+
guard let webViewController = self.resolveWebViewController(for: targetId) else {
|
|
1778
|
+
call.reject("WebView is not initialized")
|
|
1779
|
+
return
|
|
1780
|
+
}
|
|
1781
|
+
webViewController.executeScript(script: script)
|
|
1782
|
+
call.resolve()
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1389
1786
|
@objc func executeScript(_ call: CAPPluginCall) {
|
|
1390
1787
|
guard let script = call.getString("code") else {
|
|
1391
1788
|
call.reject("Cannot get script to execute")
|
|
@@ -1169,7 +1169,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
|
|
|
1169
1169
|
}
|
|
1170
1170
|
}
|
|
1171
1171
|
|
|
1172
|
-
|
|
1173
1172
|
private func makeInitialRequestContext(from urlSchemeTask: WKURLSchemeTask, requestURL: URL) -> NativeRequestContext? {
|
|
1174
1173
|
let requestURLString = requestURL.absoluteString
|
|
1175
1174
|
|