@capgo/capacitor-inappbrowser 8.6.31 → 8.6.34

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.
@@ -236,6 +236,49 @@ enum WebViewViewportLayoutSupport {
236
236
  }
237
237
  }
238
238
 
239
+ enum WebViewSafeAreaLayoutSupport {
240
+ static func contentInsetAdjustmentBehavior(enabledSafeBottomMargin: Bool) -> UIScrollView.ContentInsetAdjustmentBehavior {
241
+ enabledSafeBottomMargin ? .automatic : .never
242
+ }
243
+
244
+ static func shouldInsetLayoutMarginsFromSafeArea(enabledSafeBottomMargin: Bool) -> Bool {
245
+ enabledSafeBottomMargin
246
+ }
247
+
248
+ static func rawSystemBottomInset(effectiveBottomInset: CGFloat, additionalBottomInset: CGFloat) -> CGFloat {
249
+ max(0, effectiveBottomInset - additionalBottomInset)
250
+ }
251
+
252
+ static func additionalBottomSafeAreaOffset(enabledSafeBottomMargin: Bool, safeAreaBottomInset: CGFloat) -> CGFloat {
253
+ guard !enabledSafeBottomMargin, safeAreaBottomInset > 0 else {
254
+ return 0
255
+ }
256
+
257
+ return -safeAreaBottomInset
258
+ }
259
+
260
+ static func cssBottomInset(enabledSafeBottomMargin: Bool, safeAreaBottomInset: CGFloat) -> CGFloat {
261
+ enabledSafeBottomMargin ? safeAreaBottomInset : 0
262
+ }
263
+
264
+ static func cssTopInset(enabledSafeTopMargin: Bool, safeAreaTopInset: CGFloat) -> CGFloat {
265
+ enabledSafeTopMargin ? safeAreaTopInset : 0
266
+ }
267
+
268
+ static func safeAreaCssVariablesScript(top: CGFloat, bottom: CGFloat, left: CGFloat, right: CGFloat) -> String {
269
+ let topValue = Int(top.rounded())
270
+ let bottomValue = Int(bottom.rounded())
271
+ let leftValue = Int(left.rounded())
272
+ let rightValue = Int(right.rounded())
273
+
274
+ return "(function(){var root=document.documentElement;" +
275
+ "root.style.setProperty('--safe-area-inset-top','\(topValue)px');" +
276
+ "root.style.setProperty('--safe-area-inset-bottom','\(bottomValue)px');" +
277
+ "root.style.setProperty('--safe-area-inset-left','\(leftValue)px');" +
278
+ "root.style.setProperty('--safe-area-inset-right','\(rightValue)px');})();"
279
+ }
280
+ }
281
+
239
282
  open class WKWebViewController: UIViewController, WKScriptMessageHandler {
240
283
 
241
284
  public init() {
@@ -311,7 +354,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
311
354
  self.initWebview(isInspectable: isInspectable)
312
355
  }
313
356
 
314
- public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool, blankNavigationTab: Bool, enabledSafeBottomMargin: Bool, enabledSafeTopMargin: Bool = true, blockedHosts: [String], authorizedAppLinks: [String], allowWebViewJsVisibilityControl: Bool = false, allowScreenshotsFromWebPage: Bool = false, captureConsoleLogs: Bool = false, proxyRequests: Bool = false, proxySchemeHandler: ProxySchemeHandler? = nil, documentStartUserScripts: [String] = [], openBlankTargetInWebView: Bool = false) {
357
+ public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool, blankNavigationTab: Bool, enabledSafeBottomMargin: Bool, enabledSafeTopMargin: Bool = true, blockedHosts: [String], authorizedAppLinks: [String], allowWebViewJsVisibilityControl: Bool = false, allowScreenshotsFromWebPage: Bool = false, captureConsoleLogs: Bool = false, proxyRequests: Bool = false, proxySchemeHandler: ProxySchemeHandler? = nil, proxyBridge: ProxyBridge? = nil, proxyBridgeAccessToken: String? = nil, legacyProxyRequestURLRegexPattern: String? = nil, documentStartUserScripts: [String] = [], openBlankTargetInWebView: Bool = false) {
315
358
  super.init(nibName: nil, bundle: nil)
316
359
  self.blankNavigationTab = blankNavigationTab
317
360
  self.enabledSafeBottomMargin = enabledSafeBottomMargin
@@ -323,6 +366,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
323
366
  self.captureConsoleLogs = captureConsoleLogs
324
367
  self.proxyRequests = proxyRequests
325
368
  self.proxySchemeHandler = proxySchemeHandler
369
+ self.proxyBridge = proxyBridge
370
+ self.proxyBridgeAccessToken = proxyBridgeAccessToken
371
+ self.legacyProxyRequestURLRegexPattern = legacyProxyRequestURLRegexPattern
326
372
  self.openBlankTargetInWebView = openBlankTargetInWebView
327
373
  self.setHeaders(headers: headers)
328
374
  self.setPreventDeeplink(preventDeeplink: preventDeeplink)
@@ -379,6 +425,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
379
425
  var disableOverscroll: Bool = false
380
426
  var proxyRequests: Bool = false
381
427
  var proxySchemeHandler: ProxySchemeHandler?
428
+ var proxyBridge: ProxyBridge?
429
+ var proxyBridgeAccessToken: String?
430
+ var legacyProxyRequestURLRegexPattern: String?
382
431
  var initialWebConfiguration: WKWebViewConfiguration?
383
432
  var waitsForPopupNavigation = false
384
433
  var hiddenPopupWindow = false
@@ -395,6 +444,14 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
395
444
  private var isWebViewInitialized = false
396
445
  private var isObservingKeyboardViewportChanges = false
397
446
  private var lastViewportRefreshSize: CGSize?
447
+ private struct InjectedSafeAreaInsets: Equatable {
448
+ let top: Int
449
+ let bottom: Int
450
+ let left: Int
451
+ let right: Int
452
+ }
453
+
454
+ private var lastInjectedSafeAreaInsets: InjectedSafeAreaInsets?
398
455
  private var downloadStates: [ObjectIdentifier: WKDownloadState] = [:]
399
456
  private var previewItemURL: URL?
400
457
 
@@ -904,9 +961,15 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
904
961
 
905
962
  override open func viewDidLayoutSubviews() {
906
963
  super.viewDidLayoutSubviews()
964
+ syncWebViewSafeAreaLayout()
907
965
  refreshWebViewViewportIfNeeded()
908
966
  }
909
967
 
968
+ override open func viewSafeAreaInsetsDidChange() {
969
+ super.viewSafeAreaInsetsDidChange()
970
+ syncWebViewSafeAreaLayout()
971
+ }
972
+
910
973
  func updateButtonTintColors() {
911
974
  // Ensure all button items use the navigation bar's tint color
912
975
  if let tintColor = navigationController?.navigationBar.tintColor {
@@ -1064,6 +1127,72 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1064
1127
  webView.evaluateJavaScript("window.dispatchEvent(new Event('resize'));", completionHandler: nil)
1065
1128
  }
1066
1129
 
1130
+ private func configureWebViewScrollViewSafeArea(_ webView: WKWebView) {
1131
+ if #available(iOS 11.0, *) {
1132
+ webView.scrollView.contentInsetAdjustmentBehavior = WebViewSafeAreaLayoutSupport
1133
+ .contentInsetAdjustmentBehavior(enabledSafeBottomMargin: enabledSafeBottomMargin)
1134
+ }
1135
+
1136
+ webView.insetsLayoutMarginsFromSafeArea = WebViewSafeAreaLayoutSupport
1137
+ .shouldInsetLayoutMarginsFromSafeArea(enabledSafeBottomMargin: enabledSafeBottomMargin)
1138
+
1139
+ if !enabledSafeBottomMargin {
1140
+ webView.scrollView.contentInset = .zero
1141
+ webView.scrollView.scrollIndicatorInsets = .zero
1142
+ }
1143
+ }
1144
+
1145
+ private func syncWebViewSafeAreaLayout() {
1146
+ guard let webView = self.webView, webView.superview != nil else {
1147
+ return
1148
+ }
1149
+
1150
+ let rawSafeAreaBottomInset = WebViewSafeAreaLayoutSupport.rawSystemBottomInset(
1151
+ effectiveBottomInset: view.safeAreaInsets.bottom,
1152
+ additionalBottomInset: additionalSafeAreaInsets.bottom
1153
+ )
1154
+
1155
+ let bottomOffset = WebViewSafeAreaLayoutSupport.additionalBottomSafeAreaOffset(
1156
+ enabledSafeBottomMargin: enabledSafeBottomMargin,
1157
+ safeAreaBottomInset: rawSafeAreaBottomInset
1158
+ )
1159
+ if additionalSafeAreaInsets.bottom != bottomOffset {
1160
+ additionalSafeAreaInsets.bottom = bottomOffset
1161
+ }
1162
+
1163
+ configureWebViewScrollViewSafeArea(webView)
1164
+
1165
+ let topInset = WebViewSafeAreaLayoutSupport.cssTopInset(
1166
+ enabledSafeTopMargin: enabledSafeTopMargin,
1167
+ safeAreaTopInset: view.safeAreaInsets.top
1168
+ )
1169
+ let bottomInset = WebViewSafeAreaLayoutSupport.cssBottomInset(
1170
+ enabledSafeBottomMargin: enabledSafeBottomMargin,
1171
+ safeAreaBottomInset: rawSafeAreaBottomInset
1172
+ )
1173
+ let leftInset = view.safeAreaInsets.left
1174
+ let rightInset = view.safeAreaInsets.right
1175
+
1176
+ let roundedInsets = InjectedSafeAreaInsets(
1177
+ top: Int(topInset.rounded()),
1178
+ bottom: Int(bottomInset.rounded()),
1179
+ left: Int(leftInset.rounded()),
1180
+ right: Int(rightInset.rounded())
1181
+ )
1182
+ if lastInjectedSafeAreaInsets == roundedInsets {
1183
+ return
1184
+ }
1185
+ lastInjectedSafeAreaInsets = roundedInsets
1186
+
1187
+ let script = WebViewSafeAreaLayoutSupport.safeAreaCssVariablesScript(
1188
+ top: topInset,
1189
+ bottom: bottomInset,
1190
+ left: leftInset,
1191
+ right: rightInset
1192
+ )
1193
+ webView.evaluateJavaScript(script, completionHandler: nil)
1194
+ }
1195
+
1067
1196
  private func jsonString(from object: Any) -> String? {
1068
1197
  guard JSONSerialization.isValidJSONObject(object),
1069
1198
  let data = try? JSONSerialization.data(withJSONObject: object),
@@ -1175,6 +1304,25 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1175
1304
  }
1176
1305
  print("[InAppBrowser - preShowScriptError]: Error!!!!")
1177
1306
  semaphore.signal()
1307
+ } else if message.name == "capgoProxyBridge" {
1308
+ guard let messageBody = message.body as? [String: Any],
1309
+ let token = messageBody["token"] as? String,
1310
+ let requestId = messageBody["requestId"] as? String,
1311
+ let method = messageBody["method"] as? String,
1312
+ let headersJson = messageBody["headersJson"] as? String else {
1313
+ return
1314
+ }
1315
+
1316
+ let base64Body = messageBody["base64Body"] as? String ?? ""
1317
+ let credentialsMode = messageBody["credentialsMode"] as? String ?? "same-origin"
1318
+ proxyBridge?.storeRequest(
1319
+ token: token,
1320
+ requestId: requestId,
1321
+ method: method,
1322
+ headersJson: headersJson,
1323
+ base64Body: base64Body,
1324
+ credentialsMode: credentialsMode
1325
+ )
1178
1326
  } else if message.name == "close" {
1179
1327
  closeView()
1180
1328
  } else if message.name == "hide" {
@@ -1309,6 +1457,35 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1309
1457
  userContentController.addUserScript(script)
1310
1458
  }
