@capgo/capacitor-inappbrowser 8.6.15 → 8.6.17

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.
@@ -63,7 +63,7 @@ import org.json.JSONObject;
63
63
  )
64
64
  public class InAppBrowserPlugin extends Plugin implements WebViewDialog.PermissionHandler {
65
65
 
66
- private final String pluginVersion = "8.6.15";
66
+ private final String pluginVersion = "8.6.17";
67
67
 
68
68
  public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
69
69
  private CustomTabsClient customTabsClient;
@@ -77,7 +77,7 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
77
77
  case aware = "AWARE"
78
78
  case fakeVisible = "FAKE_VISIBLE"
79
79
  }
80
- private let pluginVersion: String = "8.6.15"
80
+ private let pluginVersion: String = "8.6.17"
81
81
  public let identifier = "InAppBrowserPlugin"
82
82
  public let jsName = "InAppBrowser"
83
83
  public let pluginMethods: [CAPPluginMethod] = [
@@ -342,12 +342,18 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
342
342
  return
343
343
  }
344
344
 
345
+ dismissActiveKeyboard()
345
346
  let presenter = self.bridge?.viewController?.presentedViewController ?? self.bridge?.viewController
346
347
  presenter?.present(navigationController, animated: isAnimated, completion: {
347
348
  self.currentPluginCall?.resolve()
348
349
  })
349
350
  }
350
351
 
