@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.
@@ -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,72 @@ 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
+ self.webViewController?.executeScript(script: script)
116
293
  call.resolve()
117
294
  }
118
295
 
296
+ @objc func postMessage(_ call: CAPPluginCall) {
297
+ let eventData = call.getObject("detail", [:])
298
+ // Check if eventData is empty
299
+ if eventData.isEmpty {
300
+ call.reject("Event data must not be empty")
301
+ return
302
+ }
303
+ print("Event data: \(eventData)")
304
+
305
+ self.webViewController?.postMessageToJS(message: eventData)
306
+ call.resolve()
307
+ }
308
+
309
+ func isHexColorCode(_ input: String) -> Bool {
310
+ let hexColorRegex = "^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$"
311
+
312
+ do {
313
+ let regex = try NSRegularExpression(pattern: hexColorRegex)
314
+ let range = NSRange(location: 0, length: input.utf16.count)
315
+ if let _ = regex.firstMatch(in: input, options: [], range: range) {
316
+ return true
317
+ }
318
+ } catch {
319
+ print("Error creating regular expression: \(error)")
320
+ }
321
+
322
+ return false
323
+ }
324
+
119
325
  @objc func open(_ call: CAPPluginCall) {
120
326
  if !self.isSetupDone {
121
327
  self.setup()
122
328
  }
123
329
 
330
+ let isInspectable = call.getBool("isInspectable", false)
331
+ let preventDeeplink = call.getBool("preventDeeplink", false)
332
+
124
333
  self.currentPluginCall = call
125
334
 
126
335
  guard let urlString = call.getString("url") else {
@@ -137,18 +346,22 @@ public class InAppBrowserPlugin: CAPPlugin {
137
346
 
138
347
  self.isPresentAfterPageLoad = call.getBool("isPresentAfterPageLoad", false)
139
348
 
349
+ let credentials = self.readCredentials(call)
350
+
140
351
  DispatchQueue.main.async {
141
352
  let url = URL(string: urlString)
142
353
 
143
354
  if self.isPresentAfterPageLoad {
144
- self.webViewController = WKWebViewController.init(url: url!, headers: headers)
355
+ self.webViewController = WKWebViewController.init(url: url!, headers: headers, isInspectable: isInspectable, credentials: credentials, preventDeeplink: preventDeeplink)
145
356
  } else {
146
357
  self.webViewController = WKWebViewController.init()
147
358
  self.webViewController?.setHeaders(headers: headers)
359
+ self.webViewController?.setCredentials(credentials: credentials)
360
+ self.webViewController?.setPreventDeeplink(preventDeeplink: preventDeeplink)
148
361
  }
149
362
 
150
363
  self.webViewController?.source = .remote(url!)
151
- self.webViewController?.leftNavigaionBarItemTypes = [.reload]
364
+ self.webViewController?.leftNavigationBarItemTypes = [.reload]
152
365
  self.webViewController?.toolbarItemTypes = [.back, .forward, .activity]
153
366
  self.webViewController?.capBrowserPlugin = self
154
367
  self.webViewController?.hasDynamicTitle = true
@@ -156,17 +369,26 @@ public class InAppBrowserPlugin: CAPPlugin {
156
369
  self.navigationWebViewController?.navigationBar.isTranslucent = false
157
370
  self.navigationWebViewController?.toolbar.isTranslucent = false
158
371
  self.navigationWebViewController?.navigationBar.backgroundColor = .white
159
- self.navigationWebViewController?.toolbar.backgroundColor = .white
372
+ let inputString: String = call.getString("toolbarColor", "#ffffff")
373
+ var color: UIColor = UIColor(hexString: "#ffffff")
374
+ if self.isHexColorCode(inputString) {
375
+ color = UIColor(hexString: inputString)
376
+ } else {
377
+ print("\(inputString) is not a valid hex color code.")
378
+ }
379
+ self.navigationWebViewController?.toolbar.backgroundColor = color
160
380
  self.navigationWebViewController?.modalPresentationStyle = .fullScreen
161
381
  if !self.isPresentAfterPageLoad {
162
382
  self.presentView()
163
383
  }
384
+ call.resolve()
164
385
  }
165
386
  }
166
387
 
167
388
  @objc func close(_ call: CAPPluginCall) {
168
389
  DispatchQueue.main.async {
169
390
  self.navigationWebViewController?.dismiss(animated: true, completion: nil)
391
+ self.notifyListeners("closeEvent", data: ["url": self.webViewController?.url?.absoluteString ?? ""])
170
392
  call.resolve()
171
393
  }
172
394
  }
@@ -200,4 +422,13 @@ public class InAppBrowserPlugin: CAPPlugin {
200
422
  @objc func appWillResignActive(_ notification: NSNotification) {
201
423
  self.showPrivacyScreen()
202
424
  }
425
+
426
+ private func readCredentials(_ call: CAPPluginCall) -> WKWebViewCredentials? {
427
+ var credentials: WKWebViewCredentials?
428
+ let credentialsDict = call.getObject("credentials", [:]).mapValues { String(describing: $0 as Any) }
429
+ if !credentialsDict.isEmpty, let username = credentialsDict["username"], let password = credentialsDict["password"] {
430
+ credentials = WKWebViewCredentials(username: username, password: password)
431
+ }
432
+ return credentials
433
+ }
203
434
  }