1311
1459
 
1460
+ private func addProxyBridgeUserScripts(to userContentController: WKUserContentController) {
1461
+ guard let accessToken = proxyBridgeAccessToken else {
1462
+ return
1463
+ }
1464
+
1465
+ let bootstrapScript = WKUserScript(
1466
+ source: ProxyBridgeSupport.bootstrapScriptSource(),
1467
+ injectionTime: .atDocumentStart,
1468
+ forMainFrameOnly: false
1469
+ )
1470
+ userContentController.addUserScript(bootstrapScript)
1471
+
1472
+ let proxyRegexSource = legacyProxyRequestURLRegexPattern ?? ""
1473
+ guard let bridgeScriptSource = ProxyBridgeSupport.loadBundledBridgeScript(
1474
+ accessToken: accessToken,
1475
+ proxyRegexSource: proxyRegexSource
1476
+ ) else {
1477
+ print("[InAppBrowser][Proxy] WARNING: Failed to load proxy-bridge.js for iOS injection")
1478
+ return
1479
+ }
1480
+
1481
+ let bridgeScript = WKUserScript(
1482
+ source: bridgeScriptSource,
1483
+ injectionTime: .atDocumentStart,
1484
+ forMainFrameOnly: false
1485
+ )
1486
+ userContentController.addUserScript(bridgeScript)
1487
+ }
1488
+
1312
1489
  func injectJavaScriptInterface() {
1313
1490
  let script = mobileAppScriptSource()
1314
1491
  DispatchQueue.main.async {
@@ -1347,6 +1524,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1347
1524
  userContentController.removeScriptMessageHandler(forName: "takeScreenshot")
1348
1525
  userContentController.removeScriptMessageHandler(forName: "consoleMessageHandler")
1349
1526
  userContentController.removeScriptMessageHandler(forName: "magicPrint")
1527
+ userContentController.removeScriptMessageHandler(forName: "capgoProxyBridge")
1350
1528
 
1351
1529
  if proxyRequests || proxySchemeHandler != nil, let handler = proxySchemeHandler {
1352
1530
  WKWebView.enableCustomSchemeHandling(for: ["https", "http"])
@@ -1358,6 +1536,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1358
1536
  }
1359
1537
  }
1360
1538
 
1539
+ if ProxyBridgeSupport.shouldInjectBridge(hasProxySchemeHandler: proxySchemeHandler != nil) {
1540
+ addProxyBridgeUserScripts(to: userContentController)
1541
+ }
1542
+
1361
1543
  let weakHandler = WeakScriptMessageHandler(self)
1362
1544
  userContentController.add(weakHandler, name: "messageHandler")
1363
1545
  userContentController.add(weakHandler, name: "preShowScriptError")
@@ -1393,6 +1575,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1393
1575
  )
