@capgo/capacitor-inappbrowser 8.6.35 → 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.
@@ -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.6.35"
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?
@@ -178,14 +190,20 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
178
190
  }
179
191
  }
180
192
 
181
- private func dismissNavigationControllerIfPresented(_ navigationController: UINavigationController?) {
182
- guard let navigationController, navigationController.presentingViewController != nil else {
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?()
183
200
  return
184
201
  }
185
- navigationController.dismiss(animated: false)
202
+ navigationController.dismiss(animated: false, completion: completion)
186
203
  }
187
204
 
188
205
  private func unregisterWebView(id: String) {
206
+ detachLayeredWebView(id: id)
189
207
  if let webView = webViewControllers[id]?.capableWebView {
190
208
  cleanupHiddenWebViewContainer(for: webView)
191
209
  }
@@ -346,6 +364,26 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
346
364
  return stores
347
365
  }
348
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
+
349
387
  private func parseProxyRules(_ rawRules: [Any]) throws -> [NativeProxyRule] {
350
388
  try rawRules.enumerated().map { index, item in
351
389
  guard let dictionary = item as? [String: Any] else {
@@ -359,19 +397,154 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
359
397
  }
360
398
  }
361
399
 
362
- func presentView(webViewId: String? = nil, isAnimated: Bool = true) {
400
+ @discardableResult
401
+ func presentView(webViewId: String? = nil, isAnimated: Bool = true) -> Bool {
363
402
  let resolvedId = webViewId ?? activeWebViewId
364
403
  let navigationController = resolvedId.flatMap { navigationControllers[$0] } ?? self.navigationWebViewController
365
404
  guard let navigationController else {
366
405
  self.currentPluginCall?.reject("Navigation controller is not initialized")
367
- return
406
+ return false
407
+ }
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
368
417
  }
369
418
 
419
+ if let resolvedId {
420
+ detachLayeredWebView(id: resolvedId)
421
+ }
370
422
  dismissActiveKeyboard()
371
423
  let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
372
424
  presenter?.present(navigationController, animated: isAnimated, completion: {
373
425
  self.currentPluginCall?.resolve()
374
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()
375
548
  }
376
549
 
377
550
  private func dismissActiveKeyboard() {
@@ -572,6 +745,24 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
572
745
  }
573
746
  }
574
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
+
575
766
  @objc func clearCookies(_ call: CAPPluginCall) {
576
767
  guard let url = call.getString("url"),
577
768
  let host = URL(string: url)?.host else {
@@ -771,12 +962,15 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
771
962
  let enabledSafeBottomMargin = call.getBool("enabledSafeBottomMargin", false)
772
963
  let enabledSafeTopMargin = call.getBool("enabledSafeTopMargin", true)
773
964
  let hidden = call.getBool("hidden", false)
965
+ let toBack = call.getBool("toBack", false)
966
+ let transparentBackground = call.getBool("transparentBackground", true)
774
967
  self.isHidden = hidden
775
968
  let hiddenPopupWindow = call.getBool("hiddenPopupWindow", false)
776
969
  let allowWebViewJsVisibilityControl = self.getConfig().getBoolean("allowWebViewJsVisibilityControl", false)
777
970
  let allowScreenshotsFromWebPage = call.getBool("allowScreenshotsFromWebPage", false)
778
971
  let captureConsoleLogs = call.getBool("captureConsoleLogs", false)
779
972
  let handleDownloads = call.getBool("handleDownloads", false)
973
+ let persistWebViewData = call.getBool("persistWebViewData", true)
780
974
  let invisibilityModeRaw = call.getString("invisibilityMode", "AWARE")
781
975
  self.invisibilityMode = InvisibilityMode(rawValue: invisibilityModeRaw.uppercased()) ?? .aware
782
976
 
@@ -918,38 +1112,36 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
918
1112
  self.proxyBridges[webViewId] = proxyBridge
919
1113
  }
920
1114
 
921
- self.webViewController = WKWebViewController.init(
922
- url: url,
923
- headers: headers,
924
- isInspectable: isInspectable,
925
- credentials: credentials,
926
- preventDeeplink: preventDeeplink,
927
- blankNavigationTab: toolbarType == "blank",
928
- enabledSafeBottomMargin: enabledSafeBottomMargin,
929
- enabledSafeTopMargin: enabledSafeTopMargin,
930
- blockedHosts: blockedHosts,
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(
931
1136
  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
1137
  openBlankTargetInWebView: openBlankTargetInWebView
945
1138
  )
946
-
947
- guard let webViewController = self.webViewController else {
948
- call.reject("Failed to initialize WebViewController")
949
- return
950
- }
1139
+ webViewController.initWebview(isInspectable: isInspectable)
1140
+ self.webViewController = webViewController
951
1141
 
952
1142
  webViewController.instanceId = webViewId
1143
+ webViewController.isLayeredBehind = toBack
1144
+ webViewController.transparentHostBackground = transparentBackground
953
1145
 
954
1146
  // Set HTTP method and body if provided
955
1147
  if let method = httpMethod {
@@ -1182,7 +1374,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1182
1374
  }
1183
1375
 
1184
1376
  // Configure modal presentation for touch passthrough if custom dimensions are set
1185
- if width != nil || height != nil {
1377
+ if (width != nil || height != nil) && !toBack {
1186
1378
  self.navigationWebViewController?.modalPresentationStyle = .overFullScreen
1187
1379
 
1188
1380
  // Create a pass-through container
@@ -1272,7 +1464,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1272
1464
  return
1273
1465
  }
1274
1466
  } else if !self.isPresentAfterPageLoad {
1275
- self.presentView(webViewId: webViewId, isAnimated: isAnimated)
1467
+ guard self.presentView(webViewId: webViewId, isAnimated: isAnimated) else {
1468
+ return
1469
+ }
1276
1470
  }
1277
1471
  call.resolve(["id": webViewId])
1278
1472
  }
@@ -1338,6 +1532,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1338
1532
  self.isHidden = hidden
1339
1533
 
1340
1534
  if hidden {
1535
+ if let resolvedId {
1536
+ self.detachLayeredWebView(id: resolvedId)
1537
+ }
1341
1538
  if !self.attachWebViewToWindow(webView) {
1342
1539
  call?.reject("Failed to get active window for hidden webview")
1343
1540
  return
@@ -1348,6 +1545,18 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1348
1545
  self.attachWebViewToController(webViewController, webView: webView)
1349
1546
  }
1350
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
+
1351
1560
  if let navController = navigationController {
1352
1561
  if let resolvedId {
1353
1562
  self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navController)
@@ -1386,6 +1595,200 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1386
1595
  self.setHiddenState(false, targetId: call.getString("id"), call: call)
1387
1596
  }
1388
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
+
1389
1792
  @objc func executeScript(_ call: CAPPluginCall) {
1390
1793
  guard let script = call.getString("code") else {
1391
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
 
@@ -387,6 +387,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
387
387
  open var allowWebViewJsVisibilityControl = false
388
388
  open var allowScreenshotsFromWebPage = false
389
389
  open var captureConsoleLogs = false
390
+ open var persistWebViewData = true
390
391
  open var handleDownloads = false
391
392
  open var delegate: WKWebViewControllerDelegate?
392
393
  open var bypassedSSLHosts: [String]?
@@ -432,6 +433,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
432
433
  var waitsForPopupNavigation = false
433
434
  var hiddenPopupWindow = false
434
435
  var opensHidden = false
436
+ var isLayeredBehind = false
437
+ var transparentHostBackground = true
435
438
 
436
439
  // Dimension properties
437
440
  var customWidth: CGFloat?
@@ -748,8 +751,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
748
751
  .compactMap { $0 as? UIWindowScene }
749
752
  .first { $0.activationState == .foregroundActive }
750
753
  ?? UIApplication.shared.connectedScenes
751
- .compactMap { $0 as? UIWindowScene }
752
- .first
754
+ .compactMap { $0 as? UIWindowScene }
755
+ .first
753
756
  return windowScene?.statusBarManager?.statusBarFrame.height ?? 0
754
757
  }
755
758
 
@@ -1513,6 +1516,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1513
1516
  self.edgesForExtendedLayout = [.bottom]
1514
1517
 
1515
1518
  let webConfiguration = initialWebConfiguration ?? WKWebViewConfiguration()
1519
+ if !persistWebViewData {
1520
+ webConfiguration.websiteDataStore = .nonPersistent()
1521
+ }
1516
1522
  let userContentController = webConfiguration.userContentController
1517
1523
  userContentController.removeAllUserScripts()
1518
1524
  userContentController.removeScriptMessageHandler(forName: "messageHandler")
@@ -1763,6 +1769,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1763
1769
  self.blockedHosts = parent.blockedHosts
1764
1770
  self.authorizedAppLinks = parent.authorizedAppLinks
1765
1771
  self.activeNativeNavigationForWebview = parent.activeNativeNavigationForWebview
1772
+ self.initialWebConfiguration = configuration
1773
+ self.persistWebViewData = parent.persistWebViewData
1766
1774
  self.disableOverscroll = parent.disableOverscroll
1767
1775
  self.proxyRequests = parent.proxyRequests
1768
1776
  self.proxySchemeHandler = proxySchemeHandler
@@ -1935,7 +1943,6 @@ public extension WKWebViewController {
1935
1943
  return false
1936
1944
  }
1937
1945
 
1938
-
1939
1946
  func load(source sourceValue: WKWebSource) {
1940
1947
  switch sourceValue {
1941
1948
  case .remote(let url):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-inappbrowser",
3
- "version": "8.6.35",
3
+ "version": "8.7.0-beta.pr596.340.1",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",