@capgo/inappbrowser 7.29.0 → 7.29.2

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 CHANGED
@@ -65,6 +65,8 @@ InAppBrowser.updateDimensions({
65
65
  });
66
66
  ```
67
67
 
68
+ **Touch Passthrough**: When custom dimensions are set (not fullscreen), touches outside the webview bounds will pass through to the underlying Capacitor webview, allowing the user to interact with your app in the exposed areas. This enables picture-in-picture style experiences where the InAppBrowser floats above your content.
69
+
68
70
  ### Open WebView with Safe Margin
69
71
 
70
72
  To create a webView with a 20px bottom margin (safe margin area outside the browser):
@@ -50,7 +50,7 @@ import org.json.JSONObject;
50
50
  )
51
51
  public class InAppBrowserPlugin extends Plugin implements WebViewDialog.PermissionHandler {
52
52
 
53
- private final String pluginVersion = "7.29.0";
53
+ private final String pluginVersion = "7.29.2";
54
54
 
55
55
  public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
56
56
  private CustomTabsClient customTabsClient;
@@ -653,6 +653,12 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
653
653
  Integer x = call.getInt("x");
654
654
  Integer y = call.getInt("y");
655
655
 
656
+ // Validate dimension parameters
657
+ if (width != null && height == null) {
658
+ call.reject("Height must be specified when width is provided");
659
+ return;
660
+ }
661
+
656
662
  if (width != null) {
657
663
  options.setWidth(width);
658
664
  }
@@ -30,6 +30,7 @@ import android.text.TextUtils;
30
30
  import android.util.Base64;
31
31
  import android.util.Log;
32
32
  import android.util.TypedValue;
33
+ import android.view.KeyEvent;
33
34
  import android.view.View;
34
35
  import android.view.ViewGroup;
35
36
  import android.view.Window;
@@ -266,6 +267,19 @@ public class WebViewDialog extends Dialog {
266
267
  );
267
268
  setContentView(R.layout.activity_browser);
268
269
 
270
+ // If custom dimensions are set, configure for touch passthrough
271
+ if (_options != null && (_options.getWidth() != null || _options.getHeight() != null)) {
272
+ Window window = getWindow();
273
+ if (window != null) {
274
+ // Make the dialog background transparent
275
+ window.setBackgroundDrawableResource(android.R.color.transparent);
276
+ // Don't dim the background
277
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
278
+ // Allow touches outside to pass through
279
+ window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
280
+ }
281
+ }
282
+
269
283
  // Set fitsSystemWindows only for Android 10 (API 29)
270
284
  if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.Q) {
271
285
  View coordinator = findViewById(R.id.coordinator_layout);
@@ -2662,6 +2676,28 @@ public class WebViewDialog extends Dialog {
2662
2676
  }
2663
2677
  }
2664
2678
 
2679
+ @Override
2680
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
2681
+ // Forward volume key events to the MainActivity
2682
+ switch (keyCode) {
2683
+ case KeyEvent.KEYCODE_VOLUME_UP:
2684
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
2685
+ return activity.onKeyDown(keyCode, event);
2686
+ }
2687
+ return super.onKeyDown(keyCode, event);
2688
+ }
2689
+
2690
+ @Override
2691
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
2692
+ // Forward volume key events to the MainActivity
2693
+ switch (keyCode) {
2694
+ case KeyEvent.KEYCODE_VOLUME_UP:
2695
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
2696
+ return activity.onKeyUp(keyCode, event);
2697
+ }
2698
+ return super.onKeyUp(keyCode, event);
2699
+ }
2700
+
2665
2701
  public static String getReasonPhrase(int statusCode) {
2666
2702
  return switch (statusCode) {
2667
2703
  case (200) -> "OK";
@@ -2672,7 +2708,7 @@ public class WebViewDialog extends Dialog {
2672
2708
  case (205) -> "Reset Content";
2673
2709
  case (206) -> "Partial Content";
2674
2710
  case (207) -> "Partial Update OK";
2675
- case (300) -> "Mutliple Choices";
2711
+ case (300) -> "Multiple Choices";
2676
2712
  case (301) -> "Moved Permanently";
2677
2713
  case (302) -> "Moved Temporarily";
2678
2714
  case (303) -> "See Other";
@@ -2975,6 +3011,12 @@ public class WebViewDialog extends Dialog {
2975
3011
  params.height = (int) getPixels(height);
2976
3012
  params.x = (x != null) ? (int) getPixels(x) : 0;
2977
3013
  params.y = (y != null) ? (int) getPixels(y) : 0;
3014
+ } else if (height != null && width == null) {
3015
+ // If only height is specified, use custom height with fullscreen width
3016
+ params.width = WindowManager.LayoutParams.MATCH_PARENT;
3017
+ params.height = (int) getPixels(height);
3018
+ params.x = 0;
3019
+ params.y = (y != null) ? (int) getPixels(y) : 0;
2978
3020
  } else {
2979
3021
  // Default to fullscreen
2980
3022
  params.width = WindowManager.LayoutParams.MATCH_PARENT;
@@ -24,7 +24,7 @@ extension UIColor {
24
24
  */
25
25
  @objc(InAppBrowserPlugin)
26
26
  public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
27
- private let pluginVersion: String = "7.29.0"
27
+ private let pluginVersion: String = "7.29.2"
28
28
  public let identifier = "InAppBrowserPlugin"
29
29
  public let jsName = "InAppBrowser"
30
30
  public let pluginMethods: [CAPPluginMethod] = [
@@ -374,6 +374,12 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
374
374
  let x = call.getFloat("x")
375
375
  let y = call.getFloat("y")
376
376
 
377
+ // Validate dimension parameters
378
+ if width != nil && height == nil {
379
+ call.reject("Height must be specified when width is provided")
380
+ return
381
+ }
382
+
377
383
  DispatchQueue.main.async {
378
384
  guard let url = URL(string: urlString) else {
379
385
  call.reject("Invalid URL format")
@@ -603,7 +609,41 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
603
609
 
604
610
  }
605
611
 
606
- self.navigationWebViewController?.modalPresentationStyle = .overCurrentContext
612
+ // Configure modal presentation for touch passthrough if custom dimensions are set
613
+ if width != nil || height != nil {
614
+ self.navigationWebViewController?.modalPresentationStyle = .overFullScreen
615
+
616
+ // Create a pass-through container
617
+ let containerView = PassThroughView()
618
+ containerView.backgroundColor = .clear
619
+
620
+ // Calculate dimensions - use screen width if only height is provided
621
+ let finalWidth = width != nil ? CGFloat(width!) : UIScreen.main.bounds.width
622
+ let finalHeight = height != nil ? CGFloat(height!) : UIScreen.main.bounds.height
623
+
624
+ containerView.targetFrame = CGRect(
625
+ x: CGFloat(x ?? 0),
626
+ y: CGFloat(y ?? 0),
627
+ width: finalWidth,
628
+ height: finalHeight
629
+ )
630
+
631
+ // Replace the navigation controller's view with our pass-through container
632
+ if let navController = self.navigationWebViewController {
633
+ let originalView = navController.view!
634
+ navController.view = containerView
635
+ containerView.addSubview(originalView)
636
+ originalView.frame = CGRect(
637
+ x: CGFloat(x ?? 0),
638
+ y: CGFloat(y ?? 0),
639
+ width: finalWidth,
640
+ height: finalHeight
641
+ )
642
+ }
643
+ } else {
644
+ self.navigationWebViewController?.modalPresentationStyle = .overCurrentContext
645
+ }
646
+
607
647
  self.navigationWebViewController?.modalTransitionStyle = .crossDissolve
608
648
  if toolbarType == "blank" {
609
649
  self.navigationWebViewController?.navigationBar.isHidden = true
@@ -153,6 +153,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
153
153
 
154
154
  internal var preShowSemaphore: DispatchSemaphore?
155
155
  internal var preShowError: String?
156
+ private var isWebViewInitialized = false
156
157
 
157
158
  func setHeaders(headers: [String: String]) {
158
159
  self.headers = headers
@@ -394,6 +395,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
394
395
  override open func viewDidDisappear(_ animated: Bool) {
395
396
  super.viewDidDisappear(animated)
396
397
 
398
+ if self.isBeingDismissed || self.isMovingFromParent {
399
+ self.cleanupWebView()
400
+ }
401
+
397
402
  if let capacitorStatusBar = capacitorStatusBar {
398
403
  self.capBrowserPlugin?.bridge?.webView?.superview?.addSubview(capacitorStatusBar)
399
404
  self.capBrowserPlugin?.bridge?.webView?.frame.origin.y = capacitorStatusBar.frame.height
@@ -582,6 +587,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
582
587
  }
583
588
 
584
589
  open func initWebview(isInspectable: Bool = true) {
590
+ if self.isWebViewInitialized {
591
+ return
592
+ }
593
+ self.isWebViewInitialized = true
585
594
  self.view.backgroundColor = UIColor.white
586
595
 
587
596
  self.extendedLayoutIncludesOpaqueBars = true
@@ -589,11 +598,13 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
589
598
 
590
599
  let webConfiguration = WKWebViewConfiguration()
591
600
  let userContentController = WKUserContentController()
592
- userContentController.add(self, name: "messageHandler")
593
- userContentController.add(self, name: "preShowScriptError")
594
- userContentController.add(self, name: "preShowScriptSuccess")
595
- userContentController.add(self, name: "close")
596
- userContentController.add(self, name: "magicPrint")
601
+
602
+ let weakHandler = WeakScriptMessageHandler(self)
603
+ userContentController.add(weakHandler, name: "messageHandler")
604
+ userContentController.add(weakHandler, name: "preShowScriptError")
605
+ userContentController.add(weakHandler, name: "preShowScriptSuccess")
606
+ userContentController.add(weakHandler, name: "close")
607
+ userContentController.add(weakHandler, name: "magicPrint")
597
608
 
598
609
  // Inject JavaScript to override window.print
599
610
  let script = WKUserScript(
@@ -1914,7 +1925,7 @@ extension WKWebViewController: WKNavigationDelegate {
1914
1925
  open func applyCustomDimensions() {
1915
1926
  guard let navigationController = navigationController else { return }
1916
1927
 
1917
- // Only apply custom dimensions if both width and height are specified
1928
+ // Apply custom dimensions if both width and height are specified
1918
1929
  if let width = customWidth, let height = customHeight {
1919
1930
  let x = customX ?? 0
1920
1931
  let y = customY ?? 0
@@ -1922,6 +1933,15 @@ extension WKWebViewController: WKNavigationDelegate {
1922
1933
  // Set the frame for the navigation controller's view
1923
1934
  navigationController.view.frame = CGRect(x: x, y: y, width: width, height: height)
1924
1935
  }
1936
+ // If only height is specified, use fullscreen width
1937
+ else if let height = customHeight, customWidth == nil {
1938
+ let x = customX ?? 0
1939
+ let y = customY ?? 0
1940
+ let screenWidth = UIScreen.main.bounds.width
1941
+
1942
+ // Set the frame with fullscreen width and custom height
1943
+ navigationController.view.frame = CGRect(x: x, y: y, width: screenWidth, height: height)
1944
+ }
1925
1945
  // Otherwise, use default fullscreen behavior (no action needed)
1926
1946
  }
1927
1947
 
@@ -1951,6 +1971,36 @@ class BlockBarButtonItem: UIBarButtonItem {
1951
1971
  var block: ((WKWebViewController) -> Void)?
1952
1972
  }
1953
1973
 
1974
+ /// Custom view that passes touches outside a target frame to the underlying view
1975
+ class PassThroughView: UIView {
1976
+ var targetFrame: CGRect?
1977
+
1978
+ override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
1979
+ // If we have a target frame and the touch is outside it, pass through
1980
+ if let frame = targetFrame {
1981
+ if !frame.contains(point) {
1982
+ return nil // Pass through to underlying views
1983
+ }
1984
+ }
1985
+
1986
+ // Otherwise, handle normally
1987
+ return super.hitTest(point, with: event)
1988
+ }
1989
+ }
1990
+
1954
1991
  extension WKNavigationActionPolicy {
1955
1992
  static let preventDeeplinkActionPolicy = WKNavigationActionPolicy(rawValue: WKNavigationActionPolicy.allow.rawValue + 2)!
1956
1993
  }
1994
+
1995
+ class WeakScriptMessageHandler: NSObject, WKScriptMessageHandler {
1996
+ weak var delegate: WKScriptMessageHandler?
1997
+
1998
+ init(_ delegate: WKScriptMessageHandler) {
1999
+ self.delegate = delegate
2000
+ super.init()
2001
+ }
2002
+
2003
+ func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
2004
+ self.delegate?.userContentController(userContentController, didReceive: message)
2005
+ }
2006
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/inappbrowser",
3
- "version": "7.29.0",
3
+ "version": "7.29.2",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",