@capacitor-plus/ios 8.0.0-beta.0

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.
Files changed (106) hide show
  1. package/Capacitor/Capacitor/AppUUID.swift +51 -0
  2. package/Capacitor/Capacitor/Array+Capacitor.swift +31 -0
  3. package/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift +32 -0
  4. package/Capacitor/Capacitor/CAPBridge.swift +25 -0
  5. package/Capacitor/Capacitor/CAPBridgeDelegate.swift +6 -0
  6. package/Capacitor/Capacitor/CAPBridgeProtocol.swift +148 -0
  7. package/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h +6 -0
  8. package/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m +5 -0
  9. package/Capacitor/Capacitor/CAPBridgeViewController.swift +384 -0
  10. package/Capacitor/Capacitor/CAPBridgedJSTypes.h +18 -0
  11. package/Capacitor/Capacitor/CAPBridgedJSTypes.m +43 -0
  12. package/Capacitor/Capacitor/CAPBridgedPlugin+getMethod.swift +13 -0
  13. package/Capacitor/Capacitor/CAPBridgedPlugin.h +41 -0
  14. package/Capacitor/Capacitor/CAPFile.swift +14 -0
  15. package/Capacitor/Capacitor/CAPInstanceConfiguration.h +38 -0
  16. package/Capacitor/Capacitor/CAPInstanceConfiguration.m +93 -0
  17. package/Capacitor/Capacitor/CAPInstanceConfiguration.swift +78 -0
  18. package/Capacitor/Capacitor/CAPInstanceDescriptor.h +167 -0
  19. package/Capacitor/Capacitor/CAPInstanceDescriptor.m +56 -0
  20. package/Capacitor/Capacitor/CAPInstanceDescriptor.swift +198 -0
  21. package/Capacitor/Capacitor/CAPInstancePlugin.swift +10 -0
  22. package/Capacitor/Capacitor/CAPLog.swift +11 -0
  23. package/Capacitor/Capacitor/CAPNotifications.swift +69 -0
  24. package/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift +20 -0
  25. package/Capacitor/Capacitor/CAPPlugin.h +60 -0
  26. package/Capacitor/Capacitor/CAPPlugin.m +180 -0
  27. package/Capacitor/Capacitor/CAPPluginCall.h +25 -0
  28. package/Capacitor/Capacitor/CAPPluginCall.m +36 -0
  29. package/Capacitor/Capacitor/CAPPluginCall.swift +97 -0
  30. package/Capacitor/Capacitor/CAPPluginMethod.h +36 -0
  31. package/Capacitor/Capacitor/CAPPluginMethod.m +44 -0
  32. package/Capacitor/Capacitor/CAPPluginMethod.swift +17 -0
  33. package/Capacitor/Capacitor/Capacitor.h +15 -0
  34. package/Capacitor/Capacitor/Capacitor.modulemap +8 -0
  35. package/Capacitor/Capacitor/CapacitorBridge.swift +768 -0
  36. package/Capacitor/Capacitor/CapacitorExtension.swift +24 -0
  37. package/Capacitor/Capacitor/Codable/JSValueDecoder.swift +479 -0
  38. package/Capacitor/Capacitor/Codable/JSValueEncoder.swift +671 -0
  39. package/Capacitor/Capacitor/Data+Capacitor.swift +22 -0
  40. package/Capacitor/Capacitor/DocLinks.swift +8 -0
  41. package/Capacitor/Capacitor/Info.plist +24 -0
  42. package/Capacitor/Capacitor/JS.swift +122 -0
  43. package/Capacitor/Capacitor/JSExport.swift +218 -0
  44. package/Capacitor/Capacitor/JSTypes.swift +254 -0
  45. package/Capacitor/Capacitor/KeyPath.swift +60 -0
  46. package/Capacitor/Capacitor/KeyValueStore.swift +303 -0
  47. package/Capacitor/Capacitor/NotificationHandlerProtocol.swift +6 -0
  48. package/Capacitor/Capacitor/NotificationRouter.swift +60 -0
  49. package/Capacitor/Capacitor/PluginCallResult.swift +106 -0
  50. package/Capacitor/Capacitor/PluginConfig.swift +56 -0
  51. package/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift +141 -0
  52. package/Capacitor/Capacitor/Plugins/CapacitorCookies.swift +57 -0
  53. package/Capacitor/Capacitor/Plugins/CapacitorHttp.swift +57 -0
  54. package/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift +225 -0
  55. package/Capacitor/Capacitor/Plugins/Console.swift +16 -0
  56. package/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift +236 -0
  57. package/Capacitor/Capacitor/Plugins/SystemBars.swift +133 -0
  58. package/Capacitor/Capacitor/Plugins/WebView.swift +44 -0
  59. package/Capacitor/Capacitor/PrivacyInfo.xcprivacy +14 -0
  60. package/Capacitor/Capacitor/Router.swift +29 -0
  61. package/Capacitor/Capacitor/TmpViewController.swift +8 -0
  62. package/Capacitor/Capacitor/UIColor.swift +55 -0
  63. package/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m +37 -0
  64. package/Capacitor/Capacitor/WKWebView+Capacitor.m +15 -0
  65. package/Capacitor/Capacitor/WKWebView+Capacitor.swift +80 -0
  66. package/Capacitor/Capacitor/WebViewAssetHandler.swift +550 -0
  67. package/Capacitor/Capacitor/WebViewDelegationHandler.swift +361 -0
  68. package/Capacitor/Capacitor/assets/native-bridge.js +1029 -0
  69. package/Capacitor.podspec +23 -0
  70. package/CapacitorCordova/CapacitorCordova/CapacitorCordova.h +25 -0
  71. package/CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap +6 -0
  72. package/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h +8 -0
  73. package/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.m +5 -0
  74. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h +28 -0
  75. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h +109 -0
  76. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailabilityDeprecated.h +21 -0
  77. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h +49 -0
  78. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h +39 -0
  79. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.m +149 -0
  80. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h +31 -0
  81. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.m +81 -0
  82. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h +52 -0
  83. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.m +116 -0
  84. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h +39 -0
  85. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.m +38 -0
  86. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h +76 -0
  87. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.m +136 -0
  88. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h +25 -0
  89. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.m +77 -0
  90. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h +82 -0
  91. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.m +216 -0
  92. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h +33 -0
  93. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h +27 -0
  94. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.m +74 -0
  95. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h +30 -0
  96. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.m +37 -0
  97. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h +34 -0
  98. package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m +55 -0
  99. package/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h +35 -0
  100. package/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.m +63 -0
  101. package/CapacitorCordova/CapacitorCordova/Info.plist +26 -0
  102. package/CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy +14 -0
  103. package/CapacitorCordova.podspec +26 -0
  104. package/LICENSE +21 -0
  105. package/package.json +33 -0
  106. package/scripts/pods_helpers.rb +12 -0