1394
1576
  )
1395
1577
  }
1578
+ if ProxyBridgeSupport.shouldInjectBridge(hasProxySchemeHandler: proxySchemeHandler != nil) {
1579
+ userContentController.add(weakHandler, name: "capgoProxyBridge")
1580
+ }
1396
1581
  userContentController.add(weakHandler, name: "magicPrint")
1397
1582
 
1398
1583
  // Inject JavaScript to override window.print
@@ -1504,6 +1689,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1504
1689
 
1505
1690
  // Disable bounce effect by setting scrollView.bounces to false when disableOverscroll is true
1506
1691
  webView.scrollView.bounces = !self.disableOverscroll
1692
+ configureWebViewScrollViewSafeArea(webView)
1507
1693
 
1508
1694
  webView.addObserver(self, forKeyPath: estimatedProgressKeyPath, options: .new, context: nil)
1509
1695
  if websiteTitleInNavigationBar {
@@ -1580,7 +1766,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1580
1766
  self.disableOverscroll = parent.disableOverscroll
1581
1767
  self.proxyRequests = parent.proxyRequests
1582
1768
  self.proxySchemeHandler = proxySchemeHandler
1583
- self.initialWebConfiguration = configuration
1769
+ self.proxyBridge = parent.proxyBridge
1770
+ self.proxyBridgeAccessToken = parent.proxyBridgeAccessToken
1771
+ self.legacyProxyRequestURLRegexPattern = parent.legacyProxyRequestURLRegexPattern
1584
1772
  self.waitsForPopupNavigation = true
1585
1773
  self.hiddenPopupWindow = parent.hiddenPopupWindow
1586
1774
  self.opensHidden = parent.hiddenPopupWindow
@@ -1860,6 +2048,7 @@ public extension WKWebViewController {
1860
2048
  webView.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptSuccess")
1861
2049
  webView.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptError")
1862
2050
  webView.configuration.userContentController.removeScriptMessageHandler(forName: "magicPrint")
2051
+ webView.configuration.userContentController.removeScriptMessageHandler(forName: "capgoProxyBridge")
1863
2052
 
1864
2053
  webView.removeFromSuperview()
1865
2054
  // Also clean progress bar view if present
@@ -2075,10 +2264,10 @@ fileprivate extension WKWebViewController {
2075
2264
  }
2076
2265
 
2077
2266
  func setUpState() {
2078
- navigationController?.setNavigationBarHidden(false, animated: true)
2267
+ navigationController?.setNavigationBarHidden(blankNavigationTab, animated: false)
2079
2268
 
2080
2269
  // Always hide toolbar since we never want it
2081
- navigationController?.setToolbarHidden(true, animated: true)
2270
+ navigationController?.setToolbarHidden(true, animated: false)
2082
2271
 
2083
2272
  // Set tint colors but don't override specific colors
2084
2273
  if tintColor == nil {
@@ -2730,6 +2919,8 @@ extension WKWebViewController: WKNavigationDelegate {
2730
2919
  delegate?.webViewController?(self, didFinish: url)
2731
2920
  }
2732
2921
  self.injectJavaScriptInterface()
2922
+ lastInjectedSafeAreaInsets = nil
2923
+ syncWebViewSafeAreaLayout()
2733
2924
  emit("browserPageLoaded")
2734
2925
  }
2735
2926
 
@@ -2944,6 +3135,7 @@ extension WKWebViewController: WKNavigationDelegate {
2944
3135
  webView.topAnchor.constraint(equalTo: topAnchor)
2945
3136
  ])
2946
3137
  self.view.layoutIfNeeded()
3138
+ syncWebViewSafeAreaLayout()
2947
3139
  refreshWebViewViewportIfNeeded(force: true)
2948
3140
  }
2949
3141
 
@@ -2965,6 +3157,7 @@ extension WKWebViewController: WKNavigationDelegate {
2965
3157
  webView.bottomAnchor.constraint(equalTo: bottomAnchor)
2966
3158
  ])
