@capgo/inappbrowser 7.0.0 → 7.1.6

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.
@@ -19,6 +19,11 @@ private struct UrlsHandledByApp {
19
19
  static var blank = true
20
20
  }
21
21
 
22
+ public struct WKWebViewCredentials {
23
+ var username: String
24
+ var password: String
25
+ }
26
+
22
27
  @objc public protocol WKWebViewControllerDelegate {
23
28
  @objc optional func webViewController(_ controller: WKWebViewController, canDismiss url: URL) -> Bool
24
29
 
@@ -28,7 +33,17 @@ private struct UrlsHandledByApp {
28
33
  @objc optional func webViewController(_ controller: WKWebViewController, decidePolicy url: URL, navigationType: NavigationType) -> Bool
29
34
  }
30
35
 
31
- open class WKWebViewController: UIViewController {
36
+ extension Dictionary {
37
+ func mapKeys<T>(_ transform: (Key) throws -> T) rethrows -> [T: Value] {
38
+ var dictionary = [T: Value]()
39
+ for (key, value) in self {
40
+ dictionary[try transform(key)] = value
41
+ }
42
+ return dictionary
43
+ }
44
+ }
45
+
46
+ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
32
47
 
33
48
  public init() {
34
49
  super.init(nibName: nil, bundle: nil)
@@ -38,23 +53,27 @@ open class WKWebViewController: UIViewController {
38
53
  super.init(coder: aDecoder)
39
54
  }
40
55
 
41
- public init(source: WKWebSource?) {
56
+ public init(source: WKWebSource?, credentials: WKWebViewCredentials? = nil) {
42
57
  super.init(nibName: nil, bundle: nil)
43
58
  self.source = source
59
+ self.credentials = credentials
44
60
  self.initWebview()
45
61
  }
46
62
 
47
- public init(url: URL) {
63
+ public init(url: URL, credentials: WKWebViewCredentials? = nil) {
48
64
  super.init(nibName: nil, bundle: nil)
49
65
  self.source = .remote(url)
66
+ self.credentials = credentials
50
67
  self.initWebview()
51
68
  }
52
69
 
53
- public init(url: URL, headers: [String: String]) {
70
+ public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool) {
54
71
  super.init(nibName: nil, bundle: nil)
55
72
  self.source = .remote(url)
73
+ self.credentials = credentials
56
74
  self.setHeaders(headers: headers)
57
- self.initWebview()
75
+ self.setPreventDeeplink(preventDeeplink: preventDeeplink)
76
+ self.initWebview(isInspectable: isInspectable)
58
77
  }
59
78
 
60
79
  open var hasDynamicTitle = false
@@ -74,16 +93,34 @@ open class WKWebViewController: UIViewController {
74
93
  var viewHeightLandscape: CGFloat?
75
94
  var viewHeightPortrait: CGFloat?
76
95
  var currentViewHeight: CGFloat?
96
+ open var closeModal = false
97
+ open var closeModalTitle = ""
98
+ open var closeModalDescription = ""
99
+ open var closeModalOk = ""
100
+ open var closeModalCancel = ""
101
+ open var ignoreUntrustedSSLError = false
102
+ var viewWasPresented = false
103
+ var preventDeeplink: Bool = false
104
+
105
+ internal var preShowSemaphore: DispatchSemaphore?
106
+ internal var preShowError: String?
77
107
 
78
108
  func setHeaders(headers: [String: String]) {
79
109
  self.headers = headers
80
- let userAgent = self.headers?["User-Agent"]
110
+ let lowercasedHeaders = headers.mapKeys { $0.lowercased() }
111
+ let userAgent = lowercasedHeaders["user-agent"]
81
112
  self.headers?.removeValue(forKey: "User-Agent")
82
- if userAgent != nil {
113
+ self.headers?.removeValue(forKey: "user-agent")
114
+
115
+ if let userAgent = userAgent {
83
116
  self.customUserAgent = userAgent
84
117
  }
85
118
  }
86
119
 
120
+ func setPreventDeeplink(preventDeeplink: Bool) {
121
+ self.preventDeeplink = preventDeeplink
122
+ }
123
+
87
124
  internal var customUserAgent: String? {
88
125
  didSet {
89
126
  guard let agent = userAgent else {
@@ -113,7 +150,8 @@ open class WKWebViewController: UIViewController {
113
150
 
114
151
  open var websiteTitleInNavigationBar = true
115
152
  open var doneBarButtonItemPosition: NavigationBarPosition = .right
116
- open var leftNavigaionBarItemTypes: [BarButtonItemType] = []
153
+ open var preShowScript: String?
154
+ open var leftNavigationBarItemTypes: [BarButtonItemType] = []
117
155
  open var rightNavigaionBarItemTypes: [BarButtonItemType] = []
118
156
  open var toolbarItemTypes: [BarButtonItemType] = [.back, .forward, .reload, .activity]
119
157
 
@@ -123,6 +161,8 @@ open class WKWebViewController: UIViewController {
123
161
  open var stopBarButtonItemImage: UIImage?
124
162
  open var activityBarButtonItemImage: UIImage?
125
163
 
164
+ open var buttonNearDoneIcon: UIImage?
165
+
126
166
  fileprivate var webView: WKWebView?
127
167
  fileprivate var progressView: UIProgressView?
128
168
 
@@ -173,6 +213,8 @@ open class WKWebViewController: UIViewController {
173
213
  return UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
174
214
  }()
175
215
 
216
+ fileprivate var credentials: WKWebViewCredentials?
217
+
176
218
  deinit {
177
219
  webView?.removeObserver(self, forKeyPath: estimatedProgressKeyPath)
178
220
  if websiteTitleInNavigationBar {
@@ -188,7 +230,66 @@ open class WKWebViewController: UIViewController {
188
230
  }
189
231
  }
190
232
 
191
- open func initWebview() {
233
+ open func setCredentials(credentials: WKWebViewCredentials?) {
234
+ self.credentials = credentials
235
+ }
236
+
237
+ // Method to send a message from Swift to JavaScript
238
+ open func postMessageToJS(message: [String: Any]) {
239
+ if let jsonData = try? JSONSerialization.data(withJSONObject: message, options: []),
240
+ let jsonString = String(data: jsonData, encoding: .utf8) {
241
+ let script = "window.dispatchEvent(new CustomEvent('messageFromNative', { detail: \(jsonString) }));"
242
+ DispatchQueue.main.async {
243
+ self.webView?.evaluateJavaScript(script, completionHandler: nil)
244
+ }
245
+ }
246
+ }
247
+
248
+ // Method to receive messages from JavaScript
249
+ public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
250
+ if message.name == "messageHandler" {
251
+ if let messageBody = message.body as? [String: Any] {
252
+ print("Received message from JavaScript:", messageBody)
253
+ self.capBrowserPlugin?.notifyListeners("messageFromWebview", data: messageBody)
254
+ } else {
255
+ print("Received non-dictionary message from JavaScript:", message.body)
256
+ self.capBrowserPlugin?.notifyListeners("messageFromWebview", data: ["rawMessage": String(describing: message.body)])
257
+ }
258
+ } else if message.name == "preShowScriptSuccess" {
259
+ guard let semaphore = preShowSemaphore else {
260
+ print("[InAppBrowser - preShowScriptSuccess]: Semaphore not found")
261
+ return
262
+ }
263
+
264
+ semaphore.signal()
265
+ } else if message.name == "preShowScriptError" {
266
+ guard let semaphore = preShowSemaphore else {
267
+ print("[InAppBrowser - preShowScriptError]: Semaphore not found")
268
+ return
269
+ }
270
+ print("[InAppBrowser - preShowScriptError]: Error!!!!")
271
+ semaphore.signal()
272
+ }
273
+ }
274
+
275
+ func injectJavaScriptInterface() {
276
+ let script = """
277
+ if (!window.mobileApp) {
278
+ window.mobileApp = {
279
+ postMessage: function(message) {
280
+ if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.messageHandler) {
281
+ window.webkit.messageHandlers.messageHandler.postMessage(message);
282
+ }
283
+ }
284
+ };
285
+ }
286
+ """
287
+ DispatchQueue.main.async {
288
+ self.webView?.evaluateJavaScript(script, completionHandler: nil)
289
+ }
290
+ }
291
+
292
+ open func initWebview(isInspectable: Bool = true) {
192
293
 
193
294
  self.view.backgroundColor = UIColor.white
194
295
 
@@ -196,8 +297,18 @@ open class WKWebViewController: UIViewController {
196
297
  self.edgesForExtendedLayout = [.bottom]
197
298
 
198
299
  let webConfiguration = WKWebViewConfiguration()
300
+ let userContentController = WKUserContentController()
301
+ userContentController.add(self, name: "messageHandler")
302
+ userContentController.add(self, name: "preShowScriptError")
303
+ userContentController.add(self, name: "preShowScriptSuccess")
304
+ webConfiguration.userContentController = userContentController
199
305
  let webView = WKWebView(frame: .zero, configuration: webConfiguration)
200
306
 
307
+ if webView.responds(to: Selector(("setInspectable:"))) {
308
+ // Fix: https://stackoverflow.com/questions/76216183/how-to-debug-wkwebview-in-ios-16-4-1-using-xcode-14-2/76603043#76603043
309
+ webView.perform(Selector(("setInspectable:")), with: isInspectable)
310
+ }
311
+
201
312
  webView.uiDelegate = self
202
313
  webView.navigationDelegate = self
203
314
 
@@ -223,8 +334,6 @@ open class WKWebViewController: UIViewController {
223
334
  self.previousToolbarState = (navigation.toolbar.tintColor, navigation.toolbar.isHidden)
224
335
  }
225
336
 
226
- // self.restateViewHeight()
227
-
228
337
  if let s = self.source {
229
338
  self.load(source: s)
230
339
  } else {
@@ -242,19 +351,19 @@ open class WKWebViewController: UIViewController {
242
351
  var bottomPadding = CGFloat(0.0)
243
352
  var topPadding = CGFloat(0.0)
244
353
  if #available(iOS 11.0, *) {
245
- let window = UIApplication.shared.keyWindow
246
- bottomPadding = (window?.safeAreaInsets.bottom)!
247
- topPadding = (window?.safeAreaInsets.top)!
354
+ let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow })
355
+ bottomPadding = window?.safeAreaInsets.bottom ?? 0.0
356
+ topPadding = window?.safeAreaInsets.top ?? 0.0
248
357
  }
249
358
  if UIDevice.current.orientation.isPortrait {
250
359
  self.navigationController?.toolbar.isHidden = false
251
360
  if self.viewHeightPortrait == nil {
252
361
  self.viewHeightPortrait = self.view.safeAreaLayoutGuide.layoutFrame.size.height
253
362
  if toolbarItemTypes.count == 0 {
254
- self.viewHeightPortrait! = self.viewHeightPortrait! + bottomPadding
363
+ self.viewHeightPortrait! += bottomPadding
255
364
  }
256
365
  if self.navigationController?.navigationBar.isHidden == true {
257
- self.viewHeightPortrait = self.viewHeightPortrait! + topPadding
366
+ self.viewHeightPortrait! += topPadding
258
367
  }
259
368
  }
260
369
  self.currentViewHeight = self.viewHeightPortrait
@@ -263,10 +372,10 @@ open class WKWebViewController: UIViewController {
263
372
  if self.viewHeightLandscape == nil {
264
373
  self.viewHeightLandscape = self.view.safeAreaLayoutGuide.layoutFrame.size.height
265
374
  if toolbarItemTypes.count == 0 {
266
- self.viewHeightLandscape! = self.viewHeightLandscape! + bottomPadding
375
+ self.viewHeightLandscape! += bottomPadding
267
376
  }
268
377
  if self.navigationController?.navigationBar.isHidden == true {
269
- self.viewHeightLandscape = self.viewHeightLandscape! + topPadding
378
+ self.viewHeightLandscape! += topPadding
270
379
  }
271
380
  }
272
381
  self.currentViewHeight = self.viewHeightLandscape
@@ -286,8 +395,11 @@ open class WKWebViewController: UIViewController {
286
395
 
287
396
  override open func viewWillAppear(_ animated: Bool) {
288
397
  super.viewWillAppear(animated)
289
- self.setupViewElements()
290
- setUpState()
398
+ if !self.viewWasPresented {
399
+ self.setupViewElements()
400
+ setUpState()
401
+ self.viewWasPresented = true
402
+ }
291
403
  }
292
404
 
293
405
  override open func viewWillDisappear(_ animated: Bool) {
@@ -295,34 +407,33 @@ open class WKWebViewController: UIViewController {
295
407
  rollbackState()
296
408
  }
297
409
 
298
- override open func didReceiveMemoryWarning() {
299
- super.didReceiveMemoryWarning()
300
- // Dispose of any resources that can be recreated.
301
- }
302
-
303
410
  override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
304
411
  switch keyPath {
305
412
  case estimatedProgressKeyPath?:
306
- guard let estimatedProgress = self.webView?.estimatedProgress else {
307
- return
308
- }
309
- self.progressView?.alpha = 1
310
- self.progressView?.setProgress(Float(estimatedProgress), animated: true)
311
-
312
- if estimatedProgress >= 1.0 {
313
- UIView.animate(withDuration: 0.3, delay: 0.3, options: .curveEaseOut, animations: {
314
- self.progressView?.alpha = 0
315
- }, completion: {
316
- _ in
317
- self.progressView?.setProgress(0, animated: false)
318
- })
413
+ DispatchQueue.main.async {
414
+ guard let estimatedProgress = self.webView?.estimatedProgress else {
415
+ return
416
+ }
417
+ self.progressView?.alpha = 1
418
+ self.progressView?.setProgress(Float(estimatedProgress), animated: true)
419
+
420
+ if estimatedProgress >= 1.0 {
421
+ UIView.animate(withDuration: 0.3, delay: 0.3, options: .curveEaseOut, animations: {
422
+ self.progressView?.alpha = 0
423
+ }, completion: {
424
+ _ in
425
+ self.progressView?.setProgress(0, animated: false)
426
+ })
427
+ }
319
428
  }
320
429
  case titleKeyPath?:
321
430
  if self.hasDynamicTitle {
322
431
  self.navigationItem.title = webView?.url?.host
323
432
  }
324
433
  case "URL":
434
+
325
435
  self.capBrowserPlugin?.notifyListeners("urlChangeEvent", data: ["url": webView?.url?.absoluteString ?? ""])
436
+ self.injectJavaScriptInterface()
326
437
  default:
327
438
  super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
328
439
  }
@@ -344,7 +455,9 @@ public extension WKWebViewController {
344
455
  }
345
456
 
346
457
  func load(remote: URL) {
347
- webView?.load(createRequest(url: remote))
458
+ DispatchQueue.main.async {
459
+ self.webView?.load(self.createRequest(url: remote))
460
+ }
348
461
  }
349
462
 
350
463
  func load(file: URL, access: URL) {
@@ -360,6 +473,15 @@ public extension WKWebViewController {
360
473
  webView?.go(to: firstPageItem)
361
474
  }
362
475
  }
476
+ func reload() {
477
+ webView?.reload()
478
+ }
479
+
480
+ func executeScript(script: String, completion: ((Any?, Error?) -> Void)? = nil) {
481
+ DispatchQueue.main.async { [weak self] in
482
+ self?.webView?.evaluateJavaScript(script, completionHandler: completion)
483
+ }
484
+ }
363
485
  }
364
486
 
365
487
  // MARK: - Fileprivate Methods
@@ -444,7 +566,7 @@ fileprivate extension WKWebViewController {
444
566
  // if presentingViewController != nil {
445
567
  switch doneBarButtonItemPosition {
446
568
  case .left:
447
- if !leftNavigaionBarItemTypes.contains(where: { type in
569
+ if !leftNavigationBarItemTypes.contains(where: { type in
448
570
  switch type {
449
571
  case .done:
450
572
  return true
@@ -452,7 +574,7 @@ fileprivate extension WKWebViewController {
452
574
  return false
453
575
  }
454
576
  }) {
455
- leftNavigaionBarItemTypes.insert(.done, at: 0)
577
+ leftNavigationBarItemTypes.insert(.done, at: 0)
456
578
  }
457
579
  case .right:
458
580
  if !rightNavigaionBarItemTypes.contains(where: { type in
@@ -470,7 +592,7 @@ fileprivate extension WKWebViewController {
470
592
  }
471
593
  // }
472
594
 
473
- navigationItem.leftBarButtonItems = leftNavigaionBarItemTypes.map {
595
+ navigationItem.leftBarButtonItems = leftNavigationBarItemTypes.map {
474
596
  barButtonItemType in
475
597
  if let barButtonItem = barButtonItem(barButtonItemType) {
476
598
  return barButtonItem
@@ -478,13 +600,17 @@ fileprivate extension WKWebViewController {
478
600
  return UIBarButtonItem()
479
601
  }
480
602
 
481
- navigationItem.rightBarButtonItems = rightNavigaionBarItemTypes.map {
603
+ var rightBarButtons = rightNavigaionBarItemTypes.map {
482
604
  barButtonItemType in
483
605
  if let barButtonItem = barButtonItem(barButtonItemType) {
484
606
  return barButtonItem
485
607
  }
486
608
  return UIBarButtonItem()
487
609
  }
610
+ if rightBarButtons.count == 1 && buttonNearDoneIcon != nil && rightBarButtons[0] == doneBarButtonItem {
611
+ rightBarButtons.append(UIBarButtonItem(image: buttonNearDoneIcon, style: .plain, target: self, action: #selector(buttonNearDoneDidClick)))
612
+ }
613
+ navigationItem.rightBarButtonItems = rightBarButtons
488
614
 
489
615
  if toolbarItemTypes.count > 0 {
490
616
  for index in 0..<toolbarItemTypes.count - 1 {
@@ -492,13 +618,14 @@ fileprivate extension WKWebViewController {
492
618
  }
493
619
  }
494
620
 
495
- setToolbarItems(toolbarItemTypes.map {
621
+ let gen = toolbarItemTypes.map {
496
622
  barButtonItemType -> UIBarButtonItem in
497
623
  if let barButtonItem = barButtonItem(barButtonItemType) {
498
624
  return barButtonItem
499
625
  }
500
626
  return UIBarButtonItem()
501
- }, animated: true)
627
+ }
628
+ setToolbarItems(gen, animated: true)
502
629
  }
503
630
 
504
631
  func updateBarButtonItems() {
@@ -617,6 +744,10 @@ fileprivate extension WKWebViewController {
617
744
  webView?.goForward()
618
745
  }
619
746
 
747
+ @objc func buttonNearDoneDidClick(sender: AnyObject) {
748
+ self.capBrowserPlugin?.notifyListeners("buttonNearDoneClick", data: [:])
749
+ }
750
+
620
751
  @objc func reloadDidClick(sender: AnyObject) {
621
752
  webView?.stopLoading()
622
753
  if webView?.url != nil {
@@ -666,13 +797,14 @@ fileprivate extension WKWebViewController {
666
797
  self.present(alert, animated: true, completion: nil)
667
798
  } else {
668
799
  let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil)
800
+ #imageLiteral(resourceName: "simulator_screenshot_B8B44B8D-EB30-425C-9BF4-1F37697A8459.png")
669
801
  activityViewController.setValue(self.shareSubject ?? self.title, forKey: "subject")
670
802
  activityViewController.popoverPresentationController?.barButtonItem = (sender as! UIBarButtonItem)
671
803
  self.present(activityViewController, animated: true, completion: nil)
672
804
  }
673
805
  }
674
806
 
675
- @objc func doneDidClick(sender: AnyObject) {
807
+ func closeView () {
676
808
  var canDismiss = true
677
809
  if let url = self.source?.url {
678
810
  canDismiss = delegate?.webViewController?(self, canDismiss: url) ?? true
@@ -684,6 +816,21 @@ fileprivate extension WKWebViewController {
684
816
  }
685
817
  }
686
818
 
819
+ @objc func doneDidClick(sender: AnyObject) {
820
+ // check if closeModal is true, if true display alert before close
821
+ if self.closeModal {
822
+ let alert = UIAlertController(title: self.closeModalTitle, message: self.closeModalDescription, preferredStyle: UIAlertController.Style.alert)
823
+ alert.addAction(UIAlertAction(title: self.closeModalOk, style: UIAlertAction.Style.default, handler: { _ in
824
+ self.closeView()
825
+ }))
826
+ alert.addAction(UIAlertAction(title: self.closeModalCancel, style: UIAlertAction.Style.default, handler: nil))
827
+ self.present(alert, animated: true, completion: nil)
828
+ } else {
829
+ self.closeView()
830
+ }
831
+
832
+ }
833
+
687
834
  @objc func customDidClick(sender: BlockBarButtonItem) {
688
835
  sender.block?(self)
689
836
  }
@@ -693,11 +840,61 @@ fileprivate extension WKWebViewController {
693
840
 
694
841
  // MARK: - WKUIDelegate
695
842
  extension WKWebViewController: WKUIDelegate {
696
-
843
+ public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
844
+ // Ensure UI updates are on the main thread
845
+ DispatchQueue.main.async {
846
+ let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
847
+ alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
848
+ completionHandler()
849
+ }))
850
+ self.present(alertController, animated: true, completion: nil)
851
+ }
852
+ }
697
853
  }
698
854
 
699
855
  // MARK: - WKNavigationDelegate
700
856
  extension WKWebViewController: WKNavigationDelegate {
857
+ internal func injectPreShowScript() {
858
+ if preShowSemaphore != nil {
859
+ return
860
+ }
861
+
862
+ // TODO: implement interface
863
+ let script = """
864
+ async function preShowFunction() {
865
+ \(self.preShowScript ?? "")
866
+ };
867
+ preShowFunction().then(
868
+ () => window.webkit.messageHandlers.preShowScriptSuccess.postMessage({})
869
+ ).catch(
870
+ err => {
871
+ console.error('Preshow error', err);
872
+ window.webkit.messageHandlers.preShowScriptError.postMessage(JSON.stringify(err, Object.getOwnPropertyNames(err)));
873
+ }
874
+ )
875
+ """
876
+ print("[InAppBrowser - InjectPreShowScript] PreShowScript script: \(script)")
877
+
878
+ self.preShowSemaphore = DispatchSemaphore(value: 0)
879
+ self.executeScript(script: script) // this will run on the main thread
880
+
881
+ defer {
882
+ self.preShowSemaphore = nil
883
+ self.preShowError = nil
884
+ }
885
+
886
+ if self.preShowSemaphore?.wait(timeout: .now() + 10) == .timedOut {
887
+ print("[InAppBrowser - InjectPreShowScript] PreShowScript running for over 10 seconds. The plugin will not wait any longer!")
888
+ return
889
+ }
890
+
891
+ // "async function preShowFunction() {\n" +
892
+ // self.preShowScript + "\n" +
893
+ // "};\n" +
894
+ // "preShowFunction().then(() => window.PreShowScriptInterface.success()).catch(err => { console.error('Preshow error', err); window.PreShowScriptInterface.error(JSON.stringify(err, Object.getOwnPropertyNames(err))) })";
895
+
896
+ }
897
+
701
898
  public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
702
899
  updateBarButtonItems()
703
900
  self.progressView?.progress = 0
@@ -708,7 +905,21 @@ extension WKWebViewController: WKNavigationDelegate {
708
905
  }
709
906
  public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
710
907
  if !didpageInit && self.capBrowserPlugin?.isPresentAfterPageLoad == true {
711
- self.capBrowserPlugin?.presentView()
908
+ // injectPreShowScript will block, don't execute on the main thread
909
+ if self.preShowScript != nil && !self.preShowScript!.isEmpty {
910
+ DispatchQueue.global(qos: .userInitiated).async {
911
+ self.injectPreShowScript()
912
+ DispatchQueue.main.async { [weak self] in
913
+ self?.capBrowserPlugin?.presentView()
914
+ }
915
+ }
916
+ } else {
917
+ self.capBrowserPlugin?.presentView()
918
+ }
919
+ } else if self.preShowScript != nil && !self.preShowScript!.isEmpty && self.capBrowserPlugin?.isPresentAfterPageLoad == true {
920
+ DispatchQueue.global(qos: .userInitiated).async {
921
+ self.injectPreShowScript()
922
+ }
712
923
  }
713
924
  didpageInit = true
714
925
  updateBarButtonItems()
@@ -717,6 +928,8 @@ extension WKWebViewController: WKNavigationDelegate {
717
928
  self.url = url
718
929
  delegate?.webViewController?(self, didFinish: url)
719
930
  }
931
+ self.injectJavaScriptInterface()
932
+ self.capBrowserPlugin?.notifyListeners("browserPageLoaded", data: [:])
720
933
  }
721
934
 
722
935
  public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
@@ -726,6 +939,7 @@ extension WKWebViewController: WKNavigationDelegate {
726
939
  self.url = url
727
940
  delegate?.webViewController?(self, didFail: url, withError: error)
728
941
  }
942
+ self.capBrowserPlugin?.notifyListeners("pageLoadError", data: [:])
729
943
  }
730
944
 
731
945
  public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
@@ -735,46 +949,76 @@ extension WKWebViewController: WKNavigationDelegate {
735
949
  self.url = url
736
950
  delegate?.webViewController?(self, didFail: url, withError: error)
737
951
  }
952
+ self.capBrowserPlugin?.notifyListeners("pageLoadError", data: [:])
738
953
  }
739
954
 
740
955
  public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
741
- if let bypassedSSLHosts = bypassedSSLHosts, bypassedSSLHosts.contains(challenge.protectionSpace.host) {
956
+ if let credentials = credentials,
957
+ challenge.protectionSpace.receivesCredentialSecurely,
958
+ let url = webView.url, challenge.protectionSpace.host == url.host, challenge.protectionSpace.protocol == url.scheme, challenge.protectionSpace.port == url.port ?? (url.scheme == "https" ? 443 : url.scheme == "http" ? 80 : nil) {
959
+ let urlCredential = URLCredential(user: credentials.username, password: credentials.password, persistence: .none)
960
+ completionHandler(.useCredential, urlCredential)
961
+ } else if let bypassedSSLHosts = bypassedSSLHosts, bypassedSSLHosts.contains(challenge.protectionSpace.host) {
742
962
  let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
743
963
  completionHandler(.useCredential, credential)
744
964
  } else {
745
- completionHandler(.performDefaultHandling, nil)
965
+ guard self.ignoreUntrustedSSLError else {
966
+ completionHandler(.performDefaultHandling, nil)
967
+ return
968
+ }
969
+ /* allows to open links with self-signed certificates
970
+ Follow Apple's guidelines https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication
971
+ */
972
+ guard let serverTrust = challenge.protectionSpace.serverTrust else {
973
+ completionHandler(.useCredential, nil)
974
+ return
975
+ }
976
+ let credential = URLCredential(trust: serverTrust)
977
+ completionHandler(.useCredential, credential)
746
978
  }
979
+ self.injectJavaScriptInterface()
747
980
  }
748
981
 
749
982
  public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
750
983
  var actionPolicy: WKNavigationActionPolicy = .allow
751
- defer {
752
- decisionHandler(actionPolicy)
984
+
985
+ if self.preventDeeplink {
986
+ actionPolicy = .preventDeeplinkActionPolicy
753
987
  }
988
+
754
989
  guard let u = navigationAction.request.url else {
755
- print("Cannot handle empty URLs")
990
+ decisionHandler(actionPolicy)
991
+ return
992
+ }
993
+
994
+ // Check if the URL is an App Store URL
995
+ if u.absoluteString.contains("apps.apple.com") {
996
+ UIApplication.shared.open(u, options: [:], completionHandler: nil)
997
+ // Cancel the navigation in the web view
998
+ decisionHandler(.cancel)
756
999
  return
757
1000
  }
758
1001
 
759
1002
  if !self.allowsFileURL && u.isFileURL {
760
1003
  print("Cannot handle file URLs")
1004
+ decisionHandler(.cancel)
761
1005
  return
762
1006
  }
763
1007
 
764
1008
  if handleURLWithApp(u, targetFrame: navigationAction.targetFrame) {
765
1009
  actionPolicy = .cancel
766
- return
767
1010
  }
768
1011
 
769
1012
  if u.host == self.source?.url?.host, let cookies = availableCookies, !checkRequestCookies(navigationAction.request, cookies: cookies) {
770
1013
  self.load(remote: u)
771
1014
  actionPolicy = .cancel
772
- return
773
1015
  }
774
1016
 
775
1017
  if let navigationType = NavigationType(rawValue: navigationAction.navigationType.rawValue), let result = delegate?.webViewController?(self, decidePolicy: u, navigationType: navigationType) {
776
1018
  actionPolicy = result ? .allow : .cancel
777
1019
  }
1020
+ self.injectJavaScriptInterface()
1021
+ decisionHandler(actionPolicy)
778
1022
  }
779
1023
  }
780
1024
 
@@ -782,3 +1026,7 @@ class BlockBarButtonItem: UIBarButtonItem {
782
1026
 
783
1027
  var block: ((WKWebViewController) -> Void)?
784
1028
  }
1029
+
1030
+ extension WKNavigationActionPolicy {
1031
+ static let preventDeeplinkActionPolicy = WKNavigationActionPolicy(rawValue: WKNavigationActionPolicy.allow.rawValue + 2)!
1032
+ }