@capgo/capacitor-inappbrowser 8.10.7 → 8.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -110,7 +110,6 @@ enum CustomSchemeOpenSupport {
110
110
  }
111
111
  }
112
112
 
113
-
114
113
  protocol ProxyRequestLocating {
115
114
  func hasPendingProxyRequest(_ requestId: String) -> Bool
116
115
  }
@@ -149,7 +148,6 @@ enum ProxyResponseRoutingSupport {
149
148
  }
150
149
  }
151
150
 
152
-
153
151
  enum StatusBarBackgroundLayoutSupport {
154
152
  enum Placement: Equatable {
155
153
  case skip
@@ -232,7 +230,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
232
230
  case aware = "AWARE"
233
231
  case fakeVisible = "FAKE_VISIBLE"
234
232
  }
235
- private let pluginVersion: String = "8.10.7"
233
+ private let pluginVersion: String = "8.12.0"
236
234
  public let identifier = "CapgoInAppBrowserPlugin"
237
235
  public let jsName = "CapgoInAppBrowser"
238
236
  public let pluginMethods: [CAPPluginMethod] = [
@@ -279,6 +277,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
279
277
  private var hiddenWebViewContainers: [ObjectIdentifier: UIView] = [:]
280
278
  private var closeModalTitle: String?
281
279
  private var layeredWebViewIds = Set<String>()
280
+ private var framedOverlayWebViewIds = Set<String>()
282
281
  private var transparentHostWebViewIds = Set<String>()
283
282
  private var hasStoredHostWebViewAppearance = false
284
283
  private var originalHostWebViewBackgroundColor: UIColor?
@@ -339,6 +338,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
339
338
  }
340
339
 
341
340
  private func unregisterWebView(id: String) {
341
+ detachFramedOverlayWebView(id: id)
342
342
  detachLayeredWebView(id: id)
343
343
  if let webView = webViewControllers[id]?.capableWebView {
344
344
  cleanupHiddenWebViewContainer(for: webView)
@@ -606,7 +606,20 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
606
606
  return true
607
607
  }
608
608
 
609
+ if let resolvedId,
610
+ let webViewController = webViewControllers[resolvedId],
611
+ webViewController.shouldPresentAsFramedOverlay {
612
+ dismissActiveKeyboard()
613
+ if presentNavigationControllerAsFramedOverlay(id: resolvedId) {
614
+ self.currentPluginCall?.resolve()
615
+ return true
616
+ }
617
+ self.currentPluginCall?.reject("Failed to present webview")
618
+ return false
619
+ }
620
+
609
621
  if let resolvedId {
622
+ detachFramedOverlayWebView(id: resolvedId)
610
623
  detachLayeredWebView(id: resolvedId)
611
624
  }
612
625
  dismissActiveKeyboard()
@@ -621,61 +634,6 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
621
634
  return true
622
635
  }
623
636
 
624
- private func targetFrame(for webViewController: WKWebViewController, in hostWebView: UIView) -> CGRect {
625
- return CustomWebViewFrameSupport.resolvedFrame(
626
- width: webViewController.customWidth,
627
- height: webViewController.customHeight,
628
- x: webViewController.customX,
629
- y: webViewController.customY,
630
- fallbackSize: hostWebView.bounds.size
631
- ) ?? hostWebView.bounds
632
- }
633
-
634
- @discardableResult
635
- private func sendNavigationControllerToBack(id: String, transparentBackground: Bool) -> Bool {
636
- guard let navigationController = navigationControllers[id],
637
- let webViewController = webViewControllers[id],
638
- let hostWebView = self.bridge?.webView else {
639
- return false
640
- }
641
-
642
- if let webView = webViewController.capableWebView, webView.superview !== webViewController.view {
643
- cleanupHiddenWebViewContainer(for: webView)
644
- attachWebViewToController(webViewController, webView: webView)
645
- }
646
-
647
- dismissActiveKeyboard()
648
- navigationController.view.removeFromSuperview()
649
- if transparentBackground {
650
- makeHostWebViewTransparent(for: id)
651
- } else {
652
- restoreHostWebViewBackgroundIfNeeded(for: id)
653
- }
654
- navigationController.view.frame = targetFrame(for: webViewController, in: hostWebView)
655
- navigationController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
656
- navigationController.view.isUserInteractionEnabled = false
657
- hostWebView.addSubview(navigationController.view)
658
- hostWebView.sendSubviewToBack(navigationController.view)
659
- navigationController.view.setNeedsLayout()
660
- navigationController.view.layoutIfNeeded()
661
-
662
- layeredWebViewIds.insert(id)
663
- webViewController.isLayeredBehind = true
664
- webViewController.transparentHostBackground = transparentBackground
665
- return true
666
- }
667
-
668
- private func detachLayeredWebView(id: String) {
669
- if let navigationController = navigationControllers[id] {
670
- if navigationController.view.superview === self.bridge?.webView {
671
- navigationController.view.removeFromSuperview()
672
- }
673
- navigationController.view.isUserInteractionEnabled = true
674
- }
675
- layeredWebViewIds.remove(id)
676
- restoreHostWebViewBackgroundIfNeeded(for: id)
677
- }
678
-
679
637
  private func storeSubviewBackgrounds(from view: UIView) {
680
638
  for subview in view.subviews {
681
639
  originalHostSubviewBackgrounds.append((subview, subview.backgroundColor, subview.isOpaque))
@@ -1291,6 +1249,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1291
1249
 
1292
1250
  // Read disableOverscroll option (iOS only - controls WebView bounce effect)
1293
1251
  let disableOverscroll = call.getBool("disableOverscroll", false)
1252
+ let enableReloadGesture = call.getBool("enableReloadGesture", false)
1294
1253
 
1295
1254
  let legacyProxyRequests = ProxySchemeRequestSupport.legacyProxyRequestsConfiguration(from: call.options["proxyRequests"])
1296
1255
  let outboundProxyRulesRaw = call.getArray("outboundProxyRules", [])
@@ -1361,6 +1320,8 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1361
1320
  authorizedAppLinks: authorizedAppLinks,
1362
1321
  openBlankTargetInWebView: openBlankTargetInWebView
1363
1322
  )
1323
+ webViewController.enableReloadGesture = enableReloadGesture
1324
+ webViewController.disableOverscroll = disableOverscroll
1364
1325
  webViewController.initWebview(isInspectable: isInspectable)
1365
1326
  self.webViewController = webViewController
1366
1327
 
@@ -1390,8 +1351,6 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1390
1351
  webViewController.customY = CGFloat(yPos)
1391
1352
  }
1392
1353
 
1393
- // Set disableOverscroll option
1394
- webViewController.disableOverscroll = disableOverscroll
1395
1354
  webViewController.handleDownloads = handleDownloads
1396
1355
 
1397
1356
  // Set native navigation gestures before view loads
@@ -1603,42 +1562,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1603
1562
  }
