@capgo/inappbrowser 7.0.0 → 7.1.1
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/CapgoInappbrowser.podspec +1 -1
- package/README.md +448 -54
- package/android/build.gradle +14 -13
- package/android/src/main/AndroidManifest.xml +3 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +534 -35
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +251 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +4 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +891 -19
- package/android/src/main/res/drawable/ic_refresh.xml +9 -0
- package/android/src/main/res/layout/tool_bar.xml +25 -3
- package/android/src/main/res/values/strings.xml +2 -0
- package/dist/docs.json +1365 -67
- package/dist/esm/definitions.d.ts +218 -9
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +10 -2
- package/dist/esm/web.js +26 -2
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +26 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +26 -2
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/InAppBrowserPlugin.m +5 -1
- package/ios/Plugin/InAppBrowserPlugin.swift +243 -12
- package/ios/Plugin/WKWebViewController.swift +299 -55
- package/package.json +26 -27
|
@@ -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
|
-
|
|
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.
|
|
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
|
|
110
|
+
let lowercasedHeaders = headers.mapKeys { $0.lowercased() }
|
|
111
|
+
let userAgent = lowercasedHeaders["user-agent"]
|
|
81
112
|
self.headers?.removeValue(forKey: "User-Agent")
|
|
82
|
-
|
|
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
|
|
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,64 @@ open class WKWebViewController: UIViewController {
|
|
|
188
230
|
}
|
|
189
231
|
}
|
|
190
232
|
|
|
191
|
-
open func
|
|
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
|
+
webView?.evaluateJavaScript(script, completionHandler: nil)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Method to receive messages from JavaScript
|
|
247
|
+
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
|
248
|
+
if message.name == "messageHandler" {
|
|
249
|
+
if let messageBody = message.body as? [String: Any] {
|
|
250
|
+
print("Received message from JavaScript:", messageBody)
|
|
251
|
+
self.capBrowserPlugin?.notifyListeners("messageFromWebview", data: messageBody)
|
|
252
|
+
} else {
|
|
253
|
+
print("Received non-dictionary message from JavaScript:", message.body)
|
|
254
|
+
self.capBrowserPlugin?.notifyListeners("messageFromWebview", data: ["rawMessage": String(describing: message.body)])
|
|
255
|
+
}
|
|
256
|
+
} else if message.name == "preShowScriptSuccess" {
|
|
257
|
+
guard let semaphore = preShowSemaphore else {
|
|
258
|
+
print("[InAppBrowser - preShowScriptSuccess]: Semaphore not found")
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
semaphore.signal()
|
|
263
|
+
} else if message.name == "preShowScriptError" {
|
|
264
|
+
guard let semaphore = preShowSemaphore else {
|
|
265
|
+
print("[InAppBrowser - preShowScriptError]: Semaphore not found")
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
print("[InAppBrowser - preShowScriptError]: Error!!!!")
|
|
269
|
+
semaphore.signal()
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
func injectJavaScriptInterface() {
|
|
274
|
+
let script = """
|
|
275
|
+
if (!window.mobileApp) {
|
|
276
|
+
window.mobileApp = {
|
|
277
|
+
postMessage: function(message) {
|
|
278
|
+
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.messageHandler) {
|
|
279
|
+
window.webkit.messageHandlers.messageHandler.postMessage(message);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
"""
|
|
285
|
+
DispatchQueue.main.async {
|
|
286
|
+
self.webView?.evaluateJavaScript(script, completionHandler: nil)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
open func initWebview(isInspectable: Bool = true) {
|
|
192
291
|
|
|
193
292
|
self.view.backgroundColor = UIColor.white
|
|
194
293
|
|
|
@@ -196,8 +295,18 @@ open class WKWebViewController: UIViewController {
|
|
|
196
295
|
self.edgesForExtendedLayout = [.bottom]
|
|
197
296
|
|
|
198
297
|
let webConfiguration = WKWebViewConfiguration()
|
|
298
|
+
let userContentController = WKUserContentController()
|
|
299
|
+
userContentController.add(self, name: "messageHandler")
|
|
300
|
+
userContentController.add(self, name: "preShowScriptError")
|
|
301
|
+
userContentController.add(self, name: "preShowScriptSuccess")
|
|
302
|
+
webConfiguration.userContentController = userContentController
|
|
199
303
|
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
|
|
200
304
|
|
|
305
|
+
if webView.responds(to: Selector(("setInspectable:"))) {
|
|
306
|
+
// Fix: https://stackoverflow.com/questions/76216183/how-to-debug-wkwebview-in-ios-16-4-1-using-xcode-14-2/76603043#76603043
|
|
307
|
+
webView.perform(Selector(("setInspectable:")), with: isInspectable)
|
|
308
|
+
}
|
|
309
|
+
|
|
201
310
|
webView.uiDelegate = self
|
|
202
311
|
webView.navigationDelegate = self
|
|
203
312
|
|
|
@@ -223,8 +332,6 @@ open class WKWebViewController: UIViewController {
|
|
|
223
332
|
self.previousToolbarState = (navigation.toolbar.tintColor, navigation.toolbar.isHidden)
|
|
224
333
|
}
|
|
225
334
|
|
|
226
|
-
// self.restateViewHeight()
|
|
227
|
-
|
|
228
335
|
if let s = self.source {
|
|
229
336
|
self.load(source: s)
|
|
230
337
|
} else {
|
|
@@ -242,19 +349,19 @@ open class WKWebViewController: UIViewController {
|
|
|
242
349
|
var bottomPadding = CGFloat(0.0)
|
|
243
350
|
var topPadding = CGFloat(0.0)
|
|
244
351
|
if #available(iOS 11.0, *) {
|
|
245
|
-
let window = UIApplication.shared.
|
|
246
|
-
bottomPadding =
|
|
247
|
-
topPadding =
|
|
352
|
+
let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow })
|
|
353
|
+
bottomPadding = window?.safeAreaInsets.bottom ?? 0.0
|
|
354
|
+
topPadding = window?.safeAreaInsets.top ?? 0.0
|
|
248
355
|
}
|
|
249
356
|
if UIDevice.current.orientation.isPortrait {
|
|
250
357
|
self.navigationController?.toolbar.isHidden = false
|
|
251
358
|
if self.viewHeightPortrait == nil {
|
|
252
359
|
self.viewHeightPortrait = self.view.safeAreaLayoutGuide.layoutFrame.size.height
|
|
253
360
|
if toolbarItemTypes.count == 0 {
|
|
254
|
-
self.viewHeightPortrait!
|
|
361
|
+
self.viewHeightPortrait! += bottomPadding
|
|
255
362
|
}
|
|
256
363
|
if self.navigationController?.navigationBar.isHidden == true {
|
|
257
|
-
self.viewHeightPortrait
|
|
364
|
+
self.viewHeightPortrait! += topPadding
|
|
258
365
|
}
|
|
259
366
|
}
|
|
260
367
|
self.currentViewHeight = self.viewHeightPortrait
|
|
@@ -263,10 +370,10 @@ open class WKWebViewController: UIViewController {
|
|
|
263
370
|
if self.viewHeightLandscape == nil {
|
|
264
371
|
self.viewHeightLandscape = self.view.safeAreaLayoutGuide.layoutFrame.size.height
|
|
265
372
|
if toolbarItemTypes.count == 0 {
|
|
266
|
-
self.viewHeightLandscape!
|
|
373
|
+
self.viewHeightLandscape! += bottomPadding
|
|
267
374
|
}
|
|
268
375
|
if self.navigationController?.navigationBar.isHidden == true {
|
|
269
|
-
self.viewHeightLandscape
|
|
376
|
+
self.viewHeightLandscape! += topPadding
|
|
270
377
|
}
|
|
271
378
|
}
|
|
272
379
|
self.currentViewHeight = self.viewHeightLandscape
|
|
@@ -286,8 +393,11 @@ open class WKWebViewController: UIViewController {
|
|
|
286
393
|
|
|
287
394
|
override open func viewWillAppear(_ animated: Bool) {
|
|
288
395
|
super.viewWillAppear(animated)
|
|
289
|
-
self.
|
|
290
|
-
|
|
396
|
+
if !self.viewWasPresented {
|
|
397
|
+
self.setupViewElements()
|
|
398
|
+
setUpState()
|
|
399
|
+
self.viewWasPresented = true
|
|
400
|
+
}
|
|
291
401
|
}
|
|
292
402
|
|
|
293
403
|
override open func viewWillDisappear(_ animated: Bool) {
|
|
@@ -295,34 +405,33 @@ open class WKWebViewController: UIViewController {
|
|
|
295
405
|
rollbackState()
|
|
296
406
|
}
|
|
297
407
|
|
|
298
|
-
override open func didReceiveMemoryWarning() {
|
|
299
|
-
super.didReceiveMemoryWarning()
|
|
300
|
-
// Dispose of any resources that can be recreated.
|
|
301
|
-
}
|
|
302
|
-
|
|
303
408
|
override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
|
|
304
409
|
switch keyPath {
|
|
305
410
|
case estimatedProgressKeyPath?:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
411
|
+
DispatchQueue.main.async {
|
|
412
|
+
guard let estimatedProgress = self.webView?.estimatedProgress else {
|
|
413
|
+
return
|
|
414
|
+
}
|
|
415
|
+
self.progressView?.alpha = 1
|
|
416
|
+
self.progressView?.setProgress(Float(estimatedProgress), animated: true)
|
|
417
|
+
|
|
418
|
+
if estimatedProgress >= 1.0 {
|
|
419
|
+
UIView.animate(withDuration: 0.3, delay: 0.3, options: .curveEaseOut, animations: {
|
|
420
|
+
self.progressView?.alpha = 0
|
|
421
|
+
}, completion: {
|
|
422
|
+
_ in
|
|
423
|
+
self.progressView?.setProgress(0, animated: false)
|
|
424
|
+
})
|
|
425
|
+
}
|
|
319
426
|
}
|
|
320
427
|
case titleKeyPath?:
|
|
321
428
|
if self.hasDynamicTitle {
|
|
322
429
|
self.navigationItem.title = webView?.url?.host
|
|
323
430
|
}
|
|
324
431
|
case "URL":
|
|
432
|
+
|
|
325
433
|
self.capBrowserPlugin?.notifyListeners("urlChangeEvent", data: ["url": webView?.url?.absoluteString ?? ""])
|
|
434
|
+
self.injectJavaScriptInterface()
|
|
326
435
|
default:
|
|
327
436
|
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
|
|
328
437
|
}
|
|
@@ -344,7 +453,9 @@ public extension WKWebViewController {
|
|
|
344
453
|
}
|
|
345
454
|
|
|
346
455
|
func load(remote: URL) {
|
|
347
|
-
|
|
456
|
+
DispatchQueue.main.async {
|
|
457
|
+
self.webView?.load(self.createRequest(url: remote))
|
|
458
|
+
}
|
|
348
459
|
}
|
|
349
460
|
|
|
350
461
|
func load(file: URL, access: URL) {
|
|
@@ -360,6 +471,15 @@ public extension WKWebViewController {
|
|
|
360
471
|
webView?.go(to: firstPageItem)
|
|
361
472
|
}
|
|
362
473
|
}
|
|
474
|
+
func reload() {
|
|
475
|
+
webView?.reload()
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
func executeScript(script: String, completion: ((Any?, Error?) -> Void)? = nil) {
|
|
479
|
+
DispatchQueue.main.async { [weak self] in
|
|
480
|
+
self?.webView?.evaluateJavaScript(script, completionHandler: completion)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
363
483
|
}
|
|
364
484
|
|
|
365
485
|
// MARK: - Fileprivate Methods
|
|
@@ -444,7 +564,7 @@ fileprivate extension WKWebViewController {
|
|
|
444
564
|
// if presentingViewController != nil {
|
|
445
565
|
switch doneBarButtonItemPosition {
|
|
446
566
|
case .left:
|
|
447
|
-
if !
|
|
567
|
+
if !leftNavigationBarItemTypes.contains(where: { type in
|
|
448
568
|
switch type {
|
|
449
569
|
case .done:
|
|
450
570
|
return true
|
|
@@ -452,7 +572,7 @@ fileprivate extension WKWebViewController {
|
|
|
452
572
|
return false
|
|
453
573
|
}
|
|
454
574
|
}) {
|
|
455
|
-
|
|
575
|
+
leftNavigationBarItemTypes.insert(.done, at: 0)
|
|
456
576
|
}
|
|
457
577
|
case .right:
|
|
458
578
|
if !rightNavigaionBarItemTypes.contains(where: { type in
|
|
@@ -470,7 +590,7 @@ fileprivate extension WKWebViewController {
|
|
|
470
590
|
}
|
|
471
591
|
// }
|
|
472
592
|
|
|
473
|
-
navigationItem.leftBarButtonItems =
|
|
593
|
+
navigationItem.leftBarButtonItems = leftNavigationBarItemTypes.map {
|
|
474
594
|
barButtonItemType in
|
|
475
595
|
if let barButtonItem = barButtonItem(barButtonItemType) {
|
|
476
596
|
return barButtonItem
|
|
@@ -478,13 +598,17 @@ fileprivate extension WKWebViewController {
|
|
|
478
598
|
return UIBarButtonItem()
|
|
479
599
|
}
|
|
480
600
|
|
|
481
|
-
|
|
601
|
+
var rightBarButtons = rightNavigaionBarItemTypes.map {
|
|
482
602
|
barButtonItemType in
|
|
483
603
|
if let barButtonItem = barButtonItem(barButtonItemType) {
|
|
484
604
|
return barButtonItem
|
|
485
605
|
}
|
|
486
606
|
return UIBarButtonItem()
|
|
487
607
|
}
|
|
608
|
+
if rightBarButtons.count == 1 && buttonNearDoneIcon != nil && rightBarButtons[0] == doneBarButtonItem {
|
|
609
|
+
rightBarButtons.append(UIBarButtonItem(image: buttonNearDoneIcon, style: .plain, target: self, action: #selector(buttonNearDoneDidClick)))
|
|
610
|
+
}
|
|
611
|
+
navigationItem.rightBarButtonItems = rightBarButtons
|
|
488
612
|
|
|
489
613
|
if toolbarItemTypes.count > 0 {
|
|
490
614
|
for index in 0..<toolbarItemTypes.count - 1 {
|
|
@@ -492,13 +616,14 @@ fileprivate extension WKWebViewController {
|
|
|
492
616
|
}
|
|
493
617
|
}
|
|
494
618
|
|
|
495
|
-
|
|
619
|
+
let gen = toolbarItemTypes.map {
|
|
496
620
|
barButtonItemType -> UIBarButtonItem in
|
|
497
621
|
if let barButtonItem = barButtonItem(barButtonItemType) {
|
|
498
622
|
return barButtonItem
|
|
499
623
|
}
|
|
500
624
|
return UIBarButtonItem()
|
|
501
|
-
}
|
|
625
|
+
}
|
|
626
|
+
setToolbarItems(gen, animated: true)
|
|
502
627
|
}
|
|
503
628
|
|
|
504
629
|
func updateBarButtonItems() {
|
|
@@ -617,6 +742,10 @@ fileprivate extension WKWebViewController {
|
|
|
617
742
|
webView?.goForward()
|
|
618
743
|
}
|
|
619
744
|
|
|
745
|
+
@objc func buttonNearDoneDidClick(sender: AnyObject) {
|
|
746
|
+
self.capBrowserPlugin?.notifyListeners("buttonNearDoneClick", data: [:])
|
|
747
|
+
}
|
|
748
|
+
|
|
620
749
|
@objc func reloadDidClick(sender: AnyObject) {
|
|
621
750
|
webView?.stopLoading()
|
|
622
751
|
if webView?.url != nil {
|
|
@@ -666,13 +795,14 @@ fileprivate extension WKWebViewController {
|
|
|
666
795
|
self.present(alert, animated: true, completion: nil)
|
|
667
796
|
} else {
|
|
668
797
|
let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil)
|
|
798
|
+
#imageLiteral(resourceName: "simulator_screenshot_B8B44B8D-EB30-425C-9BF4-1F37697A8459.png")
|
|
669
799
|
activityViewController.setValue(self.shareSubject ?? self.title, forKey: "subject")
|
|
670
800
|
activityViewController.popoverPresentationController?.barButtonItem = (sender as! UIBarButtonItem)
|
|
671
801
|
self.present(activityViewController, animated: true, completion: nil)
|
|
672
802
|
}
|
|
673
803
|
}
|
|
674
804
|
|
|
675
|
-
|
|
805
|
+
func closeView () {
|
|
676
806
|
var canDismiss = true
|
|
677
807
|
if let url = self.source?.url {
|
|
678
808
|
canDismiss = delegate?.webViewController?(self, canDismiss: url) ?? true
|
|
@@ -684,6 +814,21 @@ fileprivate extension WKWebViewController {
|
|
|
684
814
|
}
|
|
685
815
|
}
|
|
686
816
|
|
|
817
|
+
@objc func doneDidClick(sender: AnyObject) {
|
|
818
|
+
// check if closeModal is true, if true display alert before close
|
|
819
|
+
if self.closeModal {
|
|
820
|
+
let alert = UIAlertController(title: self.closeModalTitle, message: self.closeModalDescription, preferredStyle: UIAlertController.Style.alert)
|
|
821
|
+
alert.addAction(UIAlertAction(title: self.closeModalOk, style: UIAlertAction.Style.default, handler: { _ in
|
|
822
|
+
self.closeView()
|
|
823
|
+
}))
|
|
824
|
+
alert.addAction(UIAlertAction(title: self.closeModalCancel, style: UIAlertAction.Style.default, handler: nil))
|
|
825
|
+
self.present(alert, animated: true, completion: nil)
|
|
826
|
+
} else {
|
|
827
|
+
self.closeView()
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
}
|
|
831
|
+
|
|
687
832
|
@objc func customDidClick(sender: BlockBarButtonItem) {
|
|
688
833
|
sender.block?(self)
|
|
689
834
|
}
|
|
@@ -693,11 +838,59 @@ fileprivate extension WKWebViewController {
|
|
|
693
838
|
|
|
694
839
|
// MARK: - WKUIDelegate
|
|
695
840
|
extension WKWebViewController: WKUIDelegate {
|
|
696
|
-
|
|
841
|
+
public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
|
|
842
|
+
// Ensure UI updates are on the main thread
|
|
843
|
+
DispatchQueue.main.async {
|
|
844
|
+
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
|
|
845
|
+
self.present(alertController, animated: true, completion: nil)
|
|
846
|
+
}
|
|
847
|
+
completionHandler()
|
|
848
|
+
}
|
|
697
849
|
}
|
|
698
850
|
|
|
699
851
|
// MARK: - WKNavigationDelegate
|
|
700
852
|
extension WKWebViewController: WKNavigationDelegate {
|
|
853
|
+
internal func injectPreShowScript() {
|
|
854
|
+
if preShowSemaphore != nil {
|
|
855
|
+
return
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// TODO: implement interface
|
|
859
|
+
let script = """
|
|
860
|
+
async function preShowFunction() {
|
|
861
|
+
\(self.preShowScript ?? "")
|
|
862
|
+
};
|
|
863
|
+
preShowFunction().then(
|
|
864
|
+
() => window.webkit.messageHandlers.preShowScriptSuccess.postMessage({})
|
|
865
|
+
).catch(
|
|
866
|
+
err => {
|
|
867
|
+
console.error('Preshow error', err);
|
|
868
|
+
window.webkit.messageHandlers.preShowScriptError.postMessage(JSON.stringify(err, Object.getOwnPropertyNames(err)));
|
|
869
|
+
}
|
|
870
|
+
)
|
|
871
|
+
"""
|
|
872
|
+
print("[InAppBrowser - InjectPreShowScript] PreShowScript script: \(script)")
|
|
873
|
+
|
|
874
|
+
self.preShowSemaphore = DispatchSemaphore(value: 0)
|
|
875
|
+
self.executeScript(script: script) // this will run on the main thread
|
|
876
|
+
|
|
877
|
+
defer {
|
|
878
|
+
self.preShowSemaphore = nil
|
|
879
|
+
self.preShowError = nil
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if self.preShowSemaphore?.wait(timeout: .now() + 10) == .timedOut {
|
|
883
|
+
print("[InAppBrowser - InjectPreShowScript] PreShowScript running for over 10 seconds. The plugin will not wait any longer!")
|
|
884
|
+
return
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// "async function preShowFunction() {\n" +
|
|
888
|
+
// self.preShowScript + "\n" +
|
|
889
|
+
// "};\n" +
|
|
890
|
+
// "preShowFunction().then(() => window.PreShowScriptInterface.success()).catch(err => { console.error('Preshow error', err); window.PreShowScriptInterface.error(JSON.stringify(err, Object.getOwnPropertyNames(err))) })";
|
|
891
|
+
|
|
892
|
+
}
|
|
893
|
+
|
|
701
894
|
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
|
702
895
|
updateBarButtonItems()
|
|
703
896
|
self.progressView?.progress = 0
|
|
@@ -708,7 +901,21 @@ extension WKWebViewController: WKNavigationDelegate {
|
|
|
708
901
|
}
|
|
709
902
|
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
710
903
|
if !didpageInit && self.capBrowserPlugin?.isPresentAfterPageLoad == true {
|
|
711
|
-
|
|
904
|
+
// injectPreShowScript will block, don't execute on the main thread
|
|
905
|
+
if self.preShowScript != nil && !self.preShowScript!.isEmpty {
|
|
906
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
907
|
+
self.injectPreShowScript()
|
|
908
|
+
DispatchQueue.main.async { [weak self] in
|
|
909
|
+
self?.capBrowserPlugin?.presentView()
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
} else {
|
|
913
|
+
self.capBrowserPlugin?.presentView()
|
|
914
|
+
}
|
|
915
|
+
} else if self.preShowScript != nil && !self.preShowScript!.isEmpty && self.capBrowserPlugin?.isPresentAfterPageLoad == true {
|
|
916
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
917
|
+
self.injectPreShowScript()
|
|
918
|
+
}
|
|
712
919
|
}
|
|
713
920
|
didpageInit = true
|
|
714
921
|
updateBarButtonItems()
|
|
@@ -717,6 +924,8 @@ extension WKWebViewController: WKNavigationDelegate {
|
|
|
717
924
|
self.url = url
|
|
718
925
|
delegate?.webViewController?(self, didFinish: url)
|
|
719
926
|
}
|
|
927
|
+
self.injectJavaScriptInterface()
|
|
928
|
+
self.capBrowserPlugin?.notifyListeners("browserPageLoaded", data: [:])
|
|
720
929
|
}
|
|
721
930
|
|
|
722
931
|
public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
|
@@ -726,6 +935,7 @@ extension WKWebViewController: WKNavigationDelegate {
|
|
|
726
935
|
self.url = url
|
|
727
936
|
delegate?.webViewController?(self, didFail: url, withError: error)
|
|
728
937
|
}
|
|
938
|
+
self.capBrowserPlugin?.notifyListeners("pageLoadError", data: [:])
|
|
729
939
|
}
|
|
730
940
|
|
|
731
941
|
public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
|
@@ -735,46 +945,76 @@ extension WKWebViewController: WKNavigationDelegate {
|
|
|
735
945
|
self.url = url
|
|
736
946
|
delegate?.webViewController?(self, didFail: url, withError: error)
|
|
737
947
|
}
|
|
948
|
+
self.capBrowserPlugin?.notifyListeners("pageLoadError", data: [:])
|
|
738
949
|
}
|
|
739
950
|
|
|
740
951
|
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
|
|
741
|
-
if let
|
|
952
|
+
if let credentials = credentials,
|
|
953
|
+
challenge.protectionSpace.receivesCredentialSecurely,
|
|
954
|
+
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) {
|
|
955
|
+
let urlCredential = URLCredential(user: credentials.username, password: credentials.password, persistence: .none)
|
|
956
|
+
completionHandler(.useCredential, urlCredential)
|
|
957
|
+
} else if let bypassedSSLHosts = bypassedSSLHosts, bypassedSSLHosts.contains(challenge.protectionSpace.host) {
|
|
742
958
|
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
|
|
743
959
|
completionHandler(.useCredential, credential)
|
|
744
960
|
} else {
|
|
745
|
-
|
|
961
|
+
guard self.ignoreUntrustedSSLError else {
|
|
962
|
+
completionHandler(.performDefaultHandling, nil)
|
|
963
|
+
return
|
|
964
|
+
}
|
|
965
|
+
/* allows to open links with self-signed certificates
|
|
966
|
+
Follow Apple's guidelines https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication
|
|
967
|
+
*/
|
|
968
|
+
guard let serverTrust = challenge.protectionSpace.serverTrust else {
|
|
969
|
+
completionHandler(.useCredential, nil)
|
|
970
|
+
return
|
|
971
|
+
}
|
|
972
|
+
let credential = URLCredential(trust: serverTrust)
|
|
973
|
+
completionHandler(.useCredential, credential)
|
|
746
974
|
}
|
|
975
|
+
self.injectJavaScriptInterface()
|
|
747
976
|
}
|
|
748
977
|
|
|
749
978
|
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
|
750
979
|
var actionPolicy: WKNavigationActionPolicy = .allow
|
|
751
|
-
|
|
752
|
-
|
|
980
|
+
|
|
981
|
+
if self.preventDeeplink {
|
|
982
|
+
actionPolicy = .preventDeeplinkActionPolicy
|
|
753
983
|
}
|
|
984
|
+
|
|
754
985
|
guard let u = navigationAction.request.url else {
|
|
755
|
-
|
|
986
|
+
decisionHandler(actionPolicy)
|
|
987
|
+
return
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// Check if the URL is an App Store URL
|
|
991
|
+
if u.absoluteString.contains("apps.apple.com") {
|
|
992
|
+
UIApplication.shared.open(u, options: [:], completionHandler: nil)
|
|
993
|
+
// Cancel the navigation in the web view
|
|
994
|
+
decisionHandler(.cancel)
|
|
756
995
|
return
|
|
757
996
|
}
|
|
758
997
|
|
|
759
998
|
if !self.allowsFileURL && u.isFileURL {
|
|
760
999
|
print("Cannot handle file URLs")
|
|
1000
|
+
decisionHandler(.cancel)
|
|
761
1001
|
return
|
|
762
1002
|
}
|
|
763
1003
|
|
|
764
1004
|
if handleURLWithApp(u, targetFrame: navigationAction.targetFrame) {
|
|
765
1005
|
actionPolicy = .cancel
|
|
766
|
-
return
|
|
767
1006
|
}
|
|
768
1007
|
|
|
769
1008
|
if u.host == self.source?.url?.host, let cookies = availableCookies, !checkRequestCookies(navigationAction.request, cookies: cookies) {
|
|
770
1009
|
self.load(remote: u)
|
|
771
1010
|
actionPolicy = .cancel
|
|
772
|
-
return
|
|
773
1011
|
}
|
|
774
1012
|
|
|
775
1013
|
if let navigationType = NavigationType(rawValue: navigationAction.navigationType.rawValue), let result = delegate?.webViewController?(self, decidePolicy: u, navigationType: navigationType) {
|
|
776
1014
|
actionPolicy = result ? .allow : .cancel
|
|
777
1015
|
}
|
|
1016
|
+
self.injectJavaScriptInterface()
|
|
1017
|
+
decisionHandler(actionPolicy)
|
|
778
1018
|
}
|
|
779
1019
|
}
|
|
780
1020
|
|
|
@@ -782,3 +1022,7 @@ class BlockBarButtonItem: UIBarButtonItem {
|
|
|
782
1022
|
|
|
783
1023
|
var block: ((WKWebViewController) -> Void)?
|
|
784
1024
|
}
|
|
1025
|
+
|
|
1026
|
+
extension WKNavigationActionPolicy {
|
|
1027
|
+
static let preventDeeplinkActionPolicy = WKNavigationActionPolicy(rawValue: WKNavigationActionPolicy.allow.rawValue + 2)!
|
|
1028
|
+
}
|