@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.
@@ -1,5 +1,22 @@
1
1
  import Foundation
2
2
  import Capacitor
3
+ import WebKit
4
+
5
+ extension UIColor {
6
+
7
+ convenience init(hexString: String) {
8
+ let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
9
+ var int = UInt64()
10
+ Scanner(string: hex).scanHexInt64(&int)
11
+ let components = (
12
+ R: CGFloat((int >> 16) & 0xff) / 255,
13
+ G: CGFloat((int >> 08) & 0xff) / 255,
14
+ B: CGFloat((int >> 00) & 0xff) / 255
15
+ )
16
+ self.init(red: components.R, green: components.G, blue: components.B, alpha: 1)
17
+ }
18
+
19
+ }
3
20
 
4
21
  /**
5
22
  * Please read the Capacitor iOS Plugin Development Guide
@@ -26,14 +43,83 @@ public class InAppBrowserPlugin: CAPPlugin {
26
43
  #endif
27
44
  }
28
45
 
29
- func presentView() {
30
- self.bridge?.viewController?.present(self.navigationWebViewController!, animated: true, completion: {
46
+ func presentView(isAnimated: Bool = true) {
47
+ self.bridge?.viewController?.present(self.navigationWebViewController!, animated: isAnimated, completion: {
31
48
  self.currentPluginCall?.resolve()
32
49
  })
33
50
  }
34
51
 
35
- func clearCookies() {
36
- HTTPCookieStorage.shared.cookies?.forEach(HTTPCookieStorage.shared.deleteCookie)
52
+ @objc func clearAllCookies(_ call: CAPPluginCall) {
53
+ DispatchQueue.main.async {
54
+ let dataStore = WKWebsiteDataStore.default()
55
+ let dataTypes = Set([WKWebsiteDataTypeCookies])
56
+
57
+ dataStore.removeData(ofTypes: dataTypes,
58
+ modifiedSince: Date(timeIntervalSince1970: 0)) {
59
+ call.resolve()
60
+ }
61
+ }
62
+ }
63
+
64
+ @objc func clearCache(_ call: CAPPluginCall) {
65
+ DispatchQueue.main.async {
66
+ let dataStore = WKWebsiteDataStore.default()
67
+ let dataTypes = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
68
+
69
+ dataStore.removeData(ofTypes: dataTypes,
70
+ modifiedSince: Date(timeIntervalSince1970: 0)) {
71
+ call.resolve()
72
+ }
73
+ }
74
+ }
75
+
76
+ @objc func clearCookies(_ call: CAPPluginCall) {
77
+ guard let url = call.getString("url"),
78
+ let host = URL(string: url)?.host else {
79
+ call.reject("Invalid URL")
80
+ return
81
+ }
82
+
83
+ DispatchQueue.main.async {
84
+ WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
85
+ for cookie in cookies {
86
+
87
+ if cookie.domain == host || cookie.domain.hasSuffix(".\(host)") || host.hasSuffix(cookie.domain) {
88
+ let semaphore = DispatchSemaphore(value: 1)
89
+ WKWebsiteDataStore.default().httpCookieStore.delete(cookie) {
90
+ semaphore.signal()
91
+ }
92
+ semaphore.wait()
93
+ }
94
+ }
95
+
96
+ call.resolve()
97
+ }
98
+ }
99
+ }
100
+
101
+ @objc func getCookies(_ call: CAPPluginCall) {
102
+ let urlString = call.getString("url") ?? ""
103
+ let includeHttpOnly = call.getBool("includeHttpOnly") ?? true
104
+
105
+ guard let url = URL(string: urlString), let host = url.host else {
106
+ call.reject("Invalid URL")
107
+ return
108
+ }
109
+
110
+ DispatchQueue.main.async {
111
+ WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
112
+ var cookieDict = [String: String]()
113
+ for cookie in cookies {
114
+
115
+ if (includeHttpOnly || !cookie.isHTTPOnly) && (cookie.domain == host || cookie.domain.hasSuffix(".\(host)") || host.hasSuffix(cookie.domain)) {
116
+ cookieDict[cookie.name] = cookie.value
117
+ }
118
+ }
119
+ call.resolve(cookieDict)
120
+ }
121
+ }
122
+
37
123
  }
38
124
 
39
125
  @objc func openWebView(_ call: CAPPluginCall) {
@@ -52,7 +138,48 @@ public class InAppBrowserPlugin: CAPPlugin {
52
138
  return
53
139
  }
54
140
 
141
+ var buttonNearDoneIcon: UIImage?
142
+ if let buttonNearDoneSettings = call.getObject("buttonNearDone") {
143
+ guard let iosSettingsRaw = buttonNearDoneSettings["ios"] else {
144
+ call.reject("IOS settings not found")
145
+ return
146
+ }
147
+ if !(iosSettingsRaw is JSObject) {
148
+ call.reject("IOS settings are not an object")
149
+ return
150
+ }
151
+ let iosSettings = iosSettingsRaw as! JSObject
152
+
153
+ guard let iconType = iosSettings["iconType"] as? String else {
154
+ call.reject("buttonNearDone.iconType is empty")
155
+ return
156
+ }
157
+ if iconType != "sf-symbol" && iconType != "asset" {
158
+ call.reject("IconType is neither 'sf-symbol' nor 'asset'")
159
+ return
160
+ }
161
+ guard let icon = iosSettings["icon"] as? String else {
162
+ call.reject("buttonNearDone.icon is empty")
163
+ return
164
+ }
165
+
166
+ if iconType == "sf-symbol" {
167
+ buttonNearDoneIcon = UIImage(systemName: icon)
168
+ } else {
169
+ // UIImage(resource: ImageResource(name: "public/monkey.svg", bundle: Bundle.main))
170
+ buttonNearDoneIcon = UIImage(named: icon, in: Bundle.main, with: nil)
171
+ }
172
+ }
173
+
55
174
  let headers = call.getObject("headers", [:]).mapValues { String(describing: $0 as Any) }
175
+ let closeModal = call.getBool("closeModal", false)
176
+ let closeModalTitle = call.getString("closeModalTitle", "Close")
177
+ let closeModalDescription = call.getString("closeModalDescription", "Are you sure you want to close this window?")
178
+ let closeModalOk = call.getString("closeModalOk", "OK")
179
+ let closeModalCancel = call.getString("closeModalCancel", "Cancel")
180
+ let isInspectable = call.getBool("isInspectable", false)
181
+ let preventDeeplink = call.getBool("preventDeeplink", false)
182
+ let isAnimated = call.getBool("isAnimated", true)
56
183
 
57
184
  var disclaimerContent = call.getObject("shareDisclaimer")
58
185
  let toolbarType = call.getString("toolbarType", "")
@@ -60,39 +187,69 @@ public class InAppBrowserPlugin: CAPPlugin {
60
187
  if toolbarType != "activity" {
61
188
  disclaimerContent = nil
62
189
  }
190
+ let ignoreUntrustedSSLError = call.getBool("ignoreUntrustedSSLError", false)
63
191
 
64
192
  self.isPresentAfterPageLoad = call.getBool("isPresentAfterPageLoad", false)
193
+ let showReloadButton = call.getBool("showReloadButton", false)
194
+
195
+ let credentials = self.readCredentials(call)
65
196
 
66
197
  DispatchQueue.main.async {
67
198
  let url = URL(string: urlString)
68
199
 
69
200
  if self.isPresentAfterPageLoad {
70
- self.webViewController = WKWebViewController.init(url: url!, headers: headers)
201
+ self.webViewController = WKWebViewController.init(url: url!, headers: headers, isInspectable: isInspectable, credentials: credentials, preventDeeplink: preventDeeplink)
71
202
  } else {
72
203
  self.webViewController = WKWebViewController.init()
73
204
  self.webViewController?.setHeaders(headers: headers)
205
+ self.webViewController?.setCredentials(credentials: credentials)
206
+ self.webViewController?.setPreventDeeplink(preventDeeplink: preventDeeplink)
74
207
  }
75
208
 
76
209
  self.webViewController?.source = .remote(url!)
77
- self.webViewController?.leftNavigaionBarItemTypes = self.getToolbarItems(toolbarType: toolbarType)
210
+ self.webViewController?.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType) + [.reload]
211
+ self.webViewController?.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType)
78
212
  self.webViewController?.toolbarItemTypes = []
79
213
  self.webViewController?.doneBarButtonItemPosition = .right
214
+
215
+ self.webViewController?.buttonNearDoneIcon = buttonNearDoneIcon
216
+
217
+ if call.getBool("showArrow", false) {
218
+ self.webViewController?.stopBarButtonItemImage = UIImage(named: "Forward@3x", in: Bundle(for: InAppBrowserPlugin.self), compatibleWith: nil)
219
+ }
220
+
80
221
  self.webViewController?.capBrowserPlugin = self
81
222
  self.webViewController?.title = call.getString("title", "New Window")
82
223
  self.webViewController?.shareSubject = call.getString("shareSubject")
83
224
  self.webViewController?.shareDisclaimer = disclaimerContent
225
+ self.webViewController?.preShowScript = call.getString("preShowScript")
226
+ self.webViewController?.websiteTitleInNavigationBar = call.getBool("visibleTitle", true)
227
+ if closeModal {
228
+ self.webViewController?.closeModal = true
229
+ self.webViewController?.closeModalTitle = closeModalTitle
230
+ self.webViewController?.closeModalDescription = closeModalDescription
231
+ self.webViewController?.closeModalOk = closeModalOk
232
+ self.webViewController?.closeModalCancel = closeModalCancel
233
+ }
234
+ self.webViewController?.ignoreUntrustedSSLError = ignoreUntrustedSSLError
84
235
  self.navigationWebViewController = UINavigationController.init(rootViewController: self.webViewController!)
85
236
  self.navigationWebViewController?.navigationBar.isTranslucent = false
86
237
  self.navigationWebViewController?.toolbar.isTranslucent = false
87
238
  self.navigationWebViewController?.navigationBar.backgroundColor = backgroundColor
88
239
  self.navigationWebViewController?.toolbar.backgroundColor = backgroundColor
240
+ self.navigationWebViewController?.toolbar.tintColor = backgroundColor == UIColor.black ? UIColor.white : UIColor.black
89
241
  self.navigationWebViewController?.modalPresentationStyle = .fullScreen
90
242
  if toolbarType == "blank" {
91
243
  self.navigationWebViewController?.navigationBar.isHidden = true
92
244
  }
245
+ if showReloadButton {
246
+ let toolbarItems = self.getToolbarItems(toolbarType: toolbarType)
247
+ self.webViewController?.leftNavigationBarItemTypes = toolbarItems + [.reload]
248
+ }
93
249
  if !self.isPresentAfterPageLoad {
94
- self.presentView()
250
+ self.presentView(isAnimated: isAnimated)
95
251
  }
252
+ call.resolve()
96
253
  }
97
254
  }
98
255
 
@@ -107,20 +264,76 @@ public class InAppBrowserPlugin: CAPPlugin {
107
264
  return result
108
265
  }
109
266
 
267
+ @objc func reload(_ call: CAPPluginCall) {
268
+ self.webViewController?.reload()
269
+ call.resolve()
270
+ }
271
+
110
272
  @objc func setUrl(_ call: CAPPluginCall) {
111
- guard let url = call.getString("url") else {
273
+ guard let urlString = call.getString("url") else {
112
274
  call.reject("Cannot get new url to set")
113
275
  return
114
276
  }
115
- self.webViewController?.load(remote: URL(string: url)!)
277
+
278
+ guard let url = URL(string: urlString) else {
279
+ call.reject("Invalid URL")
280
+ return
281
+ }
282
+
283
+ self.webViewController?.load(remote: url)
284
+ call.resolve()
285
+ }
286
+
287
+ @objc func executeScript(_ call: CAPPluginCall) {
288
+ guard let script = call.getString("code") else {
289
+ call.reject("Cannot get script to execute")
290
+ return
291
+ }
292
+ DispatchQueue.main.async {
293
+ self.webViewController?.executeScript(script: script)
294
+ call.resolve()
295
+ }
296
+ }
297
+
298
+ @objc func postMessage(_ call: CAPPluginCall) {
299
+ let eventData = call.getObject("detail", [:])
300
+ // Check if eventData is empty
301
+ if eventData.isEmpty {
302
+ call.reject("Event data must not be empty")
303
+ return
304
+ }
305
+ print("Event data: \(eventData)")
306
+
307
+ DispatchQueue.main.async {
308
+ self.webViewController?.postMessageToJS(message: eventData)
309
+ }
116
310
  call.resolve()
117
311
  }
118
312
 
313
+ func isHexColorCode(_ input: String) -> Bool {
314
+ let hexColorRegex = "^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$"
315
+
316
+ do {
317
+ let regex = try NSRegularExpression(pattern: hexColorRegex)
318
+ let range = NSRange(location: 0, length: input.utf16.count)
319
+ if let _ = regex.firstMatch(in: input, options: [], range: range) {
320
+ return true
321
+ }
322
+ } catch {
323
+ print("Error creating regular expression: \(error)")
324
+ }
325
+
326
+ return false
327
+ }
328
+
119
329
  @objc func open(_ call: CAPPluginCall) {
120
330
  if !self.isSetupDone {
121
331
  self.setup()
122
332
  }
123
333
 
334
+ let isInspectable = call.getBool("isInspectable", false)
335
+ let preventDeeplink = call.getBool("preventDeeplink", false)
336
+
124
337
  self.currentPluginCall = call
125
338
 
126
339
  guard let urlString = call.getString("url") else {
@@ -137,18 +350,22 @@ public class InAppBrowserPlugin: CAPPlugin {
137
350
 
138
351
  self.isPresentAfterPageLoad = call.getBool("isPresentAfterPageLoad", false)
139
352
 
353
+ let credentials = self.readCredentials(call)
354
+
140
355
  DispatchQueue.main.async {
141
356
  let url = URL(string: urlString)
142
357
 
143
358
  if self.isPresentAfterPageLoad {
144
- self.webViewController = WKWebViewController.init(url: url!, headers: headers)
359
+ self.webViewController = WKWebViewController.init(url: url!, headers: headers, isInspectable: isInspectable, credentials: credentials, preventDeeplink: preventDeeplink)
145
360
  } else {
146
361
  self.webViewController = WKWebViewController.init()
147
362
  self.webViewController?.setHeaders(headers: headers)
363
+ self.webViewController?.setCredentials(credentials: credentials)
364
+ self.webViewController?.setPreventDeeplink(preventDeeplink: preventDeeplink)
148
365
  }
149
366
 
150
367
  self.webViewController?.source = .remote(url!)
151
- self.webViewController?.leftNavigaionBarItemTypes = [.reload]
368
+ self.webViewController?.leftNavigationBarItemTypes = [.reload]
152
369
  self.webViewController?.toolbarItemTypes = [.back, .forward, .activity]
153
370
  self.webViewController?.capBrowserPlugin = self
154
371
  self.webViewController?.hasDynamicTitle = true
@@ -156,17 +373,26 @@ public class InAppBrowserPlugin: CAPPlugin {
156
373
  self.navigationWebViewController?.navigationBar.isTranslucent = false
157
374
  self.navigationWebViewController?.toolbar.isTranslucent = false
158
375
  self.navigationWebViewController?.navigationBar.backgroundColor = .white
159
- self.navigationWebViewController?.toolbar.backgroundColor = .white
376
+ let inputString: String = call.getString("toolbarColor", "#ffffff")
377
+ var color: UIColor = UIColor(hexString: "#ffffff")
378
+ if self.isHexColorCode(inputString) {
379
+ color = UIColor(hexString: inputString)
380
+ } else {
381
+ print("\(inputString) is not a valid hex color code.")
382
+ }
383
+ self.navigationWebViewController?.toolbar.backgroundColor = color
160
384
  self.navigationWebViewController?.modalPresentationStyle = .fullScreen
161
385
  if !self.isPresentAfterPageLoad {
162
386
  self.presentView()
163
387
  }
388
+ call.resolve()
164
389
  }
165
390
  }
166
391
 
167
392
  @objc func close(_ call: CAPPluginCall) {
168
393
  DispatchQueue.main.async {
169
394
  self.navigationWebViewController?.dismiss(animated: true, completion: nil)
395
+ self.notifyListeners("closeEvent", data: ["url": self.webViewController?.url?.absoluteString ?? ""])
170
396
  call.resolve()
171
397
  }
172
398
  }
@@ -200,4 +426,13 @@ public class InAppBrowserPlugin: CAPPlugin {
200
426
  @objc func appWillResignActive(_ notification: NSNotification) {
201
427
  self.showPrivacyScreen()
202
428
  }
429
+
430
+ private func readCredentials(_ call: CAPPluginCall) -> WKWebViewCredentials? {
431
+ var credentials: WKWebViewCredentials?
432
+ let credentialsDict = call.getObject("credentials", [:]).mapValues { String(describing: $0 as Any) }
433
+ if !credentialsDict.isEmpty, let username = credentialsDict["username"], let password = credentialsDict["password"] {
434
+ credentials = WKWebViewCredentials(username: username, password: password)
435
+ }
436
+ return credentials
437
+ }
203
438
  }