1604
1563
  webViewController.updateTitleAppearance()
1605
1564
 
1606
- // Configure modal presentation for touch passthrough if custom dimensions are set
1607
- if (width != nil || height != nil) && !toBack {
1608
- self.navigationWebViewController?.modalPresentationStyle = .overFullScreen
1609
-
1610
- // Create a pass-through container
1611
- let containerView = PassThroughView()
1612
- containerView.backgroundColor = .clear
1613
- containerView.frame = UIScreen.main.bounds
1614
- containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
1615
- containerView.passthroughView = self.bridge?.webView
1616
-
1617
- let targetFrame = CustomWebViewFrameSupport.resolvedFrame(
1618
- width: width.map { CGFloat($0) },
1619
- height: height.map { CGFloat($0) },
1620
- x: xPos.map { CGFloat($0) },
1621
- y: yPos.map { CGFloat($0) },
1622
- fallbackSize: UIScreen.main.bounds.size
1623
- )
1624
- containerView.targetFrame = targetFrame
1625
-
1626
- // Replace the navigation controller's view with our pass-through container
1627
- if let navController = self.navigationWebViewController,
1628
- let originalView = navController.view {
1629
- navController.view = containerView
1630
- containerView.addSubview(originalView)
1631
- containerView.framedContentView = originalView
1632
- originalView.translatesAutoresizingMaskIntoConstraints = true
1633
- originalView.autoresizingMask = []
1634
- if let targetFrame {
1635
- originalView.frame = targetFrame
1636
- }
1637
- }
1638
- } else {
1639
- self.navigationWebViewController?.modalPresentationStyle = .overCurrentContext
1640
- }
1641
-
1565
+ // Custom width/height front browsers are attached as framed child overlays in
1566
+ // presentView (matching Android window sizing) so host taps outside the frame work.
1567
+ self.navigationWebViewController?.modalPresentationStyle = .overCurrentContext
1642
1568
  self.navigationWebViewController?.modalTransitionStyle = .crossDissolve