@@ -0,0 +1,303 @@
1
+ //
2
+ // KeyValueStore.swift
3
+ // Capacitor
4
+ //
5
+ // Created by Steven Sherry on 1/5/24.
6
+ // Copyright © 2024 Drifty Co. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ /// A generic KeyValueStore that allows storing and retrieving values associated with string keys.
12
+ /// The store supports both ephemeral (in-memory) storage and persistent (file-based) storage backends
13
+ /// by default, however it can also take anything that conforms to ``KeyValueStoreBackend`` as
14
+ /// a backend.
15
+ ///
16
+ /// This class provides methods to get, set and delete key-value pairs for any type of value, provided the
17
+ /// types conform to `Codable`. The default ``Backend/ephemeral`` and ``Backend/persistent(suiteName:)``
18
+ /// backends are thread-safe.
19
+ ///
20
+ /// ## Usage Examples
21
+ ///
22
+ /// ### Non-throwing API
23
+ /// ```swift
24
+ /// let store = KeyValueStore.standard
25
+ /// // Set
26
+ /// store["key"] = "value"
27
+ ///
28
+ /// // Get
29
+ /// if let value = store["key", as: String.self] {
30
+ /// // Do something with value
31
+ /// }
32
+ ///
33
+ /// // Delete
34
+ /// // The type here is a required argument because
35
+ /// // it is unable to be inferred
36
+ /// store["key", as: String.self] = nil
37
+ /// // or
38
+ /// store["key"] = nil as String?
39
+ /// ```
40
+ ///
41
+ ///
42
+ /// ### Throwing API
43
+ ///
44
+ /// ```swift
45
+ /// let store = KeyValueStore.standard
46
+ /// do {
47
+ /// // Set
48
+ /// try store.set("key", value: "value")
49
+ ///
50
+ /// // Get
51
+ /// if let value = try store.get("key", as: String.self) {
52
+ /// // Do something with value
53
+ /// }
54
+ ///
55
+ /// // Delete
56
+ /// try store.delete("key")
57
+ /// } catch {
58
+ /// print(error.localizedDescription)
59
+ /// }
60
+ /// ```
61
+ ///
62
+ /// ### Throwing vs Non-throwing
63
+ ///
64
+ /// Of the built-in backends, both ``Backend/ephemeral`` and ``Backend/persistent(suiteName:)`` will throw in the following cases:
65
+ /// * The data read from the file retrieved during ``get(_:as:)`` is unable to be decoded as the type provided.
66
+ /// * The value provided to ``set(_:value:)`` encounters an error during encoding.
67
+ /// * This is more likely to happen with types that have custom `Encodable` implementations
68
+ ///
69
+ /// ``Backend/persistent(suiteName:)`` will throw for the following additional cases:
70
+ /// * A file is unable to be read from disk during ``get(_:as:)``
71
+ /// * The existence of the file on disk is checked before attempting to read the file, so out of the
72
+ /// [possible file reading errors](https://developer.apple.com/documentation/foundation/1448136-nserror_codes#file-reading-errors),
73
+ /// the only likely candidate would be
74
+ /// [NSFileReadCorruptFileError](https://developer.apple.com/documentation/foundation/1448136-nserror_codes/nsfilereadcorruptfileerror).
75
+ /// In practice, this should never happen since writes happen atomically.
76
+ /// * The data from the value encoded in ``set(_:value:)`` is unable to be written to disk
77
+ /// * Of the [possible file writing errors](https://developer.apple.com/documentation/foundation/1448136-nserror_codes#file-writing-errors),
78
+ /// the only likely candidates are
79
+ /// [NSFileWriteInvalidFileNameError](https://developer.apple.com/documentation/foundation/1448136-nserror_codes/nsfilewriteinvalidfilenameerror)
80
+ /// if the key provided makes for an invalid file name and
81
+ /// [NSFileWriteOutOfSpaceError](https://developer.apple.com/documentation/foundation/1448136-nserror_codes/nsfilewriteoutofspaceerror)
82
+ /// if the user has no space left on disk
83
+ ///
84
+ /// The throwing API should be used in cases where detailed error information is needed for logging or diagnostics. The non-throwing API should be used
85
+ /// in cases where silent failure is preferred.
86
+ public class KeyValueStore {
87
+
88
+ /// The built-in storage backends
89
+ public enum Backend {
90
+ /// An in-memory backing store
91
+ case ephemeral
92
+ /// A persistent file-based backing store using the
93
+ /// `suiteName` as an identifier for the collection of files
94
+ case persistent(suiteName: String)
95
+ }
96
+
97
+ private let backend: any KeyValueStoreBackend
98
+
99
+ /// Creates an instance of ``KeyValueStore`` with a custom backend
100
+ /// - Parameter backend: The custom backend implementation
101
+ public init(backend: any KeyValueStoreBackend) {
102
+ self.backend = backend
103
+ }
104
+
105
+ /// Creates an instance of ``KeyValueStore`` with the provided built-in ``Backend``
106
+ /// - Parameter type: The type of ``Backend`` to use
107
+ public init(type: Backend) {
108
+ switch type {
109
+ case .ephemeral:
110
+ backend = InMemoryStore()
111
+ case .persistent(suiteName: let name):
112
+ backend = FileStore.with(name: name)
113
+ }
114
+ }
115
+
116
+ /// Creates an instance of ``KeyValueStore`` with ``Backend/persistent(suiteName:)``
117
+ /// - Parameter suiteName: The suite name to provide ``Backend/persistent(suiteName:)``
118
+ public convenience init(suiteName: String) {
119
+ self.init(type: .persistent(suiteName: suiteName))
120
+ }
121
+
122
+ /// Retrieves a value of the specified type and key
123
+ /// - Parameters:
124
+ /// - key: The unique identifier for the value
125
+ /// - type: The expected type of the value being retried
126
+ /// - Returns: A decoded value of the given type or `nil` if there is no such value
127
+ public func `get`<T>(_ key: String, as type: T.Type = T.self) throws -> T? where T: Decodable {
128
+ try backend.get(key, as: type)
129
+ }
130
+
131
+ /// Stores the value under the specified key
132
+ /// - Parameters:
133
+ /// - key: The unique identifier
134
+ /// - value: The value to be stored
135
+ public func `set`<T>(_ key: String, value: T) throws where T: Encodable {
136
+ try backend.set(key, value: value)
137
+ }
138
+
139
+ /// Deletes the value for the specified key
140
+ public func `delete`(_ key: String) throws {
141
+ try backend.delete(key)
142
+ }
143
+
144
+ /// Convenience for accessing and modifying values in the store without calling ``get(_:as:)``, ``set(_:value:)``, or ``delete(_:)``
145
+ /// - Parameters:
146
+ /// - key: The unique identifier for the value to access or modify
147
+ /// - type: The type the value is stored as
148
+ ///
149
+ /// This method is only really necessary when accessing a key and the type cannot be inferred from it's context.
150
+ /// ```swift
151
+ /// let store = KeyValueStore.standard
152
+ ///
153
+ /// // Get
154
+ /// let value = store["key", as: String.self]
155
+ ///
156
+ /// // If the type can be inferred then it may be omitted
157
+ /// let value: String? = store["key"]
158
+ /// let value = store["key"] as String?
159
+ /// let value = store["key"] ?? "default"
160
+ ///
161
+ /// // Delete
162
+ /// store["key", as: String.self] = nil
163
+ /// store["key"] = nil as String?
164
+ /// ```
165
+ public subscript<T> (_ key: String, as type: T.Type = T.self) -> T? where T: Codable {
166
+ get { try? self.get(key) }
167
+ set {
168
+ if let newValue {
169
+ try? self.set(key, value: newValue)
170
+ } else {
171
+ try? self.delete(key)
172
+ }
173
+ }
174
+ }
175
+
176
+ /// A shared persistent instance of ``KeyValueStore``
177
+ public static let standard = KeyValueStore(type: .persistent(suiteName: "standard"))
178
+ }
179
+
180
+ public protocol KeyValueStoreBackend {
181
+ func `get`<T>(_ key: String, as type: T.Type) throws -> T? where T: Decodable
182
+ func `set`<T>(_ key: String, value: T) throws where T: Encodable
183
+ func `delete`(_ key: String) throws
184
+ }
185
+
186
+ private class FileStore: KeyValueStoreBackend {
187
+ private let cache = ConcurrentDictionary<Data>()
188
+ private let decoder = JSONDecoder()
189
+ private let encoder = JSONEncoder()
190
+ private let baseUrl: URL
191
+
192
+ private init(baseUrl: URL) {
193
+ self.baseUrl = baseUrl
194
+ }
195
+
196
+ func get<T>(_ key: String, as type: T.Type) throws -> T? where T: Decodable {
197
+ if let cached = cache[key],
198
+ let value = try? decoder.decode(type, from: cached) {
199
+ return value
200
+ }
201
+
202
+ let fileCacheLocation = baseUrl.appendingPathComponent(key)
203
+ guard FileManager.default.fileExists(atPath: fileCacheLocation.path) else { return nil }
204
+
205
+ let data = try Data(contentsOf: fileCacheLocation)
206
+ let decoded = try decoder.decode(type, from: data)
207
+
208
+ cache[key] = data
209
+ return decoded
210
+ }
211
+
212
+ func set<T>(_ key: String, value: T) throws where T: Encodable {
213
+ let encoded = try encoder.encode(value)
214
+ try encoded.write(to: url(for: key), options: .atomic)
215
+ cache[key] = encoded
216
+ }
217
+
218
+ func delete(_ key: String) throws {
219
+ cache[key] = nil
220
+ try FileManager.default.removeItem(at: url(for: key))
221
+ }
222
+
223
+ private func url(for key: String) -> URL {
224
+ baseUrl.appendingPathComponent(key)
225
+ }
226
+
227
+ private static let instances = ConcurrentDictionary<FileStore>()
228
+
229
+ // This ensures we essentially have singletons for accessing file based resources
230
+ // so we don't have a scenario where two separate instances may be writing to
231
+ // the same files.
232
+ static func with(name: String) -> FileStore {
233
+ if let existing = instances[name] { return existing }
234
+ guard let library = try? FileManager
235
+ .default
236
+ .url(
237
+ for: .libraryDirectory,
238
+ in: .userDomainMask,
239
+ appropriateFor: nil,
240
+ create: true
241
+ )
242
+ else { fatalError("⚡️ ❌ Library URL unable to be accessed or created by the current application. This is an impossible state.") }
243
+
244
+ let url = library.appendingPathComponent("kvstore").appendingPathComponent(name)
245
+
246
+ // Create the folder if it doesn't exist. This should never throw for the current base directory, so we ignore the exception.
247
+ try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
248
+
249
+ let new = FileStore(baseUrl: url)
250
+ instances[name] = new
251
+ return new
252
+ }
253
+ }
254
+
255
+ private class InMemoryStore: KeyValueStoreBackend {
256
+ private let storage = ConcurrentDictionary<Data>()
257
+ private let decoder = JSONDecoder()
258
+ private let encoder = JSONEncoder()
259
+
260
+ func get<T>(_ key: String, as type: T.Type) throws -> T? where T: Decodable {
261
+ guard let data = storage[key] else { return nil }
262
+ return try decoder.decode(type, from: data)
263
+ }
264
+
265
+ func set<T>(_ key: String, value: T) throws where T: Encodable {
266
+ let data = try encoder.encode(value)
267
+ storage[key] = data
268
+ }
269
+
270
+ func delete(_ key: String) {
271
+ storage[key] = nil
272
+ }
273
+ }
274
+
275
+ class ConcurrentDictionary<Value> {
276
+ typealias StorageType = [String: Value]
277
+ private var storage: StorageType
278
+ private let lock = NSLock()
279
+
280
+ init(_ initial: StorageType = [:]) {
281
+ storage = initial
282
+ }
283
+
284
+ subscript (_ key: String) -> Value? {
285
+ get {
286
+ lock.withLock {
287
+ storage[key]
288
+ }
289
+ }
290
+
291
+ set {
292
+ lock.withLock {
293
+ storage[key] = newValue
294
+ }
295
+ }
296
+ }
297
+
298
+ func withLock<T>(_ body: (_ storage: inout StorageType) -> T) -> T {
299
+ lock.withLock {
300
+ body(&storage)
301
+ }
302
+ }
303
+ }
@@ -0,0 +1,6 @@
1
+ import Foundation
2
+
3
+ @objc(CAPNotificationHandlerProtocol) public protocol NotificationHandlerProtocol {
4
+ func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions
5
+ func didReceive(response: UNNotificationResponse)
6
+ }
@@ -0,0 +1,60 @@
1
+ import Foundation
2
+
3
+ @objc(CAPNotificationRouter) public class NotificationRouter: NSObject, UNUserNotificationCenterDelegate {
4
+ var handleApplicationNotifications: Bool {
5
+ get {
6
+ return UNUserNotificationCenter.current().delegate === self
7
+ }
8
+ set {
9
+ let center = UNUserNotificationCenter.current()
10
+
11
+ if newValue {
12
+ center.delegate = self
13
+ } else if center.delegate === self {
14
+ center.delegate = nil
15
+ }
16
+ }
17
+ }
18
+
19
+ public weak var pushNotificationHandler: NotificationHandlerProtocol? {
20
+ didSet {
21
+ if pushNotificationHandler != nil, oldValue != nil {
22
+ CAPLog.print("Push notification handler overriding previous instance: \(String(describing: type(of: oldValue)))")
23
+ }
24
+ }
25
+ }
26
+
27
+ public weak var localNotificationHandler: NotificationHandlerProtocol? {
28
+ didSet {
29
+ if localNotificationHandler != nil, oldValue != nil {
30
+ CAPLog.print("Local notification handler overriding previous instance: \(String(describing: type(of: oldValue)))")
31
+ }
32
+ }
33
+ }
34
+
35
+ public func userNotificationCenter(_ center: UNUserNotificationCenter,
36
+ willPresent notification: UNNotification,
37
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
38
+ let presentationOptions: UNNotificationPresentationOptions?
39
+
40
+ if notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self) == true {
41
+ presentationOptions = pushNotificationHandler?.willPresent(notification: notification)
42
+ } else {
43
+ presentationOptions = localNotificationHandler?.willPresent(notification: notification)
44
+ }
45
+
46
+ completionHandler(presentationOptions ?? [])
47
+ }
48
+
49
+ public func userNotificationCenter(_ center: UNUserNotificationCenter,
50
+ didReceive response: UNNotificationResponse,
51
+ withCompletionHandler completionHandler: @escaping () -> Void) {
52
+ if response.notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self) == true {
53
+ pushNotificationHandler?.didReceive(response: response)
54
+ } else {
55
+ localNotificationHandler?.didReceive(response: response)
56
+ }
57
+
58
+ completionHandler()
59
+ }
60
+ }
@@ -0,0 +1,106 @@
1
+ import Foundation
2
+
3
+ public typealias PluginCallResultData = [String: Any]
4
+
5
+ public enum PluginCallResult {
6
+ case dictionary(PluginCallResultData)
7
+
8
+ enum SerializationError: Error {
9
+ case invalidObject
10
+ }
11
+
12
+ func jsonRepresentation(includingFields: PluginCallResultData? = nil) throws -> String? {
13
+ switch self {
14
+ case .dictionary(var dictionary):
15
+ if let fields = includingFields {
16
+ dictionary.merge(fields) { (current, _) in current }
17
+ }
18
+ dictionary = prepare(dictionary: dictionary)
19
+ guard JSONSerialization.isValidJSONObject(dictionary) else {
20
+ throw SerializationError.invalidObject
21
+ }
22
+ let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
23
+ return String(data: data, encoding: .utf8)
24
+ }
25
+ }
26
+
27
+ private static let formatter = ISO8601DateFormatter()
28
+
29
+ private func prepare(dictionary: PluginCallResultData) -> PluginCallResultData {
30
+ return dictionary.mapValues { (value) -> Any in
31
+ if let date = value as? Date {
32
+ return PluginCallResult.formatter.string(from: date)
33
+ } else if let aDictionary = value as? PluginCallResultData {
34
+ return prepare(dictionary: aDictionary)
35
+ } else if let anArray = value as? [Any] {
36
+ return prepare(array: anArray)
37
+ }
38
+ return value
39
+ }
40
+ }
41
+
42
+ private func prepare(array: [Any]) -> [Any] {
43
+ return array.map { (value) -> Any in
44
+ if let date = value as? Date {
45
+ return PluginCallResult.formatter.string(from: date)
46
+ } else if let aDictionary = value as? PluginCallResultData {
47
+ return prepare(dictionary: aDictionary)
48
+ } else if let anArray = value as? [Any] {
49
+ return prepare(array: anArray)
50
+ }
51
+ return value
52
+ }
53
+ }
54
+ }
55
+
56
+ @objc public class CAPPluginCallResult: NSObject {
57
+ public let resultData: PluginCallResult?
58
+
59
+ @objc public var data: PluginCallResultData? {
60
+ guard let result = resultData else {
61
+ return nil
62
+ }
63
+ switch result {
64
+ case .dictionary(let data):
65
+ return data
66
+ }
67
+ }
68
+
69
+ @objc(init:)
70
+ public init(_ data: PluginCallResultData?) {
71
+ if let data = data {
72
+ resultData = .dictionary(data)
73
+ } else {
74
+ resultData = nil
75
+ }
76
+ }
77
+ }
78
+
79
+ @objc public class CAPPluginCallError: NSObject {
80
+ @objc public let message: String
81
+ @objc public let code: String?
82
+ @objc public let error: Error?
83
+ public let resultData: PluginCallResult?
84
+
85
+ @objc public var data: PluginCallResultData? {
86
+ guard let result = resultData else {
87
+ return nil
88
+ }
89
+ switch result {
90
+ case .dictionary(let data):
91
+ return data
92
+ }
93
+ }
94
+
95
+ @objc(init:code:error:data:)
96
+ public init(message: String, code: String?, error: Error?, data: PluginCallResultData?) {
97
+ self.message = message
98
+ self.code = code
99
+ self.error = error
100
+ if let data = data {
101
+ resultData = .dictionary(["data": data])
102
+ } else {
103
+ resultData = nil
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,56 @@
1
+ import Foundation
2
+
3
+ @objc public class PluginConfig: NSObject {
4
+
5
+ // The object containing the plugin config values
6
+ private var config: JSObject
7
+
8
+ init(config: JSObject) {
9
+ self.config = config
10
+ }
11
+
12
+ @objc public func getString(_ configKey: String, _ defaultValue: String? = nil) -> String? {
13
+ if let val = (self.config)[keyPath: KeyPath(configKey)] as? String {
14
+ return val
15
+ }
16
+ return defaultValue
17
+ }
18
+
19
+ @objc public func getBoolean(_ configKey: String, _ defaultValue: Bool) -> Bool {
20
+ if let val = (self.config)[keyPath: KeyPath(configKey)] as? Bool {
21
+ return val
22
+ }
23
+ return defaultValue
24
+ }
25
+
26
+ @objc public func getInt(_ configKey: String, _ defaultValue: Int) -> Int {
27
+ if let val = (self.config)[keyPath: KeyPath(configKey)] as? Int {
28
+ return val
29
+ }
30
+ return defaultValue
31
+ }
32
+
33
+ public func getArray(_ configKey: String, _ defaultValue: JSArray? = nil) -> JSArray? {
34
+ if let val = (self.config)[keyPath: KeyPath(configKey)] as? JSArray {
35
+ return val
36
+ }
37
+ return defaultValue
38
+ }
39
+
40
+ public func getObject(_ configKey: String) -> JSObject? {
41
+ return (self.config)[keyPath: KeyPath(configKey)] as? JSObject
42
+ }
43
+
44
+ @objc public func isEmpty() -> Bool {
45
+ return self.config.isEmpty
46
+ }
47
+
48
+ /**
49
+ * Gets the JSObject containing the config of the the provided plugin ID.
50
+ *
51
+ * @return The config for that plugin
52
+ */
53
+ public func getConfigJSON() -> JSObject {
54
+ return self.config
55
+ }
56
+ }
@@ -0,0 +1,141 @@
1
+ import Foundation
2
+
3
+ public class CapacitorWKCookieObserver: NSObject, WKHTTPCookieStoreObserver {
4
+ // Sync WKWebView Cookies to HTTPCookieStorage
5
+ public func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
6
+ DispatchQueue.main.async {
7
+ cookieStore.getAllCookies { cookies in
8
+ cookies.forEach { cookie in
9
+ HTTPCookieStorage.shared.setCookie(cookie)
10
+ }
11
+ }
12
+ }
13
+ }
14
+ }
15
+
16
+ public class CapacitorCookieManager {
17
+ var config: InstanceConfiguration?
18
+
19
+ init(_ capConfig: InstanceConfiguration?) {
20
+ self.config = capConfig
21
+ }
22
+
23
+ public func getServerUrl() -> URL? {
24
+ return self.config?.serverURL ?? self.config?.localURL
25
+ }
26
+
27
+ private func isUrlSanitized(_ urlString: String) -> Bool {
28
+ return urlString.isEmpty || urlString == getServerUrl()?.absoluteString || urlString.hasPrefix("http://") || urlString.hasPrefix("https://")
29
+ }
30
+
31
+ public func getServerUrl(_ urlString: String?) -> URL? {
32
+ guard let urlString = urlString else {
33
+ return getServerUrl()
34
+ }
35
+
36
+ if urlString.isEmpty {
37
+ return getServerUrl()
38
+ }
39
+
40
+ let validUrlString = (isUrlSanitized(urlString)) ? urlString : "http://\(urlString)"
41
+
42
+ guard let url = URL(string: validUrlString) else {
43
+ return getServerUrl()
44
+ }
45
+
46
+ return url
47
+ }
48
+
49
+ public func encode(_ value: String) -> String {
50
+ return value.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!
51
+ }
52
+
53
+ public func decode(_ value: String) -> String {
54
+ return value.removingPercentEncoding!
55
+ }
56
+
57
+ public func setCookie(_ domain: String, _ action: String) {
58
+ let url = getServerUrl(domain)!
59
+ let jar = HTTPCookieStorage.shared
60
+ let field = ["Set-Cookie": action]
61
+ let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
62
+ jar.setCookies(cookies, for: url, mainDocumentURL: nil)
63
+ syncCookiesToWebView()
64
+ }
65
+
66
+ public func setCookie(_ url: URL, _ key: String, _ value: String, _ expires: String?, _ path: String?) {
67
+ let jar = HTTPCookieStorage.shared
68
+ let field = ["Set-Cookie": "\(key)=\(value); expires=\(expires ?? ""); path=\(path ?? "/")"]
69
+ let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
70
+ jar.setCookies(cookies, for: url, mainDocumentURL: nil)
71
+ syncCookiesToWebView()
72
+ }
73
+
74
+ public func getCookiesAsMap(_ url: URL) -> [String: String] {
75
+ syncCookiesToWebView()
76
+ var cookiesMap: [String: String] = [:]
77
+ let jar = HTTPCookieStorage.shared
78
+ if let cookies = jar.cookies(for: url) {
79
+ for cookie in cookies {
80
+ if !cookie.isHTTPOnly {
81
+ cookiesMap[cookie.name] = cookie.value
82
+ }
83
+ }
84
+ }
85
+ return cookiesMap
86
+ }
87
+
88
+ public func getCookies() -> String {
89
+ syncCookiesToWebView()
90
+ let jar = HTTPCookieStorage.shared
91
+ guard let url = self.getServerUrl() else { return "" }
92
+ guard let cookies = jar.cookies(for: url) else { return "" }
93
+ let filteredCookies = cookies.filter { !$0.isHTTPOnly }
94
+ return filteredCookies.map({"\($0.name)=\($0.value)"}).joined(separator: "; ")
95
+ }
96
+
97
+ public func deleteCookie(_ url: URL, _ key: String) {
98
+ let jar = HTTPCookieStorage.shared
99
+ if let cookie = jar.cookies(for: url)?.first(where: { (cookie) -> Bool in
100
+ return cookie.name == key
101
+ }) {
102
+ jar.deleteCookie(cookie)
103
+ DispatchQueue.main.async {
104
+ WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
105
+ }
106
+ }
107
+ }
108
+
109
+ public func clearCookies(_ url: URL) {
110
+ let jar = HTTPCookieStorage.shared
111
+ jar.cookies(for: url)?.forEach({ (cookie) in
112
+ jar.deleteCookie(cookie)
113
+ DispatchQueue.main.async {
114
+ WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
115
+ }
116
+ })
117
+ }
118
+
119
+ public func clearAllCookies() {
120
+ let jar = HTTPCookieStorage.shared
121
+ jar.cookies?.forEach({ (cookie) in
122
+ jar.deleteCookie(cookie)
123
+ DispatchQueue.main.async {
124
+ WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
125
+ }
126
+ })
127
+ }
128
+
129
+ public func syncCookiesToWebView() {
130
+ if let cookies = HTTPCookieStorage.shared.cookies {
131
+ for cookie in cookies {
132
+ DispatchQueue.main.async {
133
+ WKWebsiteDataStore.default()
134
+ .httpCookieStore
135
+ .setCookie(cookie, completionHandler: nil)
136
+ }
137
+
138
+ }
139
+ }
140
+ }
141
+ }