@capgo/capacitor-inappbrowser 8.18.1 → 8.20.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.
@@ -446,13 +446,15 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
446
446
  case aware = "AWARE"
447
447
  case fakeVisible = "FAKE_VISIBLE"
448
448
  }
449
- private let pluginVersion: String = "8.18.1"
449
+ private let pluginVersion: String = "8.20.0"
450
450
  public let identifier = "CapgoInAppBrowserPlugin"
451
451
  public let jsName = "CapgoInAppBrowser"
452
452
  public let pluginMethods: [CAPPluginMethod] = [
453
453
  CAPPluginMethod(name: "goBack", returnType: CAPPluginReturnPromise),
454
454
  CAPPluginMethod(name: "open", returnType: CAPPluginReturnPromise),
455
455
  CAPPluginMethod(name: "openWebView", returnType: CAPPluginReturnPromise),
456
+ CAPPluginMethod(name: "setFullscreen", returnType: CAPPluginReturnPromise),
457
+ CAPPluginMethod(name: "getFullscreen", returnType: CAPPluginReturnPromise),
456
458
  CAPPluginMethod(name: "clearCookies", returnType: CAPPluginReturnPromise),
457
459
  CAPPluginMethod(name: "getCookies", returnType: CAPPluginReturnPromise),
458
460
  CAPPluginMethod(name: "clearAllCookies", returnType: CAPPluginReturnPromise),
@@ -555,6 +557,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
555
557
  }
556
558
 