1643
1569
  if toolbarType == "blank" {
1644
1570
  self.navigationWebViewController?.navigationBar.isHidden = true
@@ -1765,6 +1691,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1765
1691
 
1766
1692
  if hidden {
1767
1693
  if let resolvedId {
1694
+ self.detachFramedOverlayWebView(id: resolvedId)
1768
1695
  self.detachLayeredWebView(id: resolvedId)
1769
1696
  }
1770
1697
  if !self.attachWebViewToWindow(webView) {
@@ -1793,9 +1720,22 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1793
1720
  if let navController = navigationController {
1794
1721
  if let resolvedId {
1795
1722
  self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navController)
1796
- }
1797
-
1798
- if navController.presentingViewController == nil {
1723
+ if navController.presentingViewController == nil && !self.framedOverlayWebViewIds.contains(resolvedId) {
1724
+ self.revealNavigationController(
1725
+ id: resolvedId,
1726
+ navigationController: navController,
1727
+ webViewController: webViewController,
1728
+ animated: true
1729
+ ) { presented in
1730
+ if presented {
1731
+ call?.resolve()
1732
+ } else {
1733
+ call?.reject("Failed to present webview")
1734
+ }
1735
+ }
1736
+ return
1737
+ }
1738
+ } else if navController.presentingViewController == nil {
1799
1739
  let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
1800
1740
  self.presentNavigationControllerSafely(navController, from: presenter, animated: true) { presented in
1801
1741
  if presented {
@@ -1873,9 +1813,13 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1873
1813
  self.attachWebViewToController(webViewController, webView: webView)
1874
1814
  }
1875
1815
  self.setActiveWebView(id: resolvedId, webView: webViewController, navigationController: navigationController)
1876
- if navigationController.presentingViewController == nil {
1877
- let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
1878
- self.presentNavigationControllerSafely(navigationController, from: presenter, animated: isAnimated) { presented in
1816
+ if navigationController.presentingViewController == nil && !self.framedOverlayWebViewIds.contains(resolvedId) {
1817
+ self.revealNavigationController(
1818
+ id: resolvedId,
1819
+ navigationController: navigationController,
1820
+ webViewController: webViewController,
1821
+ animated: isAnimated
1822
+ ) { presented in
1879
1823
  if presented {
1880
1824
  call.resolve()
1881
1825
  } else {
@@ -1884,6 +1828,12 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1884
1828
  }
1885
1829
  return
1886
1830
  }
1831
+ if webViewController.shouldPresentAsFramedOverlay {
1832
+ guard self.presentNavigationControllerAsFramedOverlay(id: resolvedId) else {
1833
+ call.reject("Failed to present webview")
1834
+ return
1835
+ }
1836
+ }
1887
1837
  call.resolve()
1888
1838
  }
1889
1839
  }
@@ -2117,7 +2067,6 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
2117
2067
  }
2118
2068
  }
2119
2069
 
2120
-
2121
2070
  /// Keep PassThroughView clear so custom y-offsets show the host app behind the gap.
2122
2071
  private func applyBlankToolbarBackground(_ color: UIColor, to navigationController: UINavigationController?) {
2123
2072
  guard let navigationController else { return }
@@ -2377,9 +2326,12 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
2377
2326
  let webViewController = self.webViewControllers[targetId],
2378
2327
  let navigationController = self.navigationControllers[targetId] {
2379
2328
  let currentUrl = webViewController.url?.absoluteString ?? ""
2329
+ let wasPresented = navigationController.presentingViewController != nil
2380
2330
  webViewController.cleanupWebView()
2381
2331
  self.handleWebViewDidClose(id: targetId, url: currentUrl)
2382
- navigationController.dismiss(animated: isAnimated, completion: nil)
2332
+ if wasPresented {
2333
+ navigationController.dismiss(animated: isAnimated, completion: nil)
2334
+ }
2383
2335
  call.resolve()
2384
2336
  return
2385
2337
  }
@@ -2415,7 +2367,6 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
2415
2367
  }
2416
2368
  }
2417
2369
 
2418
-
2419
2370
  private func showPrivacyScreen() {
2420
2371
  if privacyScreen == nil {
2421
2372
  let newPrivacyScreen = UIImageView()
@@ -2617,3 +2568,139 @@ extension CapgoInAppBrowserPlugin: SFSafariViewControllerDelegate {
2617
2568
  }
2618
2569
  }
2619
2570
  }
2571
+
2572
+
2573
+ extension CapgoInAppBrowserPlugin {
2574
+ private func targetFrame(for webViewController: WKWebViewController, in hostWebView: UIView) -> CGRect {
2575
+ return CustomWebViewFrameSupport.resolvedFrame(
2576
+ width: webViewController.customWidth,
2577
+ height: webViewController.customHeight,
2578
+ x: webViewController.customX,
2579
+ y: webViewController.customY,
2580
+ fallbackSize: hostWebView.bounds.size
2581
+ ) ?? hostWebView.bounds
2582
+ }
2583
+
2584
+ @discardableResult
2585
+ private func sendNavigationControllerToBack(id: String, transparentBackground: Bool) -> Bool {
2586
+ guard let navigationController = navigationControllers[id],
2587
+ let webViewController = webViewControllers[id],
2588
+ let hostWebView = self.bridge?.webView else {
2589
+ return false
2590
+ }
2591
+
2592
+ if let webView = webViewController.capableWebView, webView.superview !== webViewController.view {
2593
+ cleanupHiddenWebViewContainer(for: webView)
2594
+ attachWebViewToController(webViewController, webView: webView)
2595
+ }
2596
+
2597
+ dismissActiveKeyboard()
2598
+ detachFramedOverlayWebView(id: id)
2599
+ navigationController.view.removeFromSuperview()
2600
+ if transparentBackground {
2601
+ makeHostWebViewTransparent(for: id)
2602
+ } else {
2603
+ restoreHostWebViewBackgroundIfNeeded(for: id)
2604
+ }
2605
+ navigationController.view.frame = targetFrame(for: webViewController, in: hostWebView)
2606
+ navigationController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
2607
+ navigationController.view.isUserInteractionEnabled = false
2608
+ hostWebView.addSubview(navigationController.view)
2609
+ hostWebView.sendSubviewToBack(navigationController.view)
2610
+ navigationController.view.setNeedsLayout()
2611
+ navigationController.view.layoutIfNeeded()
2612
+
2613
+ layeredWebViewIds.insert(id)
2614
+ webViewController.isLayeredBehind = true
2615
+ webViewController.transparentHostBackground = transparentBackground
2616
+ return true
2617
+ }
2618
+
2619
+ private func detachLayeredWebView(id: String) {
2620
+ if let navigationController = navigationControllers[id] {
2621
+ if navigationController.view.superview === self.bridge?.webView {
2622
+ navigationController.view.removeFromSuperview()
2623
+ }
2624
+ navigationController.view.isUserInteractionEnabled = true
2625
+ }
2626
+ layeredWebViewIds.remove(id)
2627
+ restoreHostWebViewBackgroundIfNeeded(for: id)
2628
+ }
2629
+
2630
+ /// Front custom-dimension browsers are child VCs with an exact frame (Android-style).
2631
+ /// Full-screen modal + PassThroughView still leaves UITransitionView eating host taps.
2632
+ @discardableResult
2633
+ private func presentNavigationControllerAsFramedOverlay(id: String) -> Bool {
2634
+ guard let navigationController = navigationControllers[id],
2635
+ let webViewController = webViewControllers[id],
2636
+ let parent = self.bridge?.viewController else {
2637
+ return false
2638
+ }
2639
+
2640
+ dismissNavigationControllerIfPresented(navigationController)
2641
+ detachLayeredWebView(id: id)
2642
+
2643
+ let frame = targetFrame(for: webViewController, in: parent.view)
2644
+
2645
+ if navigationController.parent !== parent {
2646
+ if navigationController.parent != nil {
2647
+ navigationController.willMove(toParent: nil)
2648
+ navigationController.view.removeFromSuperview()
2649
+ navigationController.removeFromParent()
2650
+ }
2651
+ parent.addChild(navigationController)
2652
+ parent.view.addSubview(navigationController.view)
2653
+ navigationController.didMove(toParent: parent)
2654
+ } else if navigationController.view.superview !== parent.view {
2655
+ parent.view.addSubview(navigationController.view)
2656
+ }
2657
+
2658
+ navigationController.view.frame = frame
2659
+ navigationController.view.autoresizingMask = []
2660
+ navigationController.view.isUserInteractionEnabled = true
2661
+ parent.view.bringSubviewToFront(navigationController.view)
2662
+ navigationController.view.setNeedsLayout()
2663
+ navigationController.view.layoutIfNeeded()
2664
+ webViewController.applyCustomDimensions()
2665
+
2666
+ framedOverlayWebViewIds.insert(id)
2667
+ webViewController.isLayeredBehind = false
2668
+ return true
2669
+ }
2670
+
2671
+ private func detachFramedOverlayWebView(id: String) {
2672
+ guard let navigationController = navigationControllers[id] else {
2673
+ framedOverlayWebViewIds.remove(id)
2674
+ return
2675
+ }
2676
+
2677
+ if navigationController.parent != nil {
2678
+ navigationController.willMove(toParent: nil)
2679
+ navigationController.view.removeFromSuperview()
2680
+ navigationController.removeFromParent()
2681
+ } else if framedOverlayWebViewIds.contains(id) {
2682
+ navigationController.view.removeFromSuperview()
2683
+ }
2684
+
2685
+ framedOverlayWebViewIds.remove(id)
2686
+ }
2687
+
2688
+ private func revealNavigationController(
2689
+ id: String,
2690
+ navigationController: UINavigationController,
2691
+ webViewController: WKWebViewController,
2692
+ animated: Bool,
2693
+ completion: ((Bool) -> Void)? = nil
2694
+ ) {
2695
+ if webViewController.shouldPresentAsFramedOverlay {
2696
+ completion?(presentNavigationControllerAsFramedOverlay(id: id))
2697
+ return
2698
+ }
2699
+
2700
+ detachFramedOverlayWebView(id: id)
2701
+ let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
2702
+ presentNavigationControllerSafely(navigationController, from: presenter, animated: animated, completion: completion)
2703
+ }
2704
+
2705
+ }
2706
+
@@ -471,6 +471,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
471
471
  var blockedHosts: [String] = []
472
472
  var authorizedAppLinks: [String] = []
473
473
  var activeNativeNavigationForWebview: Bool = true
474
+ var enableReloadGesture: Bool = false
474
475
  var disableOverscroll: Bool = false
475
476
  var proxyRequests: Bool = false
476
477
  var proxySchemeHandler: ProxySchemeHandler?
@@ -490,6 +491,11 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
490
491
  var customX: CGFloat?
491
492
  var customY: CGFloat?
492
493
 
494
+ /// Front (non-toBack) browsers with a custom height use a framed child overlay.
495
+ var shouldPresentAsFramedOverlay: Bool {
496
+ !isLayeredBehind && customHeight != nil
497
+ }
498
+
493
499
  internal var preShowSemaphore: DispatchSemaphore?
494
500
  internal var preShowError: String?
495
501
  private var isWebViewInitialized = false
@@ -2207,6 +2213,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2207
2213
 
2208
2214
  // Disable bounce effect by setting scrollView.bounces to false when disableOverscroll is true
2209
2215
  webView.scrollView.bounces = !self.disableOverscroll
2216
+ configureReloadGesture(for: webView)
2210
2217
  configureWebViewScrollViewSafeArea(webView)
2211
2218
 
2212
2219
  webView.addObserver(self, forKeyPath: estimatedProgressKeyPath, options: .new, context: nil)
@@ -2289,6 +2296,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2289
2296
  configuration.userContentController = WKUserContentController()
2290
2297
  self.initialWebConfiguration = configuration
2291
2298
  self.persistWebViewData = parent.persistWebViewData
2299
+ self.enableReloadGesture = parent.enableReloadGesture
2292
2300
  self.disableOverscroll = parent.disableOverscroll
2293
2301
  self.proxyRequests = parent.proxyRequests
2294
2302
  self.proxySchemeHandler = proxySchemeHandler
@@ -2431,6 +2439,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2431
2439
  }
2432
2440
  self.progressView?.alpha = 1
2433
2441
  self.progressView?.setProgress(Float(estimatedProgress), animated: true)
2442
+ self.emit("browserPageLoadProgress", data: ["progress": estimatedProgress])
2434
2443
 
2435
2444
  if estimatedProgress >= 1.0 {
2436
2445
  UIView.animate(withDuration: 0.3, delay: 0.3, options: .curveEaseOut, animations: {
@@ -2552,6 +2561,31 @@ public extension WKWebViewController {
2552
2561
  self.webView?.allowsBackForwardNavigationGestures = self.activeNativeNavigationForWebview
2553
2562
  }
2554
2563
 
2564
+ private func configureReloadGesture(for webView: WKWebView) {
2565
+ if let existing = webView.scrollView.refreshControl {
2566
+ existing.endRefreshing()
2567
+ existing.removeTarget(nil, action: nil, for: .allEvents)
2568
+ webView.scrollView.refreshControl = nil
2569
+ }
2570
+
2571
+ guard enableReloadGesture, !disableOverscroll else {
2572
+ return
2573
+ }
2574
+
2575
+ webView.scrollView.alwaysBounceVertical = true
2576
+ let refreshControl = UIRefreshControl()
2577
+ refreshControl.addTarget(self, action: #selector(handleReloadGesture(_:)), for: .valueChanged)
2578
+ webView.scrollView.refreshControl = refreshControl
2579
+ }
2580
+
2581
+ @objc private func handleReloadGesture(_ sender: UIRefreshControl) {
2582
+ reload()
2583
+ }
2584
+
2585
+ private func stopReloadGesture() {
2586
+ webView?.scrollView.refreshControl?.endRefreshing()
2587
+ }
2588
+
2555
2589
  func cleanupWebView() {
2556
2590
  guard let webView = self.webView else { return }
2557
2591
  webView.stopLoading()
@@ -3451,6 +3485,7 @@ extension WKWebViewController: WKNavigationDelegate {
3451
3485
  self.url = urlValue
3452
3486
  delegate?.webViewController?(self, didStart: urlValue)
3453
3487
  }
3488
+ emit("browserPageLoadStart")
3454
3489
  }
3455
3490
  public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
3456
3491
  if !didpageInit && self.capBrowserPlugin?.isPresentAfterPageLoad == true {
@@ -3501,6 +3536,7 @@ extension WKWebViewController: WKNavigationDelegate {
3501
3536
  lastInjectedSafeAreaInsets = nil
3502
3537
  syncWebViewSafeAreaLayout()
3503
3538
  emit("browserPageLoaded")
3539
+ stopReloadGesture()
3504
3540
  }
3505
3541
 
3506
3542
  public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
@@ -3510,6 +3546,7 @@ extension WKWebViewController: WKNavigationDelegate {
3510
3546
  self.url = url
3511
3547
  delegate?.webViewController?(self, didFail: url, withError: error)
3512
3548
  }
3549
+ stopReloadGesture()
3513
3550
  emit("pageLoadError")
3514
3551
  }
3515
3552
 
@@ -3520,6 +3557,7 @@ extension WKWebViewController: WKNavigationDelegate {
3520
3557
  self.url = url
3521
3558
  delegate?.webViewController?(self, didFail: url, withError: error)
3522
3559
  }
3560
+ stopReloadGesture()
3523
3561
  emit("pageLoadError")
3524
3562
  }
3525
3563
 
@@ -3659,14 +3697,18 @@ extension WKWebViewController: WKNavigationDelegate {
3659
3697
 
3660
3698
  /// Apply custom dimensions to the view if specified
3661
3699
  func applyCustomDimensions() {
3662
- guard let navigationController = navigationController,
3663
- let targetFrame = CustomWebViewFrameSupport.resolvedFrame(
3664
- width: customWidth,
3665
- height: customHeight,
3666
- x: customX,
3667
- y: customY,
3668
- fallbackSize: UIScreen.main.bounds.size
3669
- ) else {
3700
+ guard let navigationController = navigationController else {
3701
+ return
3702
+ }
3703
+
3704
+ let fallbackSize = navigationController.view.superview?.bounds.size ?? UIScreen.main.bounds.size
3705
+ guard let targetFrame = CustomWebViewFrameSupport.resolvedFrame(
3706
+ width: customWidth,
3707
+ height: customHeight,
3708
+ x: customX,
3709
+ y: customY,
3710
+ fallbackSize: fallbackSize
3711
+ ) else {
3670
3712
  return
3671
3713
  }
3672
3714
 
@@ -3827,7 +3869,6 @@ class PassThroughView: UIView {
3827
3869
  }
3828
3870
  }
3829
3871
  weak var framedContentView: UIView?
3830
- weak var passthroughView: UIView?
3831
3872
 
3832
3873
  override func layoutSubviews() {
3833
3874
  super.layoutSubviews()
@@ -3840,12 +3881,11 @@ class PassThroughView: UIView {
3840
3881
  }
3841
3882
 
3842
3883
  override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
3884
+ // Outside the browser frame: decline the hit. Callers that still use a full-screen
3885
+ // PassThroughView depend on the parent hierarchy continuing hit-testing; framed
3886
+ // front overlays avoid modal UITransitionView entirely instead.
3843
3887
  if let frame = targetFrame, !frame.contains(point) {
3844
- guard let passthroughView else {
3845
- return nil
3846
- }
3847
- let convertedPoint = convert(point, to: passthroughView)
3848
- return passthroughView.hitTest(convertedPoint, with: event)
3888
+ return nil
3849
3889
  }
3850
3890
 
3851
3891
  return super.hitTest(point, with: event)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-inappbrowser",
3
- "version": "8.10.7",
3
+ "version": "8.12.0",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",