2967
3159
  self.view.layoutIfNeeded()
3160
+ syncWebViewSafeAreaLayout()
2968
3161
  refreshWebViewViewportIfNeeded(force: true)
2969
3162
  }
2970
3163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-inappbrowser",
3
- "version": "8.6.31",
3
+ "version": "8.6.34",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -32,7 +32,7 @@
32
32
  ],
33
33
  "scripts": {
34
34
  "verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
35
- "verify:ios": "xcodebuild -scheme CapgoCapacitorInappbrowser -destination generic/platform=iOS",
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
38
  "test:web": "bun test src/proxy-bridge-support.test.ts",
@@ -43,7 +43,7 @@
43
43
  "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
44
44
  "swiftlint": "node-swiftlint",
45
45
  "docgen": "docgen --api InAppBrowserPlugin --output-readme README.md --output-json dist/docs.json",
46
- "build:proxy-bridge": "esbuild src/proxy-bridge.ts --bundle --outfile=android/src/main/assets/proxy-bridge.js --format=iife --target=es2015",
46
+ "build:proxy-bridge": "esbuild src/proxy-bridge.ts --bundle --outfile=android/src/main/assets/proxy-bridge.js --format=iife --target=es2015 && mkdir -p ios/Sources/InAppBrowserPlugin/Resources && cp android/src/main/assets/proxy-bridge.js ios/Sources/InAppBrowserPlugin/Resources/proxy-bridge.js",
47
47
  "build": "bun run clean && bun run docgen && tsc && rollup -c rollup.config.mjs && bun run build:proxy-bridge",
48
48
  "clean": "rimraf ./dist",
49
49
  "watch": "tsc --watch",