557
559
  private func unregisterWebView(id: String) {
560
+ webViewControllers[id]?.setBrowserFullscreen(false)
558
561
  detachFramedOverlayWebView(id: id)
559
562
  detachLayeredWebView(id: id)
560
563
  if let webView = webViewControllers[id]?.capableWebView {
@@ -649,7 +652,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
649
652
  return nil
650
653
  }
651
654
 
652
- let navigationController = UINavigationController(rootViewController: popupController)
655
+ let navigationController = BrowserNavigationController(rootViewController: popupController)
653
656
  cloneNavigationAppearance(from: parentController.navigationController, to: navigationController)
654
657
  let shouldActivatePopup = ActiveWebViewSupport.shouldActivateNewWebView(
655
658
  isHidden: shouldHidePopup,
@@ -827,7 +830,15 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
827
830
  dismissActiveKeyboard()
828
831
  let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
829
832
  presentNavigationControllerSafely(navigationController, from: presenter, animated: isAnimated) { presented in
830
- if !presented {
833
+ if presented {
834
+ if let resolvedId,
835
+ let controller = self.webViewControllers[resolvedId],
836
+ self.navigationControllers[resolvedId] === navigationController,
837
+ navigationController.presentedViewController == nil,
838
+ !navigationController.isBeingDismissed {
839
+ self.setActiveWebView(id: resolvedId, webView: controller, navigationController: navigationController)
840
+ }
841
+ } else {
831
842
  // openWebView already resolves with the webView id on success.
832
843
  // Resolving here caused a double-resolve (empty, then with id). See #631.
833
844
  self.currentPluginCall?.reject("Failed to present webview")
@@ -1384,6 +1395,12 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1384
1395
  let screenshotOnHide = call.getBool("screenshotOnHide", false)
1385
1396
  let captureConsoleLogs = call.getBool("captureConsoleLogs", false)
1386
1397
  let handleDownloads = call.getBool("handleDownloads", false)
1398
+ if let rawDownloadPreview = call.getString("downloadPreview"),
1399
+ DownloadPreviewSupport.normalizedMode(rawDownloadPreview) == nil {
1400
+ call.reject("downloadPreview must be 'inAppBrowser' or 'systemPreview'")
1401
+ return
1402
+ }
1403
+ let downloadPreview = DownloadPreviewSupport.resolve(perOpenValue: call.getString("downloadPreview"))
1387
1404
  let persistWebViewData = call.getBool("persistWebViewData", true)
1388
1405
  let useSharedDataStore = call.getBool("useSharedDataStore", false)
1389
1406
  let clearCookiesOnOpen = call.getBool("clearCookiesOnOpen", false)
@@ -1480,6 +1497,11 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1480
1497
  let height = call.getFloat("height")
1481
1498
  let xPos = call.getFloat("x")
1482
1499
  let yPos = call.getFloat("y")
1500
+ let fullscreen = call.getBool("fullscreen", false)
1501
+ if fullscreen && (toBack || width != nil || height != nil || xPos != nil || yPos != nil) {
1502
+ call.reject("Fullscreen is not supported for framed or behind-host WebViews")
1503
+ return
1504
+ }
1483
1505
 
1484
1506
  // Read disableOverscroll option (iOS only - controls WebView bounce effect)
1485
1507
  let disableOverscroll = call.getBool("disableOverscroll", false)
@@ -1595,6 +1617,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1595
1617
  }
1596
1618
 
1597
1619
  webViewController.handleDownloads = handleDownloads
1620
+ webViewController.downloadPreview = downloadPreview
1598
1621
 
1599
1622
  // Set native navigation gestures before view loads
1600
1623
  webViewController.activeNativeNavigationForWebview = activeNativeNavigationForWebview
@@ -1746,7 +1769,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1746
1769
  }
1747
1770
  }
1748
1771
 
1749
- self.navigationWebViewController = UINavigationController.init(rootViewController: webViewController)
1772
+ self.navigationWebViewController = BrowserNavigationController(rootViewController: webViewController)
1750
1773
  if let navigationController = self.navigationWebViewController {
1751
1774
  self.registerWebView(id: webViewId, webView: webViewController, navigationController: navigationController)
1752
1775
  }
@@ -1848,6 +1871,8 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1848
1871
 
1849
1872
  }
1850
1873
 
1874
+ webViewController.pendingStartupFullscreen = fullscreen
1875
+
1851
1876
  // We don't use the toolbar anymore, always hide it
1852
1877
  self.navigationWebViewController?.setToolbarHidden(true, animated: false)
1853
1878
 
@@ -1945,6 +1970,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
1945
1970
  self.isHidden = hidden
1946
1971
 
1947
1972
  if hidden {
1973
+ webViewController.setBrowserFullscreen(false)
1948
1974
  if let resolvedId {
1949
1975
  self.detachFramedOverlayWebView(id: resolvedId)
1950
1976
  self.detachLayeredWebView(id: resolvedId)
@@ -2038,6 +2064,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
2038
2064
  }
2039
2065
 
2040
2066
  let transparentBackground = call.getBool("transparentBackground", true)
2067
+ webViewController.setBrowserFullscreen(false)
2041
2068
  self.dismissNavigationControllerIfPresented(navigationController) {
2042
2069
  webViewController.isLayeredBehind = true
2043
2070
  webViewController.transparentHostBackground = transparentBackground
@@ -2654,9 +2681,21 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
2654
2681
 
2655
2682
  @objc func appDidBecomeActive(_ notification: NSNotification) {
2656
2683
  self.hidePrivacyScreen()
2684
+ guard let controller = webViewController,
2685
+ controller.pendingStartupFullscreen,
2686
+ let navigation = controller.navigationController,
2687
+ navigation.presentingViewController != nil,
2688
+ navigation.presentedViewController == nil,
2689
+ controller.presentedViewController == nil,
2690
+ controller.viewIfLoaded?.window != nil,
2691
+ controller.capableWebView?.superview === controller.viewIfLoaded else { return }
2692
+ controller.setBrowserFullscreen(true)
2657
2693
  }
2658
2694
 
2659
2695
  @objc func appWillResignActive(_ notification: NSNotification) {
2696
+ for controller in webViewControllers.values {
2697
+ controller.setBrowserFullscreen(false)
2698
+ }
2660
2699
  self.showPrivacyScreen()
2661
2700
  }
2662
2701
 
@@ -2984,3 +3023,50 @@ extension CapgoInAppBrowserPlugin {
2984
3023
 
2985
3024
  }
2986
3025
 
3026
+
3027
+ extension CapgoInAppBrowserPlugin {
3028
+ @objc func setFullscreen(_ call: CAPPluginCall) {
3029
+ guard let value = call.options["enabled"] as? NSNumber,
3030
+ CFGetTypeID(value) == CFBooleanGetTypeID() else {
3031
+ call.reject("enabled must be a boolean")
3032
+ return
3033
+ }
3034
+ let enabled = value.boolValue
3035
+ DispatchQueue.main.async {
3036
+ guard let id = call.getString("id") ?? self.activeWebViewId,
3037
+ let controller = self.webViewControllers[id],
3038
+ controller.capableWebView != nil else {
3039
+ call.reject("WebView is not initialized or does not support fullscreen")
3040
+ return
3041
+ }
3042
+ if enabled {
3043
+ guard controller.supportsBrowserFullscreen,
3044
+ let navigation = self.navigationControllers[id],
3045
+ navigation.presentingViewController != nil,
3046
+ navigation.presentedViewController == nil,
3047
+ controller.presentedViewController == nil,
3048
+ controller.viewIfLoaded?.window != nil,
3049
+ controller.capableWebView?.superview === controller.view,
3050
+ UIApplication.shared.applicationState == .active else {
3051
+ call.reject("Fullscreen requires a visible, frontmost, unframed WebView")
3052
+ return
3053
+ }
3054
+ }
3055
+ controller.setBrowserFullscreen(enabled)
3056
+ call.resolve()
3057
+ }
3058
+ }
3059
+
3060
+ @objc func getFullscreen(_ call: CAPPluginCall) {
3061
+ DispatchQueue.main.async {
3062
+ guard let id = call.getString("id") ?? self.activeWebViewId,
3063
+ let controller = self.webViewControllers[id],
3064
+ controller.capableWebView != nil else {
3065
+ call.reject("WebView is not initialized or does not support fullscreen")
3066
+ return
3067
+ }
3068
+ call.resolve(["enabled": controller.isBrowserFullscreen])
3069
+ }
3070
+ }
3071
+
3072
+ }
@@ -427,6 +427,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
427
427
  open internal(set) var url: URL?
428
428
  open var tintColor: UIColor?
429
429
  open var allowsFileURL = true
430
+ open var downloadPreview = DownloadPreviewSupport.defaultMode
430
431
  open var allowWebViewJsVisibilityControl = false
431
432
  open var allowScreenshotsFromWebPage = false
432
433
  open var captureConsoleLogs = false
@@ -445,6 +446,11 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
445
446
  open var capBrowserPlugin: CapgoInAppBrowserPlugin?
446
447
  open var isInspectable: Bool = false
447
448
  var instanceId: String = ""
449
+ var browserFullscreen = BrowserFullscreenState()
450
+
451
+ override open var prefersStatusBarHidden: Bool { isBrowserFullscreen }
452
+ override open var prefersHomeIndicatorAutoHidden: Bool { isBrowserFullscreen }
453
+
448
454
  var shareDisclaimer: [String: Any]?
449
455
  var shareSubject: String?
450
456
  var didpageInit = false
@@ -769,7 +775,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
769
775
 
770
776
  private func previewDownloadedFile(_ fileURL: URL, mimeType: String?, sourceURL: String?) {
771
777
  DispatchQueue.main.async {
772
- if self.allowsFileURL && self.shouldPreviewDownloadedFile(fileURL, mimeType: mimeType) {
778
+ if DownloadPreviewSupport.usesInAppBrowserPreview(self.downloadPreview) &&
779
+ self.shouldPreviewDownloadedFile(fileURL, mimeType: mimeType) {
773
780
  let accessURL = fileURL.deletingLastPathComponent()
774
781
  self.source = .file(fileURL, access: accessURL)
775
782
  self.load(file: fileURL, access: accessURL)
@@ -1233,6 +1240,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1233
1240
  hostView.insertSubview(backgroundView, at: 0)
1234
1241
  backgroundView.translatesAutoresizingMaskIntoConstraints = false
1235
1242
  backgroundView.backgroundColor = color
1243
+ backgroundView.isHidden = isBrowserFullscreen
1236
1244
 
1237
1245
  var constraints = [
1238
1246
  backgroundView.topAnchor.constraint(equalTo: hostView.topAnchor),
@@ -1473,6 +1481,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1473
1481
  override open func viewDidLayoutSubviews() {
1474
1482
  super.viewDidLayoutSubviews()
1475
1483
  syncWebViewSafeAreaLayout()
1484
+ updateFullscreenExitButtonPosition()
1476
1485
  refreshWebViewViewportIfNeeded()
1477
1486
  }
1478
1487
 
@@ -2346,6 +2355,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2346
2355
  self.allowScreenshotsFromWebPage = parent.allowScreenshotsFromWebPage
2347
2356
  self.preferredContentMode = parent.preferredContentMode
2348
2357
  self.handleDownloads = parent.handleDownloads
2358
+ self.downloadPreview = parent.downloadPreview
2349
2359
  self.websiteTitleInNavigationBar = parent.websiteTitleInNavigationBar
2350
2360
  self.doneBarButtonItemPosition = parent.doneBarButtonItemPosition
2351
2361
  self.showArrowAsClose = parent.showArrowAsClose
@@ -2376,7 +2386,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2376
2386
  }
2377
2387
 
2378
2388
  private func applyNavigationVisibility() {
2379
- navigationController?.setNavigationBarHidden(blankNavigationTab, animated: false)
2389
+ navigationController?.setNavigationBarHidden(isBrowserFullscreen || blankNavigationTab, animated: false)
2380
2390
  // Always hide toolbar since we never want it.
2381
2391
  navigationController?.setToolbarHidden(true, animated: false)
2382
2392
  }
@@ -2409,6 +2419,11 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2409
2419
  }
2410
2420
  }
2411
2421
 
2422
+ // Apply only when presented; hidden startup must not change the host's system bars.
2423
+ if pendingStartupFullscreen && UIApplication.shared.applicationState == .active {
2424
+ setBrowserFullscreen(true)
2425
+ }
2426
+
2412
2427
  // Update status bar style
2413
2428
  updateStatusBarStyle()
2414
2429
 
@@ -2459,7 +2474,12 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
2459
2474
 
2460
2475
  override open func viewWillDisappear(_ animated: Bool) {
2461
2476
  super.viewWillDisappear(animated)
2462
- rollbackState()
2477
+ if isBeingDismissed || isMovingFromParent || navigationController?.isBeingDismissed == true {
2478
+ setBrowserFullscreen(false)
2479
+ }
2480
+ if !isBrowserFullscreen {
2481
+ rollbackState()
2482
+ }
2463
2483
  }
2464
2484
 
2465
2485
  override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
@@ -2594,6 +2614,7 @@ public extension WKWebViewController {
2594
2614
  }
2595
2615
 
2596
2616
  func cleanupWebView() {
2617
+ setBrowserFullscreen(false)
2597
2618
  guard let webView = self.webView else { return }
2598
2619
  webView.stopLoading()
2599
2620
  previewItemURL = nil
@@ -3647,6 +3668,10 @@ extension WKWebViewController: WKNavigationDelegate {
3647
3668
  return
3648
3669
  }
3649
3670
 
3671
+ if navigationAction.targetFrame?.isMainFrame == true {
3672
+ exitFullscreenIfOriginChanges(to: url)
3673
+ }
3674
+
3650
3675
  if handleDownloads, url.scheme?.lowercased() == "blob" {
3651
3676
  handleBlobDownloadFromPage(
3652
3677
  blobUrl: url.absoluteString,
@@ -3722,6 +3747,9 @@ extension WKWebViewController: WKNavigationDelegate {
3722
3747
  }
3723
3748
 
3724
3749
  public func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
3750
+ if navigationResponse.isForMainFrame {
3751
+ exitFullscreenIfOriginChanges(to: navigationResponse.response.url)
3752
+ }
3725
3753
  if shouldInterceptDownload(for: navigationResponse) {
3726
3754
  decisionHandler(.download)
3727
3755
  return
@@ -3740,10 +3768,6 @@ extension WKWebViewController: WKNavigationDelegate {
3740
3768
  stopReloadGesture()
3741
3769
  }
3742
3770
 
3743
- public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
3744
- stopReloadGesture()
3745
- }
3746
-
3747
3771
  // MARK: - Dimension Management
3748
3772
 
3749
3773
  func applyCustomDimensions() {
@@ -3796,6 +3820,7 @@ extension WKWebViewController: WKNavigationDelegate {
3796
3820
 
3797
3821
  /// Update dimensions at runtime
3798
3822
  func updateDimensions(width: CGFloat?, height: CGFloat?, xPos: CGFloat?, yPos: CGFloat?) {
3823
+ setBrowserFullscreen(false)
3799
3824
  // Update stored dimensions
3800
3825
  if let width = width {
3801
3826
  customWidth = width
@@ -3815,6 +3840,10 @@ extension WKWebViewController: WKNavigationDelegate {
3815
3840
  }
3816
3841
 
3817
3842
  func updateSafeTopMargin(_ enabled: Bool) {
3843
+ if isBrowserFullscreen && !browserFullscreen.applyingLayout {
3844
+ browserFullscreen.baseline?.safeTop = enabled
3845
+ return
3846
+ }
3818
3847
  guard enabled != self.enabledSafeTopMargin else { return }
3819
3848
  self.enabledSafeTopMargin = enabled
3820
3849
  guard let webView = self.webView else { return }
@@ -3837,6 +3866,10 @@ extension WKWebViewController: WKNavigationDelegate {
3837
3866
  }
3838
3867
 
3839
3868
  func updateSafeBottomMargin(_ enabled: Bool) {
3869
+ if isBrowserFullscreen && !browserFullscreen.applyingLayout {
3870
+ browserFullscreen.baseline?.safeBottom = enabled
3871
+ return
3872
+ }
3840
3873
  guard enabled != self.enabledSafeBottomMargin else { return }
3841
3874
  self.enabledSafeBottomMargin = enabled
3842
3875
  guard let webView = self.webView else { return }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-inappbrowser",
3
- "version": "8.18.1",
3
+ "version": "8.20.0",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -35,7 +35,7 @@
35
35
  "verify:ios": "bun run build:proxy-bridge && xcodebuild -scheme CapgoCapacitorInappbrowser -destination generic/platform=iOS",
36
36
  "verify:android": "cd android && ./gradlew clean build test && cd ..",
37
37
  "verify:web": "bun run build && bun run test:web",
38
- "test:web": "bun test src/proxy-bridge-support.test.ts src/bundled-asset-support.test.ts",
38
+ "test:web": "bun test src/proxy-bridge-support.test.ts src/bundled-asset-support.test.ts src/fullscreen-web.test.ts",
39
39
  "test:maestro:android": "./scripts/test-maestro-android.sh",
40
40
  "lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
41
41
  "fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format",