352
+ private func dismissActiveKeyboard() {
353
+ self.bridge?.webView?.endEditing(true)
354
+ UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
355
+ }
356
+
351
357
  private func activeWindow() -> UIWindow? {
352
358
  return UIApplication.shared.connectedScenes
353
359
  .compactMap { $0 as? UIWindowScene }
@@ -403,6 +403,7 @@ enum ProxySchemeRequestSupport {
403
403
  }
404
404
 
405
405
  final class PendingProxyTask {
406
+ let requestId: String
406
407
  let schemeTask: WKURLSchemeTask
407
408
  var requestContext: NativeRequestContext
408
409
  var responseData: NativeResponseData?
@@ -411,12 +412,32 @@ final class PendingProxyTask {
411
412
  var redirectRequest: URLRequest?
412
413
  var timeoutToken: UUID?
413
414
  var canceled = false
414
-
415
- init(schemeTask: WKURLSchemeTask, requestContext: NativeRequestContext, phase: String) {
415
+ /// Set true when WebKit calls `webView(_:stop:)` for this task. Once stopped,
416
+ /// the `WKURLSchemeTask` must never receive `didReceive`/`didFinish`/`didFailWithError`
417
+ /// again or WebKit raises an uncatchable NSException.
418
+ var isStopped = false
419
+ /// Set true the first time a terminal scheme-task call sequence is committed.
420
+ /// Guarantees at-most-once completion even when multiple async sources
421
+ /// (URLSession delegate queue, cookie-sync main hop, global timeout, cancel-all)
422
+ /// race to finish the same request.
423
+ private var isComplete = false
424
+
425
+ init(requestId: String, schemeTask: WKURLSchemeTask, requestContext: NativeRequestContext, phase: String) {
426
+ self.requestId = requestId
416
427
  self.schemeTask = schemeTask
417
428
  self.requestContext = requestContext
418
429
  self.phase = phase
419
430
  }
431
+
432
+ /// Claims the right to issue the single allowed terminal call sequence on the
433
+ /// scheme task. Returns true exactly once, and only while the task is live
434
+ /// (not stopped). Callers MUST hold the handler's `taskLock` so the claim is
435
+ /// atomic with respect to `webView(_:stop:)` marking the task stopped.
436
+ func beginCompletionIfLive() -> Bool {
437
+ if isComplete || isStopped { return false }
438
+ isComplete = true
439
+ return true
440
+ }
420
441
  }
421
442
 
422
443
  // swiftlint:disable type_body_length
@@ -491,7 +512,7 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
491
512
  base64Body: extractBody(from: urlSchemeTask.request),
492
513
  isMainFrame: ProxySchemeRequestSupport.isMainFrameRequest(urlSchemeTask.request)
493
514
  )
494
- let pendingTask = PendingProxyTask(schemeTask: urlSchemeTask, requestContext: requestContext, phase: "outbound")
515
+ let pendingTask = PendingProxyTask(requestId: requestId, schemeTask: urlSchemeTask, requestContext: requestContext, phase: "outbound")
495
516
 
496
517
  taskLock.lock()
497
518
  pendingTasks[requestId] = pendingTask
@@ -503,6 +524,7 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
503
524
  public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
504
525
  taskLock.lock()
505
526
  if let entry = pendingTasks.first(where: { $0.value.schemeTask === urlSchemeTask }) {
527
+ entry.value.isStopped = true
506
528
  pendingTasks.removeValue(forKey: entry.key)
507
529
  let cleanupToken = UUID()
508
530
  stoppedRequests[entry.key] = cleanupToken
@@ -573,7 +595,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
573
595
 
574
596
  if pendingTask.canceled {
575
597
  finishWithCanceledResponse(task: pendingTask)
576
- removePendingTask(requestId: requestId)
577
598
  return
578
599
  }
579
600
 
@@ -583,7 +604,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
583
604
  ) {
584
605
  case .finishCachedResponse:
585
606
  guard let responseData = pendingTask.responseData else { return }
586
- removePendingTask(requestId: requestId)
587
607
  syncResponseCookies(from: responseData, fallbackURL: pendingTask.requestContext.url) {
588
608
  self.finish(task: pendingTask, with: responseData)
589
609
  }
@@ -600,14 +620,14 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
600
620
  do {
601
621
  request = try makeURLRequest(from: pendingTask.requestContext)
602
622
  } catch {
603
- pendingTask.schemeTask.didFailWithError(
604
- NSError(
623
+ failSchemeTask(
624
+ pendingTask,
625
+ with: NSError(
605
626
  domain: "ProxySchemeHandler",
606
627
  code: -3,
607
628
  userInfo: [NSLocalizedDescriptionKey: error.localizedDescription]
608
629
  )
609
630
  )
610
- removePendingTask(requestId: requestId)
611
631
  return
612
632
  }
613
633
  let task = session.dataTask(with: request) { [weak self] data, response, error in
@@ -615,13 +635,18 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
615
635
  guard let pendingTask = self.pendingTask(for: requestId) else { return }
616
636
 
617
637
  if let error {
618
- if (error as NSError).code == NSURLErrorCancelled, pendingTask.redirectRequest != nil {
638
+ if (error as NSError).code == NSURLErrorCancelled {
639
+ // The data task is only canceled by webView(_:stop:) or
640
+ // cancelAllPendingTasks(), and both own the task's lifecycle: stop has
641
+ // already removed it (and marked it stopped) before canceling, while
642
+ // cancelAll routes a terminal failSchemeTask through completeSchemeTask,
643
+ // which removes it on the main queue. Removing it here on the URLSession
644
+ // background queue would unhook it from pendingTasks before a racing
645
+ // stop could mark it stopped, reopening the post-stop completion crash.
646
+ // So just stop processing and let the owning path complete it.
619
647
  return
620
648
  }
621
- if (error as NSError).code != NSURLErrorCancelled {
622
- pendingTask.schemeTask.didFailWithError(error)
623
- }
624
- self.removePendingTask(requestId: requestId)
649
+ self.failSchemeTask(pendingTask, with: error)
625
650
  return
626
651
  }
627
652
 
@@ -680,13 +705,11 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
680
705
  switch inboundRule.action {
681
706
  case .cancel:
682
707
  finishWithCanceledResponse(task: pendingTask)
683
- removePendingTask(requestId: requestId)
684
708
  case .continue:
685
709
  if pendingTask.redirectRequest != nil {
686
710
  followPendingRedirect(requestId: requestId)
687
711
  } else {
688
712
  finish(task: pendingTask, with: responseData)
689
- removePendingTask(requestId: requestId)
690
713
  }
691
714
  case .delegateToJs:
692
715
  emitProxyEvent(requestId: requestId, pendingTask: pendingTask)
@@ -697,7 +720,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
697
720
  followPendingRedirect(requestId: requestId)
698
721
  } else {
699
722
  finish(task: pendingTask, with: responseData)
700
- removePendingTask(requestId: requestId)
701
723
  }
702
724
  }
703
725
  }
@@ -759,7 +781,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
759
781
  self.fallbackToNativePipeline(requestId: requestId)
760
782
  return
761
783
  case .finishCachedResponse:
762
- self.pendingTasks.removeValue(forKey: requestId)
763
784
  self.taskLock.unlock()
764
785
  guard let responseData else { return }
765
786
  self.syncResponseCookies(from: responseData, fallbackURL: pendingTask.requestContext.url) {
@@ -767,12 +788,12 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
767
788
  }
768
789
  return
769
790
  case .failRequest:
770
- self.pendingTasks.removeValue(forKey: requestId)
771
791
  self.taskLock.unlock()
772
792
  }
773
793
 
774
- pendingTask.schemeTask.didFailWithError(
775
- NSError(
794
+ self.failSchemeTask(
795
+ pendingTask,
796
+ with: NSError(
776
797
  domain: "ProxySchemeHandler",
777
798
  code: NSURLErrorTimedOut,
778
799
  userInfo: [NSLocalizedDescriptionKey: "Proxy handler did not respond within \(Int(self.proxyTimeoutSeconds)) seconds"]
@@ -825,14 +846,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
825
846
  return task
826
847
  }
827
848
 
828
- private func removePendingTask(requestId: String) {
829
- taskLock.lock()
830
- pendingTasks.removeValue(forKey: requestId)
831
- stoppedRequests.removeValue(forKey: requestId)
832
- timedOutRequests.removeValue(forKey: requestId)
833
- taskLock.unlock()
834
- }
835
-
836
849
  private func routeCurrentRequest(requestId: String) {
837
850
  guard let pendingTask = pendingTask(for: requestId) else { return }
838
851
  pendingTask.phase = "outbound"
@@ -842,7 +855,6 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
842
855
  switch outboundRule.action {
843
856
  case .cancel:
844
857
  finishWithCanceledResponse(task: pendingTask)
845
- removePendingTask(requestId: requestId)
846
858
  case .continue:
847
859
  executeNativePipeline(requestId: requestId)
848
860
  case .delegateToJs:
@@ -1022,27 +1034,73 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
1022
1034
  )
1023
1035
  }
1024
1036
 
1037
+ /// Runs a terminal `WKURLSchemeTask` call sequence at most once, and never after
1038
+ /// the task has been stopped.
1039
+ ///
1040
+ /// `WKURLSchemeTask` raises an uncatchable NSException if `didReceive`/`didFinish`/
1041
+ /// `didFailWithError` is called after `webView(_:stop:)`, after the task already
1042
+ /// completed, or out of order. Completion can be triggered from several racing
1043
+ /// sources — the URLSession delegate queue, the cookie-sync main-thread hop, the
1044
+ /// global timeout closure, `webView(_:stop:)`, and `cancelAllPendingTasks()`. This
1045
+ /// helper funnels every terminal call onto the main thread (the same queue WebKit
1046
+ /// uses for `start`/`stop`) and gates it behind `beginCompletionIfLive()`, so the
1047
+ /// liveness check and the actual call cannot be separated by a `stop`.
1048
+ ///
1049
+ /// This helper is also the single owner of task removal. Callers MUST NOT remove
1050
+ /// the task from `pendingTasks` eagerly on a background thread before calling a
1051
+ /// terminal method: doing so creates a window where `webView(_:stop:)` (which only
1052
+ /// finds tasks via `pendingTasks`) can no longer mark the task stopped, so a queued
1053
+ /// completion would then call `didReceive`/`didFinish`/`didFailWithError` on an
1054
+ /// already-stopped task and crash. Keeping the task tracked until this main-queue
1055
+ /// block runs lets a racing `stop` win the liveness claim.
1056
+ private func completeSchemeTask(_ task: PendingProxyTask, _ body: @escaping (WKURLSchemeTask) -> Void) {
1057
+ let runBody: () -> Void = { [weak self] in
1058
+ guard let self else { return }
1059
+ self.taskLock.lock()
1060
+ let isLive = task.beginCompletionIfLive()
1061
+ self.pendingTasks.removeValue(forKey: task.requestId)
1062
+ self.stoppedRequests.removeValue(forKey: task.requestId)
1063
+ self.timedOutRequests.removeValue(forKey: task.requestId)
1064
+ self.taskLock.unlock()
1065
+ guard isLive else { return }
1066
+ body(task.schemeTask)
1067
+ }
1068
+ if Thread.isMainThread {
1069
+ runBody()
1070
+ } else {
1071
+ DispatchQueue.main.async(execute: runBody)
1072
+ }
1073
+ }
1074
+
1075
+ private func failSchemeTask(_ task: PendingProxyTask, with error: Error) {
1076
+ completeSchemeTask(task) { schemeTask in
1077
+ schemeTask.didFailWithError(error)
1078
+ }
1079
+ }
1080
+
1025
1081
  private func finish(task: PendingProxyTask, with responseData: NativeResponseData) {
1026
- guard let url = URL(string: task.requestContext.url),
1027
- let httpResponse = HTTPURLResponse(
1028
- url: url,
1029
- statusCode: responseData.statusCode,
1030
- httpVersion: "HTTP/1.1",
1031
- headerFields: responseData.headers
1032
- )
1033
- else {
1034
- task.schemeTask.didFailWithError(
1035
- NSError(
1036
- domain: "ProxySchemeHandler",
1037
- code: -2,
1038
- userInfo: [NSLocalizedDescriptionKey: "Failed to create response"]
1082
+ completeSchemeTask(task) { schemeTask in
1083
+ guard let url = URL(string: task.requestContext.url),
1084
+ let httpResponse = HTTPURLResponse(
1085
+ url: url,
1086
+ statusCode: responseData.statusCode,
1087
+ httpVersion: "HTTP/1.1",
1088
+ headerFields: responseData.headers
1089
+ )
1090
+ else {
1091
+ schemeTask.didFailWithError(
1092
+ NSError(
1093
+ domain: "ProxySchemeHandler",
1094
+ code: -2,
1095
+ userInfo: [NSLocalizedDescriptionKey: "Failed to create response"]
1096
+ )
1039
1097
  )
1040
- )
1041
- return
1098
+ return
1099
+ }
1100
+ schemeTask.didReceive(httpResponse)
1101
+ schemeTask.didReceive(responseData.body)
1102
+ schemeTask.didFinish()
1042
1103
  }
1043
- task.schemeTask.didReceive(httpResponse)
1044
- task.schemeTask.didReceive(responseData.body)
1045
- task.schemeTask.didFinish()
1046
1104
  }
1047
1105
 
1048
1106
  private func finishWithCanceledResponse(task: PendingProxyTask) {
@@ -1138,15 +1196,19 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
1138
1196
  func cancelAllPendingTasks() {
1139
1197
  taskLock.lock()
1140
1198
  let pending = pendingTasks
1141
- pendingTasks.removeAll()
1199
+ // Do not clear pendingTasks here. completeSchemeTask removes each task on the
1200
+ // main queue once its failure is claimed, so a concurrent webView(_:stop:) can
1201
+ // still find and mark the task stopped before the queued failure runs. Clearing
1202
+ // eagerly would reopen the post-stop completion crash this fix closes.
1142
1203
  stoppedRequests.removeAll()
1143
1204
  taskLock.unlock()
1144
1205
  session.invalidateAndCancel()
1145
1206
 
1146
1207
  for (_, task) in pending {
1147
1208
  task.urlSessionTask?.cancel()
1148
- task.schemeTask.didFailWithError(
1149
- NSError(
1209
+ failSchemeTask(
1210
+ task,
1211
+ with: NSError(
1150
1212
  domain: "ProxySchemeHandler",
1151
1213
  code: NSURLErrorCancelled,
1152
1214
  userInfo: [NSLocalizedDescriptionKey: "WebView closed"]
@@ -226,6 +226,16 @@ enum ConsoleMessageSupport {
226
226
  }
227
227
  }
228
228
 
229
+ enum WebViewViewportLayoutSupport {
230
+ static func shouldRefreshViewport(previousSize: CGSize?, currentSize: CGSize, force: Bool = false) -> Bool {
231
+ guard currentSize.width > 0, currentSize.height > 0 else {
232
+ return false
233
+ }
234
+
235
+ return force || previousSize != currentSize
236
+ }
237
+ }
238
+
229
239
  open class WKWebViewController: UIViewController, WKScriptMessageHandler {
230
240
 
231
241
  public init() {
@@ -343,9 +353,6 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
343
353
  var shareDisclaimer: [String: Any]?
344
354
  var shareSubject: String?
345
355
  var didpageInit = false
346
- var viewHeightLandscape: CGFloat?
347
- var viewHeightPortrait: CGFloat?
348
- var currentViewHeight: CGFloat?
349
356
  open var closeModal = false
350
357
  open var closeModalTitle = ""
351
358
  open var closeModalDescription = ""
@@ -386,6 +393,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
386
393
  internal var preShowSemaphore: DispatchSemaphore?
387
394
  internal var preShowError: String?
388
395
  private var isWebViewInitialized = false
396
+ private var isObservingKeyboardViewportChanges = false
397
+ private var lastViewportRefreshSize: CGSize?
389
398
  private var downloadStates: [ObjectIdentifier: WKDownloadState] = [:]
390
399
  private var previewItemURL: URL?
391
400
 
@@ -432,10 +441,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
432
441
 
433
442
  private func attachmentDispositionType(_ response: URLResponse) -> String? {
434
443
  guard let disposition = attachmentDisposition(response)?
435
- .split(separator: ";", maxSplits: 1)
436
- .first?
437
- .trimmingCharacters(in: .whitespacesAndNewlines)
438
- .lowercased(),
444
+ .split(separator: ";", maxSplits: 1)
445
+ .first?
446
+ .trimmingCharacters(in: .whitespacesAndNewlines)
447
+ .lowercased(),
439
448
  !disposition.isEmpty else {
440
449
  return nil
441
450
  }
@@ -527,7 +536,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
527
536
  "application/download",
528
537
  "application/x-download",
529
538
  "application/binary",
530
- "application/x-binary",
539
+ "application/x-binary"
531
540
  ]
532
541
 
533
542
  if let candidate, !candidate.isEmpty, !genericMimeTypes.contains(candidate) {
@@ -590,7 +599,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
590
599
  "fileName": fileURL.lastPathComponent,
591
600
  "path": fileURL.path,
592
601
  "localUrl": fileURL.absoluteString,
593
- "handledBy": handledBy,
602
+ "handledBy": handledBy
594
603
  ]
595
604
  if let sourceURL {
596
605
  data["sourceUrl"] = sourceURL
@@ -842,6 +851,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
842
851
  }
843
852
 
844
853
  deinit {
854
+ NotificationCenter.default.removeObserver(self)
845
855
  webView?.removeObserver(self, forKeyPath: estimatedProgressKeyPath)
846
856
  if websiteTitleInNavigationBar {
847
857
  webView?.removeObserver(self, forKeyPath: titleKeyPath)
@@ -886,6 +896,11 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
886
896
  }
887
897
  }
888
898
 
899
+ override open func viewDidLayoutSubviews() {
900
+ super.viewDidLayoutSubviews()
901
+ refreshWebViewViewportIfNeeded()
902
+ }
903
+
889
904
  func updateButtonTintColors() {
890
905
  // Ensure all button items use the navigation bar's tint color
891
906
  if let tintColor = navigationController?.navigationBar.tintColor {
@@ -986,6 +1001,63 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
986
1001
  capBrowserPlugin?.notifyListeners(eventName, data: payload(with: data))
987
1002
  }
988
1003
 
1004
+ private func startObservingKeyboardViewportChanges() {
1005
+ guard !isObservingKeyboardViewportChanges else {
1006
+ return
1007
+ }
1008
+
1009
+ isObservingKeyboardViewportChanges = true
1010
+ let center = NotificationCenter.default
1011
+ center.addObserver(self, selector: #selector(keyboardViewportDidChange(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
1012
+ center.addObserver(self, selector: #selector(keyboardViewportDidChange(_:)), name: UIResponder.keyboardDidHideNotification, object: nil)
1013
+ center.addObserver(self, selector: #selector(keyboardViewportDidChange(_:)), name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
1014
+ }
1015
+
1016
+ @objc private func keyboardViewportDidChange(_ notification: Notification) {
1017
+ scheduleWebViewViewportRefresh(force: true, delay: viewportRefreshDelay(from: notification))
1018
+ }
1019
+
1020
+ private func viewportRefreshDelay(from notification: Notification) -> TimeInterval {
1021
+ guard let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber else {
1022
+ return 0.05
1023
+ }
1024
+
1025
+ return max(0.05, duration.doubleValue)
1026
+ }
1027
+
1028
+ private func scheduleWebViewViewportRefresh(force: Bool = false, delay: TimeInterval = 0.05) {
1029
+ DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
1030
+ self?.refreshWebViewViewportIfNeeded(force: force)
1031
+ }
1032
+ }
1033
+
1034
+ private func refreshWebViewViewportIfNeeded(force: Bool = false) {
1035
+ guard let webView = self.webView, webView.superview != nil else {
1036
+ return
1037
+ }
1038
+
1039
+ if force {
1040
+ self.view.setNeedsLayout()
1041
+ self.view.layoutIfNeeded()
1042
+ }
1043
+
1044
+ let currentSize = webView.bounds.size
1045
+ guard WebViewViewportLayoutSupport.shouldRefreshViewport(
1046
+ previousSize: lastViewportRefreshSize,
1047
+ currentSize: currentSize,
1048
+ force: force
1049
+ ) else {
1050
+ return
1051
+ }
1052
+
1053
+ lastViewportRefreshSize = currentSize
1054
+ webView.setNeedsLayout()
1055
+ webView.layoutIfNeeded()
1056
+ webView.scrollView.setNeedsLayout()
1057
+ webView.scrollView.layoutIfNeeded()
1058
+ webView.evaluateJavaScript("window.dispatchEvent(new Event('resize'));", completionHandler: nil)
1059
+ }
1060
+
989
1061
  private func jsonString(from object: Any) -> String? {
990
1062
  guard JSONSerialization.isValidJSONObject(object),
991
1063
  let data = try? JSONSerialization.data(withJSONObject: object),
@@ -1251,6 +1323,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1251
1323
  return
1252
1324
  }
1253
1325
  self.isWebViewInitialized = true
1326
+ self.startObservingKeyboardViewportChanges()
1254
1327
  self.view.backgroundColor = UIColor.white
1255
1328
 
1256
1329
  self.extendedLayoutIncludesOpaqueBars = true
@@ -1540,47 +1613,6 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1540
1613
  return self.capableWebView
1541
1614
  }
1542
1615
 
1543
- @objc func restateViewHeight() {
1544
- var bottomPadding = CGFloat(0.0)
1545
- var topPadding = CGFloat(0.0)
1546
- let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow })
1547
- bottomPadding = window?.safeAreaInsets.bottom ?? 0.0
1548
- topPadding = window?.safeAreaInsets.top ?? 0.0
1549
- if UIDevice.current.orientation.isPortrait {
1550
- // Don't force toolbar visibility
1551
- if self.viewHeightPortrait == nil {
1552
- self.viewHeightPortrait = self.view.safeAreaLayoutGuide.layoutFrame.size.height
1553
- self.viewHeightPortrait! += bottomPadding
1554
- if self.navigationController?.navigationBar.isHidden == true {
1555
- self.viewHeightPortrait! += topPadding
1556
- }
1557
- }
1558
- self.currentViewHeight = self.viewHeightPortrait
1559
- } else if UIDevice.current.orientation.isLandscape {
1560
- // Don't force toolbar visibility
1561
- if self.viewHeightLandscape == nil {
1562
- self.viewHeightLandscape = self.view.safeAreaLayoutGuide.layoutFrame.size.height
1563
- self.viewHeightLandscape! += bottomPadding
1564
- if self.navigationController?.navigationBar.isHidden == true {
1565
- self.viewHeightLandscape! += topPadding
1566
- }
1567
- }
1568
- self.currentViewHeight = self.viewHeightLandscape
1569
- }
1570
- }
1571
-
1572
- override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
1573
- // self.view.frame.size.height = self.currentViewHeight!
1574
- }
1575
-
1576
- override open func viewWillLayoutSubviews() {
1577
- restateViewHeight()
1578
- // Don't override frame height when enabledSafeBottomMargin is true, as it would override our constraints
1579
- if self.currentViewHeight != nil && !self.enabledSafeBottomMargin {
1580
- self.view.frame.size.height = self.currentViewHeight!
1581
- }
1582
- }
1583
-
1584
1616
  override open func viewWillAppear(_ animated: Bool) {
1585
1617
  super.viewWillAppear(animated)
1586
1618
  if !self.viewWasPresented {
@@ -1620,6 +1652,8 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
1620
1652
 
1621
1653
  override open func viewDidAppear(_ animated: Bool) {
1622
1654
  super.viewDidAppear(animated)
1655
+ refreshWebViewViewportIfNeeded(force: true)
1656
+ scheduleWebViewViewportRefresh(force: true, delay: 0.25)
1623
1657
 
1624
1658
  // Force add buttonNearDone if it's not visible yet
1625
1659
  if buttonNearDoneIcon != nil {
@@ -2907,6 +2941,7 @@ extension WKWebViewController: WKNavigationDelegate {
2907
2941
  webView.topAnchor.constraint(equalTo: topAnchor)
2908
2942
  ])
2909
2943
  self.view.layoutIfNeeded()
2944
+ refreshWebViewViewportIfNeeded(force: true)
2910
2945
  }
2911
2946
 
2912
2947
  open func updateSafeBottomMargin(_ enabled: Bool) {
@@ -2927,6 +2962,7 @@ extension WKWebViewController: WKNavigationDelegate {
2927
2962
  webView.bottomAnchor.constraint(equalTo: bottomAnchor)
2928
2963
  ])
2929
2964
  self.view.layoutIfNeeded()
2965
+ refreshWebViewViewportIfNeeded(force: true)
2930
2966
  }
2931
2967
  }
2932
2968
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-inappbrowser",
3
- "version": "8.6.15",
3
+ "version": "8.6.17",
4
4
  "description": "Capacitor plugin in app browser",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",