@capgo/capacitor-inappbrowser 8.6.34 → 8.7.0-beta.pr596.340.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 +442 -57
- package/ios/Sources/InAppBrowserPlugin/ProxySchemeHandler.swift +0 -1
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +10 -3
- 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),
|
|
@@ -138,11 +142,16 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
138
142
|
private var proxyBridges: [String: ProxyBridge] = [:]
|
|
139
143
|
private var webViewStack: [String] = []
|
|
140
144
|
private var activeWebViewId: String?
|
|
141
|
-
private weak var presentationContainerView: UIView?
|
|
142
|
-
private var presentationContainerWasInteractive = true
|
|
143
|
-
private var presentationContainerPreviousAlpha: CGFloat = 1
|
|
144
145
|
private var hiddenWebViewContainers: [ObjectIdentifier: UIView] = [:]
|
|
145
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
|
|
146
155
|
private var closeModalDescription: String?
|
|
147
156
|
private var closeModalOk: String?
|
|
148
157
|
private var closeModalCancel: String?
|
|
@@ -181,7 +190,20 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
181
190
|
}
|
|
182
191
|
}
|
|
183
192
|
|
|
193
|
+
private func dismissNavigationControllerIfPresented(_ navigationController: UINavigationController?, completion: (() -> Void)? = nil) {
|
|
194
|
+
guard let navigationController else {
|
|
195
|
+
completion?()
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
guard navigationController.presentingViewController != nil else {
|
|
199
|
+
completion?()
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
navigationController.dismiss(animated: false, completion: completion)
|
|
203
|
+
}
|
|
204
|
+
|
|
184
205
|
private func unregisterWebView(id: String) {
|
|
206
|
+
detachLayeredWebView(id: id)
|
|
185
207
|
if let webView = webViewControllers[id]?.capableWebView {
|
|
186
208
|
cleanupHiddenWebViewContainer(for: webView)
|
|
187
209
|
}
|
|
@@ -342,6 +364,26 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
342
364
|
return stores
|
|
343
365
|
}
|
|
344
366
|
|
|
367
|
+
private func allBrowsingDataStores() -> [WKWebsiteDataStore] {
|
|
368
|
+
var seen = Set<ObjectIdentifier>()
|
|
369
|
+
var stores: [WKWebsiteDataStore] = []
|
|
370
|
+
|
|
371
|
+
func append(_ store: WKWebsiteDataStore) {
|
|
372
|
+
let identifier = ObjectIdentifier(store)
|
|
373
|
+
if seen.insert(identifier).inserted {
|
|
374
|
+
stores.append(store)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
append(WKWebsiteDataStore.default())
|
|
379
|
+
for controller in webViewControllers.values {
|
|
380
|
+
if let store = controller.websiteDataStore() {
|
|
381
|
+
append(store)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return stores
|
|
385
|
+
}
|
|
386
|
+
|
|
345
387
|
private func parseProxyRules(_ rawRules: [Any]) throws -> [NativeProxyRule] {
|
|
346
388
|
try rawRules.enumerated().map { index, item in
|
|
347
389
|
guard let dictionary = item as? [String: Any] else {
|
|
@@ -355,19 +397,154 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
355
397
|
}
|
|
356
398
|
}
|
|
357
399
|
|
|
358
|
-
|
|
400
|
+
@discardableResult
|
|
401
|
+
func presentView(webViewId: String? = nil, isAnimated: Bool = true) -> Bool {
|
|
359
402
|
let resolvedId = webViewId ?? activeWebViewId
|
|
360
403
|
let navigationController = resolvedId.flatMap { navigationControllers[$0] } ?? self.navigationWebViewController
|
|
361
404
|
guard let navigationController else {
|
|
362
405
|
self.currentPluginCall?.reject("Navigation controller is not initialized")
|
|
363
|
-
return
|
|
406
|
+
return false
|
|
364
407
|
}
|
|
365
408
|
|
|
409
|
+
if let resolvedId,
|
|
410
|
+
let webViewController = webViewControllers[resolvedId],
|
|
411
|
+
webViewController.isLayeredBehind {
|
|
412
|
+
if !sendNavigationControllerToBack(id: resolvedId, transparentBackground: webViewController.transparentHostBackground) {
|
|
413
|
+
self.currentPluginCall?.reject("Failed to send webview to back")
|
|
414
|
+
return false
|
|
415
|
+
}
|
|
416
|
+
return true
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if let resolvedId {
|
|
420
|
+
detachLayeredWebView(id: resolvedId)
|
|
421
|
+
}
|
|
366
422
|
dismissActiveKeyboard()
|
|
367
423
|
let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
|
|
368
424
|
presenter?.present(navigationController, animated: isAnimated, completion: {
|
|
369
425
|
self.currentPluginCall?.resolve()
|
|
370
426
|
})
|
|
427
|
+
return true
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private func targetFrame(for webViewController: WKWebViewController, in hostWebView: UIView) -> CGRect {
|
|
431
|
+
return CustomWebViewFrameSupport.resolvedFrame(
|
|
432
|
+
width: webViewController.customWidth,
|
|
433
|
+
height: webViewController.customHeight,
|
|
434
|
+
x: webViewController.customX,
|
|
435
|
+
y: webViewController.customY,
|
|
436
|
+
fallbackSize: hostWebView.bounds.size
|
|
437
|
+
) ?? hostWebView.bounds
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
@discardableResult
|
|
441
|
+
private func sendNavigationControllerToBack(id: String, transparentBackground: Bool) -> Bool {
|
|
442
|
+
guard let navigationController = navigationControllers[id],
|
|
443
|
+
let webViewController = webViewControllers[id],
|
|
444
|
+
let hostWebView = self.bridge?.webView else {
|
|
445
|
+
return false
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if let webView = webViewController.capableWebView, webView.superview !== webViewController.view {
|
|
449
|
+
cleanupHiddenWebViewContainer(for: webView)
|
|
450
|
+
attachWebViewToController(webViewController, webView: webView)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
dismissActiveKeyboard()
|
|
454
|
+
navigationController.view.removeFromSuperview()
|
|
455
|
+
if transparentBackground {
|
|
456
|
+
makeHostWebViewTransparent(for: id)
|
|
457
|
+
} else {
|
|
458
|
+
restoreHostWebViewBackgroundIfNeeded(for: id)
|
|
459
|
+
}
|
|
460
|
+
navigationController.view.frame = targetFrame(for: webViewController, in: hostWebView)
|
|
461
|
+
navigationController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
462
|
+
navigationController.view.isUserInteractionEnabled = false
|
|
463
|
+
hostWebView.addSubview(navigationController.view)
|
|
464
|
+
hostWebView.sendSubviewToBack(navigationController.view)
|
|
465
|
+
navigationController.view.setNeedsLayout()
|
|
466
|
+
navigationController.view.layoutIfNeeded()
|
|
467
|
+
|
|
468
|
+
layeredWebViewIds.insert(id)
|
|
469
|
+
webViewController.isLayeredBehind = true
|
|
470
|
+
webViewController.transparentHostBackground = transparentBackground
|
|
471
|
+
return true
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
private func detachLayeredWebView(id: String) {
|
|
475
|
+
if let navigationController = navigationControllers[id] {
|
|
476
|
+
if navigationController.view.superview === self.bridge?.webView {
|
|
477
|
+
navigationController.view.removeFromSuperview()
|
|
478
|
+
}
|
|
479
|
+
navigationController.view.isUserInteractionEnabled = true
|
|
480
|
+
}
|
|
481
|
+
layeredWebViewIds.remove(id)
|
|
482
|
+
restoreHostWebViewBackgroundIfNeeded(for: id)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
private func storeSubviewBackgrounds(from view: UIView) {
|
|
486
|
+
for subview in view.subviews {
|
|
487
|
+
originalHostSubviewBackgrounds.append((subview, subview.backgroundColor, subview.isOpaque))
|
|
488
|
+
storeSubviewBackgrounds(from: subview)
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
private func clearBackgrounds(in view: UIView) {
|
|
493
|
+
view.isOpaque = false
|
|
494
|
+
view.backgroundColor = .clear
|
|
495
|
+
view.subviews.forEach { clearBackgrounds(in: $0) }
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private func makeHostWebViewTransparent(for id: String) {
|
|
499
|
+
guard let hostWebView = self.bridge?.webView else {
|
|
500
|
+
return
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
transparentHostWebViewIds.insert(id)
|
|
504
|
+
if !hasStoredHostWebViewAppearance {
|
|
505
|
+
hasStoredHostWebViewAppearance = true
|
|
506
|
+
originalHostWebViewBackgroundColor = hostWebView.backgroundColor
|
|
507
|
+
originalHostWebViewIsOpaque = hostWebView.isOpaque
|
|
508
|
+
originalHostSuperviewBackgroundColor = hostWebView.superview?.backgroundColor
|
|
509
|
+
originalHostSuperviewIsOpaque = hostWebView.superview?.isOpaque ?? true
|
|
510
|
+
originalHostSubviewBackgrounds.removeAll()
|
|
511
|
+
storeSubviewBackgrounds(from: hostWebView)
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
clearBackgrounds(in: hostWebView)
|
|
515
|
+
hostWebView.superview?.isOpaque = false
|
|
516
|
+
hostWebView.superview?.backgroundColor = .clear
|
|
517
|
+
hostWebView.setNeedsLayout()
|
|
518
|
+
hostWebView.layoutIfNeeded()
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private func restoreHostWebViewBackgroundIfNeeded(for id: String? = nil) {
|
|
522
|
+
if let id {
|
|
523
|
+
transparentHostWebViewIds.remove(id)
|
|
524
|
+
} else {
|
|
525
|
+
transparentHostWebViewIds.removeAll()
|
|
526
|
+
}
|
|
527
|
+
guard transparentHostWebViewIds.isEmpty, hasStoredHostWebViewAppearance else {
|
|
528
|
+
return
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if let hostWebView = self.bridge?.webView {
|
|
532
|
+
hostWebView.backgroundColor = originalHostWebViewBackgroundColor
|
|
533
|
+
hostWebView.isOpaque = originalHostWebViewIsOpaque
|
|
534
|
+
hostWebView.superview?.backgroundColor = originalHostSuperviewBackgroundColor
|
|
535
|
+
hostWebView.superview?.isOpaque = originalHostSuperviewIsOpaque
|
|
536
|
+
for (view, backgroundColor, isOpaque) in originalHostSubviewBackgrounds {
|
|
537
|
+
view.backgroundColor = backgroundColor
|
|
538
|
+
view.isOpaque = isOpaque
|
|
539
|
+
}
|
|
540
|
+
hostWebView.setNeedsLayout()
|
|
541
|
+
hostWebView.layoutIfNeeded()
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
hasStoredHostWebViewAppearance = false
|
|
545
|
+
originalHostWebViewBackgroundColor = nil
|
|
546
|
+
originalHostSuperviewBackgroundColor = nil
|
|
547
|
+
originalHostSubviewBackgrounds.removeAll()
|
|
371
548
|
}
|
|
372
549
|
|
|
373
550
|
private func dismissActiveKeyboard() {
|
|
@@ -568,6 +745,24 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
568
745
|
}
|
|
569
746
|
}
|
|
570
747
|
|
|
748
|
+
@objc func clearAllBrowsingData(_ call: CAPPluginCall) {
|
|
749
|
+
DispatchQueue.main.async {
|
|
750
|
+
let dataStores = self.allBrowsingDataStores()
|
|
751
|
+
let dataTypes = WKWebsiteDataStore.allWebsiteDataTypes()
|
|
752
|
+
let group = DispatchGroup()
|
|
753
|
+
for dataStore in dataStores {
|
|
754
|
+
group.enter()
|
|
755
|
+
dataStore.removeData(ofTypes: dataTypes,
|
|
756
|
+
modifiedSince: Date(timeIntervalSince1970: 0)) {
|
|
757
|
+
group.leave()
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
group.notify(queue: .main) {
|
|
761
|
+
call.resolve()
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
571
766
|
@objc func clearCookies(_ call: CAPPluginCall) {
|
|
572
767
|
guard let url = call.getString("url"),
|
|
573
768
|
let host = URL(string: url)?.host else {
|
|
@@ -767,12 +962,15 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
767
962
|
let enabledSafeBottomMargin = call.getBool("enabledSafeBottomMargin", false)
|
|
768
963
|
let enabledSafeTopMargin = call.getBool("enabledSafeTopMargin", true)
|
|
769
964
|
let hidden = call.getBool("hidden", false)
|
|
965
|
+
let toBack = call.getBool("toBack", false)
|
|
966
|
+
let transparentBackground = call.getBool("transparentBackground", true)
|
|
770
967
|
self.isHidden = hidden
|
|
771
968
|
let hiddenPopupWindow = call.getBool("hiddenPopupWindow", false)
|
|
772
969
|
let allowWebViewJsVisibilityControl = self.getConfig().getBoolean("allowWebViewJsVisibilityControl", false)
|
|
773
970
|
let allowScreenshotsFromWebPage = call.getBool("allowScreenshotsFromWebPage", false)
|
|
774
971
|
let captureConsoleLogs = call.getBool("captureConsoleLogs", false)
|
|
775
972
|
let handleDownloads = call.getBool("handleDownloads", false)
|
|
973
|
+
let persistWebViewData = call.getBool("persistWebViewData", true)
|
|
776
974
|
let invisibilityModeRaw = call.getString("invisibilityMode", "AWARE")
|
|
777
975
|
self.invisibilityMode = InvisibilityMode(rawValue: invisibilityModeRaw.uppercased()) ?? .aware
|
|
778
976
|
|
|
@@ -914,38 +1112,36 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
914
1112
|
self.proxyBridges[webViewId] = proxyBridge
|
|
915
1113
|
}
|
|
916
1114
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1115
|
+
let webViewController = WKWebViewController()
|
|
1116
|
+
webViewController.blankNavigationTab = toolbarType == "blank"
|
|
1117
|
+
webViewController.enabledSafeBottomMargin = enabledSafeBottomMargin
|
|
1118
|
+
webViewController.enabledSafeTopMargin = enabledSafeTopMargin
|
|
1119
|
+
webViewController.source = .remote(url)
|
|
1120
|
+
webViewController.setCredentials(credentials: credentials)
|
|
1121
|
+
webViewController.allowWebViewJsVisibilityControl = allowWebViewJsVisibilityControl
|
|
1122
|
+
webViewController.allowScreenshotsFromWebPage = allowScreenshotsFromWebPage
|
|
1123
|
+
webViewController.captureConsoleLogs = captureConsoleLogs
|
|
1124
|
+
webViewController.proxyRequests = legacyProxyRequests.isEnabled
|
|
1125
|
+
webViewController.proxySchemeHandler = proxyHandler
|
|
1126
|
+
webViewController.proxyBridge = proxyBridge
|
|
1127
|
+
webViewController.proxyBridgeAccessToken = proxyBridgeAccessToken
|
|
1128
|
+
webViewController.legacyProxyRequestURLRegexPattern = legacyProxyRequests.urlRegex?.pattern
|
|
1129
|
+
webViewController.openBlankTargetInWebView = openBlankTargetInWebView
|
|
1130
|
+
webViewController.persistWebViewData = persistWebViewData
|
|
1131
|
+
webViewController.setHeaders(headers: headers)
|
|
1132
|
+
webViewController.setPreventDeeplink(preventDeeplink: preventDeeplink)
|
|
1133
|
+
webViewController.setBlockedHosts(blockedHosts: blockedHosts)
|
|
1134
|
+
webViewController.setAuthorizedAppLinks(authorizedAppLinks: authorizedAppLinks)
|
|
1135
|
+
webViewController.documentStartUserScripts = self.documentStartUserScripts(
|
|
927
1136
|
authorizedAppLinks: authorizedAppLinks,
|
|
928
|
-
allowWebViewJsVisibilityControl: allowWebViewJsVisibilityControl,
|
|
929
|
-
allowScreenshotsFromWebPage: allowScreenshotsFromWebPage,
|
|
930
|
-
captureConsoleLogs: captureConsoleLogs,
|
|
931
|
-
proxyRequests: legacyProxyRequests.isEnabled,
|
|
932
|
-
proxySchemeHandler: proxyHandler,
|
|
933
|
-
proxyBridge: proxyBridge,
|
|
934
|
-
proxyBridgeAccessToken: proxyBridgeAccessToken,
|
|
935
|
-
legacyProxyRequestURLRegexPattern: legacyProxyRequests.urlRegex?.pattern,
|
|
936
|
-
documentStartUserScripts: self.documentStartUserScripts(
|
|
937
|
-
authorizedAppLinks: authorizedAppLinks,
|
|
938
|
-
openBlankTargetInWebView: openBlankTargetInWebView
|
|
939
|
-
),
|
|
940
1137
|
openBlankTargetInWebView: openBlankTargetInWebView
|
|
941
1138
|
)
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
call.reject("Failed to initialize WebViewController")
|
|
945
|
-
return
|
|
946
|
-
}
|
|
1139
|
+
webViewController.initWebview(isInspectable: isInspectable)
|
|
1140
|
+
self.webViewController = webViewController
|
|
947
1141
|
|
|
948
1142
|
webViewController.instanceId = webViewId
|
|
1143
|
+
webViewController.isLayeredBehind = toBack
|
|
1144
|
+
webViewController.transparentHostBackground = transparentBackground
|
|
949
1145
|
|
|
950
1146
|
// Set HTTP method and body if provided
|
|
951
1147
|
if let method = httpMethod {
|
|
@@ -1178,7 +1374,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1178
1374
|
}
|
|
1179
1375
|
|
|
1180
1376
|
// Configure modal presentation for touch passthrough if custom dimensions are set
|
|
1181
|
-
if width != nil || height != nil {
|
|
1377
|
+
if (width != nil || height != nil) && !toBack {
|
|
1182
1378
|
self.navigationWebViewController?.modalPresentationStyle = .overFullScreen
|
|
1183
1379
|
|
|
1184
1380
|
// Create a pass-through container
|
|
@@ -1268,7 +1464,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1268
1464
|
return
|
|
1269
1465
|
}
|
|
1270
1466
|
} else if !self.isPresentAfterPageLoad {
|
|
1271
|
-
self.presentView(webViewId: webViewId, isAnimated: isAnimated)
|
|
1467
|
+
guard self.presentView(webViewId: webViewId, isAnimated: isAnimated) else {
|
|
1468
|
+
return
|
|
1469
|
+
}
|
|
1272
1470
|
}
|
|
1273
1471
|
call.resolve(["id": webViewId])
|
|
1274
1472
|
}
|
|
@@ -1334,42 +1532,35 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1334
1532
|
self.isHidden = hidden
|
|
1335
1533
|
|
|
1336
1534
|
if hidden {
|
|
1337
|
-
if let
|
|
1338
|
-
|
|
1339
|
-
navController.view.isUserInteractionEnabled = false
|
|
1340
|
-
if let containerView = navController.view.superview {
|
|
1341
|
-
if self.presentationContainerView == nil || self.presentationContainerView !== containerView {
|
|
1342
|
-
self.presentationContainerView = containerView
|
|
1343
|
-
self.presentationContainerWasInteractive = containerView.isUserInteractionEnabled
|
|
1344
|
-
self.presentationContainerPreviousAlpha = containerView.alpha
|
|
1345
|
-
}
|
|
1346
|
-
containerView.isUserInteractionEnabled = false
|
|
1347
|
-
containerView.alpha = 0
|
|
1348
|
-
}
|
|
1535
|
+
if let resolvedId {
|
|
1536
|
+
self.detachLayeredWebView(id: resolvedId)
|
|
1349
1537
|
}
|
|
1350
|
-
|
|
1351
1538
|
if !self.attachWebViewToWindow(webView) {
|
|
1352
1539
|
call?.reject("Failed to get active window for hidden webview")
|
|
1353
1540
|
return
|
|
1354
1541
|
}
|
|
1542
|
+
self.dismissNavigationControllerIfPresented(navigationController)
|
|
1355
1543
|
} else {
|
|
1356
1544
|
if webView.superview !== webViewController.view {
|
|
1357
1545
|
self.attachWebViewToController(webViewController, webView: webView)
|
|
1358
1546
|
}
|
|
1359
1547
|
|
|
1548
|
+
if webViewController.isLayeredBehind, let resolvedId {
|
|
1549
|
+
if self.sendNavigationControllerToBack(id: resolvedId, transparentBackground: webViewController.transparentHostBackground) {
|
|
1550
|
+
if let navController = navigationController {
|
|
1551
|
+
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navController)
|
|
1552
|
+
}
|
|
1553
|
+
call?.resolve()
|
|
1554
|
+
} else {
|
|
1555
|
+
call?.reject("Failed to send webview to back")
|
|
1556
|
+
}
|
|
1557
|
+
return
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1360
1560
|
if let navController = navigationController {
|
|
1361
1561
|
if let resolvedId {
|
|
1362
1562
|
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navController)
|
|
1363
1563
|
}
|
|
1364
|
-
navController.view.isHidden = false
|
|
1365
|
-
navController.view.isUserInteractionEnabled = true
|
|
1366
|
-
if let containerView = self.presentationContainerView {
|
|
1367
|
-
containerView.isUserInteractionEnabled = self.presentationContainerWasInteractive
|
|
1368
|
-
containerView.alpha = self.presentationContainerPreviousAlpha
|
|
1369
|
-
self.presentationContainerView = nil
|
|
1370
|
-
self.presentationContainerWasInteractive = true
|
|
1371
|
-
self.presentationContainerPreviousAlpha = 1
|
|
1372
|
-
}
|
|
1373
1564
|
|
|
1374
1565
|
if navController.presentingViewController == nil {
|
|
1375
1566
|
let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
|
|
@@ -1404,6 +1595,200 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1404
1595
|
self.setHiddenState(false, targetId: call.getString("id"), call: call)
|
|
1405
1596
|
}
|
|
1406
1597
|
|
|
1598
|
+
@objc func sendToBack(_ call: CAPPluginCall) {
|
|
1599
|
+
DispatchQueue.main.async {
|
|
1600
|
+
let targetId = call.getString("id") ?? self.activeWebViewId
|
|
1601
|
+
guard let resolvedId = targetId,
|
|
1602
|
+
let webViewController = self.resolveWebViewController(for: resolvedId),
|
|
1603
|
+
let navigationController = self.resolveNavigationController(for: resolvedId) else {
|
|
1604
|
+
call.reject("WebView is not initialized")
|
|
1605
|
+
return
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
let transparentBackground = call.getBool("transparentBackground", true)
|
|
1609
|
+
self.dismissNavigationControllerIfPresented(navigationController) {
|
|
1610
|
+
webViewController.isLayeredBehind = true
|
|
1611
|
+
webViewController.transparentHostBackground = transparentBackground
|
|
1612
|
+
guard self.sendNavigationControllerToBack(id: resolvedId, transparentBackground: transparentBackground) else {
|
|
1613
|
+
call.reject("Failed to send webview to back")
|
|
1614
|
+
return
|
|
1615
|
+
}
|
|
1616
|
+
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navigationController)
|
|
1617
|
+
call.resolve()
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
@objc func bringToFront(_ call: CAPPluginCall) {
|
|
1623
|
+
DispatchQueue.main.async {
|
|
1624
|
+
let targetId = call.getString("id") ?? self.activeWebViewId
|
|
1625
|
+
guard let resolvedId = targetId,
|
|
1626
|
+
let webViewController = self.resolveWebViewController(for: resolvedId),
|
|
1627
|
+
let navigationController = self.resolveNavigationController(for: resolvedId) else {
|
|
1628
|
+
call.reject("WebView is not initialized")
|
|
1629
|
+
return
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
webViewController.isLayeredBehind = false
|
|
1633
|
+
webViewController.transparentHostBackground = true
|
|
1634
|
+
self.detachLayeredWebView(id: resolvedId)
|
|
1635
|
+
if let webView = webViewController.capableWebView, webView.superview !== webViewController.view {
|
|
1636
|
+
self.attachWebViewToController(webViewController, webView: webView)
|
|
1637
|
+
}
|
|
1638
|
+
self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navigationController)
|
|
1639
|
+
if navigationController.presentingViewController == nil {
|
|
1640
|
+
let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
|
|
1641
|
+
presenter?.present(navigationController, animated: true, completion: {
|
|
1642
|
+
call.resolve()
|
|
1643
|
+
})
|
|
1644
|
+
return
|
|
1645
|
+
}
|
|
1646
|
+
call.resolve()
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
private func jsNumber(_ value: Float?, fallback: String = "0") -> String {
|
|
1651
|
+
guard let value, value.isFinite else {
|
|
1652
|
+
return fallback
|
|
1653
|
+
}
|
|
1654
|
+
return String(Double(value))
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
private func dispatchInputScript(type: String, x: Float?, y: Float?, deltaX: Float?, deltaY: Float?) -> String? {
|
|
1658
|
+
if type == "scroll" {
|
|
1659
|
+
guard let x, let y, let deltaX, let deltaY,
|
|
1660
|
+
x.isFinite, y.isFinite, deltaX.isFinite, deltaY.isFinite else {
|
|
1661
|
+
return nil
|
|
1662
|
+
}
|
|
1663
|
+
let xLiteral = jsNumber(x)
|
|
1664
|
+
let yLiteral = jsNumber(y)
|
|
1665
|
+
let deltaXLiteral = jsNumber(deltaX)
|
|
1666
|
+
let deltaYLiteral = jsNumber(deltaY)
|
|
1667
|
+
return """
|
|
1668
|
+
(function() {
|
|
1669
|
+
const x = \(xLiteral);
|
|
1670
|
+
const y = \(yLiteral);
|
|
1671
|
+
const dx = \(deltaXLiteral);
|
|
1672
|
+
const dy = \(deltaYLiteral);
|
|
1673
|
+
let target = Number.isFinite(x) && Number.isFinite(y) ? document.elementFromPoint(x, y) : null;
|
|
1674
|
+
while (target && target !== document.body && target !== document.documentElement) {
|
|
1675
|
+
const style = window.getComputedStyle(target);
|
|
1676
|
+
const canScroll = /(auto|scroll)/.test(style.overflow + style.overflowX + style.overflowY) &&
|
|
1677
|
+
(target.scrollHeight > target.clientHeight || target.scrollWidth > target.clientWidth);
|
|
1678
|
+
if (canScroll && typeof target.scrollBy === 'function') {
|
|
1679
|
+
target.scrollBy(dx, dy);
|
|
1680
|
+
return true;
|
|
1681
|
+
}
|
|
1682
|
+
target = target.parentElement;
|
|
1683
|
+
}
|
|
1684
|
+
window.scrollBy(dx, dy);
|
|
1685
|
+
return true;
|
|
1686
|
+
})();
|
|
1687
|
+
"""
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
let pointerEvents: [String]
|
|
1691
|
+
let mouseEvents: [String]
|
|
1692
|
+
let touchEvents: [String]
|
|
1693
|
+
switch type {
|
|
1694
|
+
case "click":
|
|
1695
|
+
pointerEvents = ["pointerdown", "pointerup"]
|
|
1696
|
+
mouseEvents = ["mousedown", "mouseup", "click"]
|
|
1697
|
+
touchEvents = ["touchstart", "touchend"]
|
|
1698
|
+
case "touchstart":
|
|
1699
|
+
pointerEvents = ["pointerdown"]
|
|
1700
|
+
mouseEvents = ["mousedown"]
|
|
1701
|
+
touchEvents = ["touchstart"]
|
|
1702
|
+
case "touchmove":
|
|
1703
|
+
pointerEvents = ["pointermove"]
|
|
1704
|
+
mouseEvents = ["mousemove"]
|
|
1705
|
+
touchEvents = ["touchmove"]
|
|
1706
|
+
case "touchend":
|
|
1707
|
+
pointerEvents = ["pointerup"]
|
|
1708
|
+
mouseEvents = ["mouseup"]
|
|
1709
|
+
touchEvents = ["touchend"]
|
|
1710
|
+
case "touchcancel":
|
|
1711
|
+
pointerEvents = ["pointercancel"]
|
|
1712
|
+
mouseEvents = []
|
|
1713
|
+
touchEvents = ["touchcancel"]
|
|
1714
|
+
default:
|
|
1715
|
+
return nil
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
guard let x, let y, x.isFinite, y.isFinite else {
|
|
1719
|
+
return nil
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
let pointerEventsData = try? JSONSerialization.data(withJSONObject: pointerEvents)
|
|
1723
|
+
let mouseEventsData = try? JSONSerialization.data(withJSONObject: mouseEvents)
|
|
1724
|
+
let touchEventsData = try? JSONSerialization.data(withJSONObject: touchEvents)
|
|
1725
|
+
let pointerEventsJSON = pointerEventsData.flatMap { String(data: $0, encoding: .utf8) } ?? "[]"
|
|
1726
|
+
let mouseEventsJSON = mouseEventsData.flatMap { String(data: $0, encoding: .utf8) } ?? "[]"
|
|
1727
|
+
let touchEventsJSON = touchEventsData.flatMap { String(data: $0, encoding: .utf8) } ?? "[]"
|
|
1728
|
+
|
|
1729
|
+
return """
|
|
1730
|
+
(function() {
|
|
1731
|
+
const x = \(jsNumber(x));
|
|
1732
|
+
const y = \(jsNumber(y));
|
|
1733
|
+
const target = document.elementFromPoint(x, y);
|
|
1734
|
+
if (!target) return false;
|
|
1735
|
+
const base = { bubbles: true, cancelable: true, composed: true, clientX: x, clientY: y, screenX: x, screenY: y };
|
|
1736
|
+
for (const name of \(pointerEventsJSON)) {
|
|
1737
|
+
if (typeof PointerEvent === 'function') {
|
|
1738
|
+
target.dispatchEvent(new PointerEvent(name, Object.assign({}, base, { pointerId: 1, pointerType: 'touch', isPrimary: true })));
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
for (const name of \(mouseEventsJSON)) {
|
|
1742
|
+
target.dispatchEvent(new MouseEvent(name, base));
|
|
1743
|
+
}
|
|
1744
|
+
if (typeof TouchEvent === 'function' && typeof Touch === 'function') {
|
|
1745
|
+
for (const name of \(touchEventsJSON)) {
|
|
1746
|
+
try {
|
|
1747
|
+
const touch = new Touch({ identifier: 1, target: target, clientX: x, clientY: y, screenX: x, screenY: y });
|
|
1748
|
+
const activeTouches = name === 'touchend' || name === 'touchcancel' ? [] : [touch];
|
|
1749
|
+
target.dispatchEvent(new TouchEvent(name, {
|
|
1750
|
+
bubbles: true,
|
|
1751
|
+
cancelable: true,
|
|
1752
|
+
composed: true,
|
|
1753
|
+
touches: activeTouches,
|
|
1754
|
+
targetTouches: activeTouches,
|
|
1755
|
+
changedTouches: [touch]
|
|
1756
|
+
}));
|
|
1757
|
+
} catch (_) {}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return true;
|
|
1761
|
+
})();
|
|
1762
|
+
"""
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
@objc func dispatchInputEvent(_ call: CAPPluginCall) {
|
|
1766
|
+
guard let type = call.getString("type") else {
|
|
1767
|
+
call.reject("Input event type is required")
|
|
1768
|
+
return
|
|
1769
|
+
}
|
|
1770
|
+
guard let script = dispatchInputScript(
|
|
1771
|
+
type: type,
|
|
1772
|
+
x: call.getFloat("x"),
|
|
1773
|
+
y: call.getFloat("y"),
|
|
1774
|
+
deltaX: call.getFloat("deltaX"),
|
|
1775
|
+
deltaY: call.getFloat("deltaY")
|
|
1776
|
+
) else {
|
|
1777
|
+
call.reject("Unsupported input event type or invalid input payload: \(type)")
|
|
1778
|
+
return
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
DispatchQueue.main.async {
|
|
1782
|
+
let targetId = call.getString("id") ?? self.activeWebViewId
|
|
1783
|
+
guard let webViewController = self.resolveWebViewController(for: targetId) else {
|
|
1784
|
+
call.reject("WebView is not initialized")
|
|
1785
|
+
return
|
|
1786
|
+
}
|
|
1787
|
+
webViewController.executeScript(script: script)
|
|
1788
|
+
call.resolve()
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1407
1792
|
@objc func executeScript(_ call: CAPPluginCall) {
|
|
1408
1793
|
guard let script = call.getString("code") else {
|
|
1409
1794
|
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
|
|