@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.
- package/Capacitor/Capacitor/AppUUID.swift +51 -0
- package/Capacitor/Capacitor/Array+Capacitor.swift +31 -0
- package/Capacitor/Capacitor/CAPApplicationDelegateProxy.swift +32 -0
- package/Capacitor/Capacitor/CAPBridge.swift +25 -0
- package/Capacitor/Capacitor/CAPBridgeDelegate.swift +6 -0
- package/Capacitor/Capacitor/CAPBridgeProtocol.swift +148 -0
- package/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.h +6 -0
- package/Capacitor/Capacitor/CAPBridgeViewController+CDVScreenOrientationDelegate.m +5 -0
- package/Capacitor/Capacitor/CAPBridgeViewController.swift +384 -0
- package/Capacitor/Capacitor/CAPBridgedJSTypes.h +18 -0
- package/Capacitor/Capacitor/CAPBridgedJSTypes.m +43 -0
- package/Capacitor/Capacitor/CAPBridgedPlugin+getMethod.swift +13 -0
- package/Capacitor/Capacitor/CAPBridgedPlugin.h +41 -0
- package/Capacitor/Capacitor/CAPFile.swift +14 -0
- package/Capacitor/Capacitor/CAPInstanceConfiguration.h +38 -0
- package/Capacitor/Capacitor/CAPInstanceConfiguration.m +93 -0
- package/Capacitor/Capacitor/CAPInstanceConfiguration.swift +78 -0
- package/Capacitor/Capacitor/CAPInstanceDescriptor.h +167 -0
- package/Capacitor/Capacitor/CAPInstanceDescriptor.m +56 -0
- package/Capacitor/Capacitor/CAPInstanceDescriptor.swift +198 -0
- package/Capacitor/Capacitor/CAPInstancePlugin.swift +10 -0
- package/Capacitor/Capacitor/CAPLog.swift +11 -0
- package/Capacitor/Capacitor/CAPNotifications.swift +69 -0
- package/Capacitor/Capacitor/CAPPlugin+LoadInstance.swift +20 -0
- package/Capacitor/Capacitor/CAPPlugin.h +60 -0
- package/Capacitor/Capacitor/CAPPlugin.m +180 -0
- package/Capacitor/Capacitor/CAPPluginCall.h +25 -0
- package/Capacitor/Capacitor/CAPPluginCall.m +36 -0
- package/Capacitor/Capacitor/CAPPluginCall.swift +97 -0
- package/Capacitor/Capacitor/CAPPluginMethod.h +36 -0
- package/Capacitor/Capacitor/CAPPluginMethod.m +44 -0
- package/Capacitor/Capacitor/CAPPluginMethod.swift +17 -0
- package/Capacitor/Capacitor/Capacitor.h +15 -0
- package/Capacitor/Capacitor/Capacitor.modulemap +8 -0
- package/Capacitor/Capacitor/CapacitorBridge.swift +768 -0
- package/Capacitor/Capacitor/CapacitorExtension.swift +24 -0
- package/Capacitor/Capacitor/Codable/JSValueDecoder.swift +479 -0
- package/Capacitor/Capacitor/Codable/JSValueEncoder.swift +671 -0
- package/Capacitor/Capacitor/Data+Capacitor.swift +22 -0
- package/Capacitor/Capacitor/DocLinks.swift +8 -0
- package/Capacitor/Capacitor/Info.plist +24 -0
- package/Capacitor/Capacitor/JS.swift +122 -0
- package/Capacitor/Capacitor/JSExport.swift +218 -0
- package/Capacitor/Capacitor/JSTypes.swift +254 -0
- package/Capacitor/Capacitor/KeyPath.swift +60 -0
- package/Capacitor/Capacitor/KeyValueStore.swift +303 -0
- package/Capacitor/Capacitor/NotificationHandlerProtocol.swift +6 -0
- package/Capacitor/Capacitor/NotificationRouter.swift +60 -0
- package/Capacitor/Capacitor/PluginCallResult.swift +106 -0
- package/Capacitor/Capacitor/PluginConfig.swift +56 -0
- package/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift +141 -0
- package/Capacitor/Capacitor/Plugins/CapacitorCookies.swift +57 -0
- package/Capacitor/Capacitor/Plugins/CapacitorHttp.swift +57 -0
- package/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift +225 -0
- package/Capacitor/Capacitor/Plugins/Console.swift +16 -0
- package/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift +236 -0
- package/Capacitor/Capacitor/Plugins/SystemBars.swift +133 -0
- package/Capacitor/Capacitor/Plugins/WebView.swift +44 -0
- package/Capacitor/Capacitor/PrivacyInfo.xcprivacy +14 -0
- package/Capacitor/Capacitor/Router.swift +29 -0
- package/Capacitor/Capacitor/TmpViewController.swift +8 -0
- package/Capacitor/Capacitor/UIColor.swift +55 -0
- package/Capacitor/Capacitor/UIStatusBarManager+CAPHandleTapAction.m +37 -0
- package/Capacitor/Capacitor/WKWebView+Capacitor.m +15 -0
- package/Capacitor/Capacitor/WKWebView+Capacitor.swift +80 -0
- package/Capacitor/Capacitor/WebViewAssetHandler.swift +550 -0
- package/Capacitor/Capacitor/WebViewDelegationHandler.swift +361 -0
- package/Capacitor/Capacitor/assets/native-bridge.js +1029 -0
- package/Capacitor.podspec +23 -0
- package/CapacitorCordova/CapacitorCordova/CapacitorCordova.h +25 -0
- package/CapacitorCordova/CapacitorCordova/CapacitorCordova.modulemap +6 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.h +8 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/AppDelegate.m +5 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDV.h +28 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailability.h +109 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVAvailabilityDeprecated.h +21 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegate.h +49 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.h +39 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVCommandDelegateImpl.m +149 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.h +31 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVConfigParser.m +81 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.h +52 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVInvokedUrlCommand.m +116 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.h +39 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin+Resources.m +38 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.h +76 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPlugin.m +136 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.h +25 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginManager.m +77 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.h +82 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVPluginResult.m +216 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVScreenOrientationDelegate.h +33 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.h +27 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVURLProtocol.m +74 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.h +30 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVViewController.m +37 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.h +34 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/CDVWebViewProcessPoolFactory.m +55 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.h +35 -0
- package/CapacitorCordova/CapacitorCordova/Classes/Public/NSDictionary+CordovaPreferences.m +63 -0
- package/CapacitorCordova/CapacitorCordova/Info.plist +26 -0
- package/CapacitorCordova/CapacitorCordova/PrivacyInfo.xcprivacy +14 -0
- package/CapacitorCordova.podspec +26 -0
- package/LICENSE +21 -0
- package/package.json +33 -0
- package/scripts/pods_helpers.rb +12 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc(CAPCookiesPlugin)
|
|
4
|
+
public class CAPCookiesPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
5
|
+
public let identifier = "CAPCookiesPlugin"
|
|
6
|
+
public let jsName = "CapacitorCookies"
|
|
7
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
8
|
+
CAPPluginMethod(name: "getCookies", returnType: CAPPluginReturnPromise),
|
|
9
|
+
CAPPluginMethod(name: "setCookie", returnType: CAPPluginReturnPromise),
|
|
10
|
+
CAPPluginMethod(name: "deleteCookie", returnType: CAPPluginReturnPromise),
|
|
11
|
+
CAPPluginMethod(name: "clearCookies", returnType: CAPPluginReturnPromise),
|
|
12
|
+
CAPPluginMethod(name: "clearAllCookies", returnType: CAPPluginReturnPromise)
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
var cookieManager: CapacitorCookieManager?
|
|
16
|
+
|
|
17
|
+
@objc override public func load() {
|
|
18
|
+
cookieManager = CapacitorCookieManager(bridge?.config)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@objc func getCookies(_ call: CAPPluginCall) {
|
|
22
|
+
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid URL / Server URL")}
|
|
23
|
+
call.resolve(cookieManager!.getCookiesAsMap(url))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@objc func setCookie(_ call: CAPPluginCall) {
|
|
27
|
+
guard let key = call.getString("key") else { return call.reject("Must provide key") }
|
|
28
|
+
guard let value = call.getString("value") else { return call.reject("Must provide value") }
|
|
29
|
+
|
|
30
|
+
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid domain") }
|
|
31
|
+
|
|
32
|
+
let expires = call.getString("expires", "")
|
|
33
|
+
let path = call.getString("path", "")
|
|
34
|
+
cookieManager!.setCookie(url, key, cookieManager!.encode(value), expires, path)
|
|
35
|
+
call.resolve()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@objc func deleteCookie(_ call: CAPPluginCall) {
|
|
39
|
+
guard let key = call.getString("key") else { return call.reject("Must provide key") }
|
|
40
|
+
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid URL / Server URL")}
|
|
41
|
+
cookieManager!.deleteCookie(url, key)
|
|
42
|
+
call.resolve()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@objc func clearCookies(_ call: CAPPluginCall) {
|
|
46
|
+
let url = cookieManager!.getServerUrl(call.getString("url"))
|
|
47
|
+
if url != nil {
|
|
48
|
+
cookieManager!.clearCookies(url!)
|
|
49
|
+
call.resolve()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@objc func clearAllCookies(_ call: CAPPluginCall) {
|
|
54
|
+
cookieManager!.clearAllCookies()
|
|
55
|
+
call.resolve()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc(CAPHttpPlugin)
|
|
4
|
+
public class CAPHttpPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
5
|
+
public let identifier = "CAPHttpPlugin"
|
|
6
|
+
public let jsName = "CapacitorHttp"
|
|
7
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
8
|
+
CAPPluginMethod(name: "request", returnType: CAPPluginReturnPromise),
|
|
9
|
+
CAPPluginMethod(name: "get", returnType: CAPPluginReturnPromise),
|
|
10
|
+
CAPPluginMethod(name: "post", returnType: CAPPluginReturnPromise),
|
|
11
|
+
CAPPluginMethod(name: "put", returnType: CAPPluginReturnPromise),
|
|
12
|
+
CAPPluginMethod(name: "patch", returnType: CAPPluginReturnPromise),
|
|
13
|
+
CAPPluginMethod(name: "delete", returnType: CAPPluginReturnPromise)
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
@objc func http(_ call: CAPPluginCall, _ httpMethod: String?) {
|
|
17
|
+
do {
|
|
18
|
+
if let clazz = NSClassFromString("SSLPinningHttpRequestHandlerClass") {
|
|
19
|
+
// swiftlint:disable force_cast
|
|
20
|
+
(clazz as! NSObject.Type).perform(#selector(self.request(_:)), with: [
|
|
21
|
+
"call": call,
|
|
22
|
+
"httpMethod": httpMethod as Any,
|
|
23
|
+
"config": self.bridge?.config as Any
|
|
24
|
+
])
|
|
25
|
+
// swiftlint:enable force_cast
|
|
26
|
+
} else {
|
|
27
|
+
try HttpRequestHandler.request(call, httpMethod, self.bridge?.config)
|
|
28
|
+
}
|
|
29
|
+
} catch let error {
|
|
30
|
+
call.reject(error.localizedDescription)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@objc func request(_ call: CAPPluginCall) {
|
|
35
|
+
http(call, nil)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@objc func get(_ call: CAPPluginCall) {
|
|
39
|
+
http(call, "GET")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@objc func post(_ call: CAPPluginCall) {
|
|
43
|
+
http(call, "POST")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@objc func put(_ call: CAPPluginCall) {
|
|
47
|
+
http(call, "PUT")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@objc func patch(_ call: CAPPluginCall) {
|
|
51
|
+
http(call, "PATCH")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@objc func delete(_ call: CAPPluginCall) {
|
|
55
|
+
http(call, "DELETE")
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
open class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {
|
|
4
|
+
public var request: URLRequest
|
|
5
|
+
public var headers: [String: String]
|
|
6
|
+
|
|
7
|
+
public enum CapacitorUrlRequestError: Error {
|
|
8
|
+
case serializationError(String?)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public init(_ url: URL, method: String) {
|
|
12
|
+
request = URLRequest(url: url)
|
|
13
|
+
request.httpMethod = method
|
|
14
|
+
headers = [:]
|
|
15
|
+
if let lang = Locale.autoupdatingCurrent.languageCode {
|
|
16
|
+
if let country = Locale.autoupdatingCurrent.regionCode {
|
|
17
|
+
headers["Accept-Language"] = "\(lang)-\(country),\(lang);q=0.5"
|
|
18
|
+
} else {
|
|
19
|
+
headers["Accept-Language"] = "\(lang);q=0.5"
|
|
20
|
+
}
|
|
21
|
+
request.addValue(headers["Accept-Language"]!, forHTTPHeaderField: "Accept-Language")
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public func getRequestDataAsJson(_ data: JSValue) throws -> Data? {
|
|
26
|
+
// We need to check if the JSON is valid before attempting to serialize, as JSONSerialization.data will not throw an exception that can be caught, and will cause the application to crash if it fails.
|
|
27
|
+
if JSONSerialization.isValidJSONObject(data) {
|
|
28
|
+
return try JSONSerialization.data(withJSONObject: data)
|
|
29
|
+
} else {
|
|
30
|
+
throw CapacitorUrlRequest.CapacitorUrlRequestError.serializationError("[ data ] argument for request of content-type [ application/json ] must be serializable to JSON")
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public func getRequestDataAsFormUrlEncoded(_ data: JSValue) throws -> Data? {
|
|
35
|
+
guard var components = URLComponents(url: request.url!, resolvingAgainstBaseURL: false) else { return nil }
|
|
36
|
+
components.queryItems = []
|
|
37
|
+
|
|
38
|
+
guard let obj = data as? JSObject else {
|
|
39
|
+
// Throw, other data types explicitly not supported
|
|
40
|
+
throw CapacitorUrlRequestError.serializationError("[ data ] argument for request with content-type [ multipart/form-data ] may only be a plain javascript object")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let allowed = CharacterSet(charactersIn: "-._*").union(.alphanumerics)
|
|
44
|
+
|
|
45
|
+
obj.keys.forEach { (key: String) in
|
|
46
|
+
let value = obj[key] as? String ?? ""
|
|
47
|
+
components.queryItems?.append(URLQueryItem(name: key.addingPercentEncoding(withAllowedCharacters: allowed)?.replacingOccurrences(of: "%20", with: "+") ?? key, value: value.addingPercentEncoding(withAllowedCharacters: allowed)?.replacingOccurrences(of: "%20", with: "+")))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if components.query != nil {
|
|
51
|
+
return Data(components.query!.utf8)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return nil
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public func getRequestDataAsMultipartFormData(_ data: JSValue, _ contentType: String) throws -> Data {
|
|
58
|
+
guard let obj = data as? JSObject else {
|
|
59
|
+
// Throw, other data types explicitly not supported.
|
|
60
|
+
throw CapacitorUrlRequestError.serializationError("[ data ] argument for request with content-type [ application/x-www-form-urlencoded ] may only be a plain javascript object")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let strings: [String: String] = obj.compactMapValues { any in
|
|
64
|
+
any as? String
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var data = Data()
|
|
68
|
+
var boundary = UUID().uuidString
|
|
69
|
+
if contentType.contains("="), let contentBoundary = contentType.components(separatedBy: "=").last {
|
|
70
|
+
boundary = contentBoundary
|
|
71
|
+
} else {
|
|
72
|
+
overrideContentType(boundary)
|
|
73
|
+
}
|
|
74
|
+
strings.forEach { key, value in
|
|
75
|
+
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
|
|
76
|
+
data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
|
|
77
|
+
data.append(value.data(using: .utf8)!)
|
|
78
|
+
}
|
|
79
|
+
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
|
|
80
|
+
|
|
81
|
+
return data
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private func overrideContentType(_ boundary: String) {
|
|
85
|
+
let contentType = "multipart/form-data; boundary=\(boundary)"
|
|
86
|
+
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
|
|
87
|
+
headers["Content-Type"] = contentType
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public func getRequestDataAsString(_ data: JSValue) throws -> Data {
|
|
91
|
+
guard let stringData = data as? String else {
|
|
92
|
+
throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as string")
|
|
93
|
+
}
|
|
94
|
+
return Data(stringData.utf8)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public func getRequestHeader(_ index: String) -> Any? {
|
|
98
|
+
var normalized = [:] as [String: Any]
|
|
99
|
+
self.headers.keys.forEach { (key: String) in
|
|
100
|
+
normalized[key.lowercased()] = self.headers[key]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return normalized[index.lowercased()]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public func getRequestDataFromFormData(_ data: JSValue, _ contentType: String) throws -> Data? {
|
|
107
|
+
guard let list = data as? JSArray else {
|
|
108
|
+
// Throw, other data types explicitly not supported.
|
|
109
|
+
throw CapacitorUrlRequestError.serializationError("Data must be an array for FormData")
|
|
110
|
+
}
|
|
111
|
+
var data = Data()
|
|
112
|
+
var boundary = UUID().uuidString
|
|
113
|
+
if contentType.contains("="), let contentBoundary = contentType.components(separatedBy: "=").last {
|
|
114
|
+
boundary = contentBoundary
|
|
115
|
+
} else {
|
|
116
|
+
overrideContentType(boundary)
|
|
117
|
+
}
|
|
118
|
+
for entry in list {
|
|
119
|
+
guard let item = entry as? [String: String] else {
|
|
120
|
+
throw CapacitorUrlRequestError.serializationError("Data must be an array for FormData")
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let type = item["type"]
|
|
124
|
+
let key = item["key"]
|
|
125
|
+
let value = item["value"]!
|
|
126
|
+
|
|
127
|
+
if type == "base64File" {
|
|
128
|
+
let fileName = item["fileName"]
|
|
129
|
+
let fileContentType = item["contentType"]
|
|
130
|
+
|
|
131
|
+
data.append("--\(boundary)\r\n".data(using: .utf8)!)
|
|
132
|
+
data.append("Content-Disposition: form-data; name=\"\(key!)\"; filename=\"\(fileName!)\"\r\n".data(using: .utf8)!)
|
|
133
|
+
data.append("Content-Type: \(fileContentType!)\r\n".data(using: .utf8)!)
|
|
134
|
+
data.append("Content-Transfer-Encoding: binary\r\n".data(using: .utf8)!)
|
|
135
|
+
data.append("\r\n".data(using: .utf8)!)
|
|
136
|
+
|
|
137
|
+
data.append(Data(base64Encoded: value)!)
|
|
138
|
+
|
|
139
|
+
data.append("\r\n".data(using: .utf8)!)
|
|
140
|
+
} else if type == "string" {
|
|
141
|
+
data.append("--\(boundary)\r\n".data(using: .utf8)!)
|
|
142
|
+
data.append("Content-Disposition: form-data; name=\"\(key!)\"\r\n".data(using: .utf8)!)
|
|
143
|
+
data.append("\r\n".data(using: .utf8)!)
|
|
144
|
+
data.append(value.data(using: .utf8)!)
|
|
145
|
+
data.append("\r\n".data(using: .utf8)!)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
data.append("--\(boundary)--\r\n".data(using: .utf8)!)
|
|
149
|
+
|
|
150
|
+
return data
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public func getRequestData(_ body: JSValue, _ contentType: String, _ dataType: String? = nil) throws -> Data? {
|
|
154
|
+
if dataType == "file" {
|
|
155
|
+
guard let stringData = body as? String else {
|
|
156
|
+
throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as string")
|
|
157
|
+
}
|
|
158
|
+
return Data(base64Encoded: stringData)
|
|
159
|
+
} else if dataType == "formData" {
|
|
160
|
+
return try getRequestDataFromFormData(body, contentType)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// If data can be parsed directly as a string, return that without processing.
|
|
164
|
+
if let strVal = try? getRequestDataAsString(body) {
|
|
165
|
+
return strVal
|
|
166
|
+
} else if contentType.contains("application/json") {
|
|
167
|
+
return try getRequestDataAsJson(body)
|
|
168
|
+
} else if contentType.contains("application/x-www-form-urlencoded") {
|
|
169
|
+
return try getRequestDataAsFormUrlEncoded(body)
|
|
170
|
+
} else if contentType.contains("multipart/form-data") {
|
|
171
|
+
return try getRequestDataAsMultipartFormData(body, contentType)
|
|
172
|
+
} else {
|
|
173
|
+
throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed for content type [ \(contentType) ]")
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@available(*, deprecated, message: "Use newer function with passed headers of type [String: Any]")
|
|
178
|
+
public func setRequestHeaders(_ headers: [String: String]) {
|
|
179
|
+
headers.keys.forEach { (key: String) in
|
|
180
|
+
let value = headers[key]
|
|
181
|
+
request.addValue(value!, forHTTPHeaderField: key)
|
|
182
|
+
self.headers[key] = value
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public func setRequestHeaders(_ headers: [String: Any]) {
|
|
187
|
+
headers.keys.forEach { (key: String) in
|
|
188
|
+
let value = headers[key]
|
|
189
|
+
request.setValue("\(value!)", forHTTPHeaderField: key)
|
|
190
|
+
self.headers[key] = "\(value!)"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public func setRequestBody(_ body: JSValue, _ dataType: String? = nil) throws {
|
|
195
|
+
let contentType = self.getRequestHeader("Content-Type") as? String
|
|
196
|
+
|
|
197
|
+
if contentType != nil {
|
|
198
|
+
request.httpBody = try getRequestData(body, contentType!, dataType)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public func setContentType(_ data: String?) {
|
|
203
|
+
request.setValue(data, forHTTPHeaderField: "Content-Type")
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public func setTimeout(_ timeout: TimeInterval) {
|
|
207
|
+
request.timeoutInterval = timeout
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public func getUrlRequest() -> URLRequest {
|
|
211
|
+
return request
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
open func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
|
|
215
|
+
completionHandler(nil)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
open func getUrlSession(_ call: CAPPluginCall) -> URLSession {
|
|
219
|
+
let disableRedirects = call.getBool("disableRedirects") ?? false
|
|
220
|
+
if !disableRedirects {
|
|
221
|
+
return URLSession.shared
|
|
222
|
+
}
|
|
223
|
+
return URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc(CAPConsolePlugin)
|
|
4
|
+
public class CAPConsolePlugin: CAPPlugin, CAPBridgedPlugin {
|
|
5
|
+
public let identifier = "CAPConsolePlugin"
|
|
6
|
+
public let jsName = "Console"
|
|
7
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
8
|
+
CAPPluginMethod(name: "log", returnType: CAPPluginReturnNone)
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
@objc public func log(_ call: CAPPluginCall) {
|
|
12
|
+
let message = call.getString("message") ?? ""
|
|
13
|
+
let level = call.getString("level") ?? "log"
|
|
14
|
+
CAPLog.print("⚡️ [\(level)] - \(message)")
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
|
|
4
|
+
public enum ResponseType: String {
|
|
5
|
+
case arrayBuffer = "arraybuffer"
|
|
6
|
+
case blob = "blob"
|
|
7
|
+
case document = "document"
|
|
8
|
+
case json = "json"
|
|
9
|
+
case text = "text"
|
|
10
|
+
|
|
11
|
+
public static let `default`: ResponseType = .text
|
|
12
|
+
|
|
13
|
+
public init(string: String?) {
|
|
14
|
+
guard let string = string else {
|
|
15
|
+
self = .default
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
guard let responseType = ResponseType(rawValue: string.lowercased()) else {
|
|
20
|
+
self = .default
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
self = responseType
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Helper that safely parses JSON Data. Otherwise returns an error (without throwing)
|
|
29
|
+
/// - Parameters:
|
|
30
|
+
/// - data: The JSON Data to parse
|
|
31
|
+
/// - Returns: The parsed value or an error
|
|
32
|
+
func tryParseJson(_ data: Data) -> Any {
|
|
33
|
+
do {
|
|
34
|
+
return try JSONSerialization.jsonObject(with: data, options: [.mutableContainers, .fragmentsAllowed])
|
|
35
|
+
} catch {
|
|
36
|
+
return error.localizedDescription
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Helper to convert the headers dictionary to lower case keys. This allows case-insensitive querying in the bridge javascript.
|
|
41
|
+
/// - Parameters:
|
|
42
|
+
/// - headers: The headers as dictionary. The type is unspecific because the incoming headers are coming from the
|
|
43
|
+
/// allHeaderFields property of the HttpResponse.
|
|
44
|
+
/// - Returns: The modified headers dictionary with lowercase keys
|
|
45
|
+
private func lowerCaseHeaderDictionary(_ headers: [AnyHashable: Any]) -> [String: Any] {
|
|
46
|
+
// Lowercases the key of the headers dictionary.
|
|
47
|
+
return Dictionary(uniqueKeysWithValues: headers.map({ (key: AnyHashable, value: Any) in
|
|
48
|
+
return (String(describing: key).lowercased(), value)
|
|
49
|
+
}))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
open class HttpRequestHandler {
|
|
53
|
+
open class CapacitorHttpRequestBuilder {
|
|
54
|
+
public var url: URL?
|
|
55
|
+
public var method: String?
|
|
56
|
+
public var params: [String: String]?
|
|
57
|
+
open var request: CapacitorUrlRequest?
|
|
58
|
+
|
|
59
|
+
public init() { }
|
|
60
|
+
|
|
61
|
+
/// Set the URL of the HttpRequest
|
|
62
|
+
/// - Throws: an error of URLError if the urlString cannot be parsed
|
|
63
|
+
/// - Parameters:
|
|
64
|
+
/// - urlString: The URL value to parse
|
|
65
|
+
/// - Returns: self to continue chaining functions
|
|
66
|
+
public func setUrl(_ urlString: String) throws -> CapacitorHttpRequestBuilder {
|
|
67
|
+
guard let url = URL(string: urlString) else {
|
|
68
|
+
throw URLError(.badURL)
|
|
69
|
+
}
|
|
70
|
+
self.url = url
|
|
71
|
+
return self
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public func setMethod(_ method: String) -> CapacitorHttpRequestBuilder {
|
|
75
|
+
self.method = method
|
|
76
|
+
return self
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public func setUrlParams(_ params: [String: Any], _ shouldEncodeUrlParams: Bool = true) -> CapacitorHttpRequestBuilder {
|
|
80
|
+
if params.count != 0 {
|
|
81
|
+
// swiftlint:disable force_cast
|
|
82
|
+
var cmps = URLComponents(url: url!, resolvingAgainstBaseURL: true)
|
|
83
|
+
if cmps?.queryItems == nil {
|
|
84
|
+
cmps?.queryItems = []
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if shouldEncodeUrlParams {
|
|
88
|
+
var urlSafeParams: [URLQueryItem] = []
|
|
89
|
+
for (key, value) in params {
|
|
90
|
+
if let arr = value as? [String] {
|
|
91
|
+
arr.forEach { str in
|
|
92
|
+
urlSafeParams.append(URLQueryItem(name: key, value: str))
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
urlSafeParams.append(URLQueryItem(name: key, value: (value as! String)))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
cmps!.queryItems?.append(contentsOf: urlSafeParams)
|
|
99
|
+
} else {
|
|
100
|
+
cmps?.query = params.flatMap { key, value -> [String] in
|
|
101
|
+
if let arrayValue = value as? [String] {
|
|
102
|
+
return arrayValue.map { "\(key)=\($0)" }
|
|
103
|
+
} else {
|
|
104
|
+
return ["\(key)=\(value)"]
|
|
105
|
+
}
|
|
106
|
+
}.joined(separator: "&")
|
|
107
|
+
}
|
|
108
|
+
url = cmps!.url!
|
|
109
|
+
}
|
|
110
|
+
return self
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
open func openConnection() -> CapacitorHttpRequestBuilder {
|
|
114
|
+
request = CapacitorUrlRequest(url!, method: method!)
|
|
115
|
+
return self
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public func build() -> CapacitorUrlRequest {
|
|
119
|
+
return request!
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public static func setCookiesFromResponse(_ response: HTTPURLResponse, _ config: InstanceConfiguration?) {
|
|
124
|
+
let headers = response.allHeaderFields
|
|
125
|
+
if let cookies = headers["Set-Cookie"] as? String {
|
|
126
|
+
for cookie in cookies.components(separatedBy: ",") {
|
|
127
|
+
let domainComponents = cookie.lowercased().components(separatedBy: "domain=")
|
|
128
|
+
if domainComponents.count > 1 {
|
|
129
|
+
CapacitorCookieManager(config).setCookie(
|
|
130
|
+
domainComponents[1].components(separatedBy: ";")[0],
|
|
131
|
+
cookie
|
|
132
|
+
)
|
|
133
|
+
} else {
|
|
134
|
+
CapacitorCookieManager(config).setCookie("", cookie)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
CapacitorCookieManager(config).syncCookiesToWebView()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public static func buildResponse(_ data: Data?, _ response: HTTPURLResponse, responseType: ResponseType = .default) -> [String: Any] {
|
|
142
|
+
var output = [:] as [String: Any]
|
|
143
|
+
|
|
144
|
+
output["status"] = response.statusCode
|
|
145
|
+
|
|
146
|
+
// HTTP Headers are case insensitive. The allHeaderFields dictionary returned by Apple Foundation Code has its keys capitalized.
|
|
147
|
+
// According to the documentation at https://developer.apple.com/documentation/foundation/httpurlresponse/1417930-allheaderfields
|
|
148
|
+
// "HTTP headers are case insensitive. To simplify your code, URL Loading System canonicalizes certain header field names into
|
|
149
|
+
// their standard form. For example, if the server sends a content-length header, it’s automatically adjusted to be Content-Length."
|
|
150
|
+
// To handle the case insevitivy, we are converting the header keys to lower case here. When querying for headers in the native bridge,
|
|
151
|
+
// we are lowercasing the key as well.
|
|
152
|
+
output["headers"] = lowerCaseHeaderDictionary(response.allHeaderFields)
|
|
153
|
+
output["url"] = response.url?.absoluteString
|
|
154
|
+
|
|
155
|
+
guard let data = data else {
|
|
156
|
+
output["data"] = ""
|
|
157
|
+
return output
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let contentType = (response.allHeaderFields["Content-Type"] as? String ?? "application/default").lowercased()
|
|
161
|
+
|
|
162
|
+
if contentType.contains("application/json") || responseType == .json {
|
|
163
|
+
output["data"] = tryParseJson(data)
|
|
164
|
+
} else if responseType == .arrayBuffer || responseType == .blob {
|
|
165
|
+
output["data"] = data.base64EncodedString()
|
|
166
|
+
} else if responseType == .document || responseType == .text || responseType == .default {
|
|
167
|
+
output["data"] = String(data: data, encoding: .utf8)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return output
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public static func request(_ call: CAPPluginCall, _ httpMethod: String?, _ config: InstanceConfiguration?) throws {
|
|
174
|
+
guard var urlString = call.getString("url") else { throw URLError(.badURL) }
|
|
175
|
+
let method = httpMethod ?? call.getString("method", "GET")
|
|
176
|
+
|
|
177
|
+
var headers = (call.getObject("headers") ?? [:]) as [String: Any]
|
|
178
|
+
let params = (call.getObject("params") ?? [:]) as [String: Any]
|
|
179
|
+
let responseType = call.getString("responseType") ?? "text"
|
|
180
|
+
let connectTimeout = call.getDouble("connectTimeout")
|
|
181
|
+
let shouldEncodeUrlParams = call.getBool("shouldEncodeUrlParams", true)
|
|
182
|
+
let readTimeout = call.getDouble("readTimeout")
|
|
183
|
+
let dataType = call.getString("dataType") ?? "any"
|
|
184
|
+
|
|
185
|
+
if urlString == urlString.removingPercentEncoding {
|
|
186
|
+
guard let encodedUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { throw URLError(.badURL) }
|
|
187
|
+
urlString = encodedUrlString
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let request = try CapacitorHttpRequestBuilder()
|
|
191
|
+
.setUrl(urlString)
|
|
192
|
+
.setMethod(method)
|
|
193
|
+
.setUrlParams(params, shouldEncodeUrlParams)
|
|
194
|
+
.openConnection()
|
|
195
|
+
.build()
|
|
196
|
+
|
|
197
|
+
if let userAgentString = config?.overridenUserAgentString, headers["User-Agent"] == nil, headers["user-agent"] == nil {
|
|
198
|
+
headers["User-Agent"] = userAgentString
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
request.setRequestHeaders(headers)
|
|
202
|
+
|
|
203
|
+
// Timeouts in iOS are in seconds. So read the value in millis and divide by 1000
|
|
204
|
+
let timeout = (connectTimeout ?? readTimeout ?? 600000.0) / 1000.0
|
|
205
|
+
request.setTimeout(timeout)
|
|
206
|
+
|
|
207
|
+
if let data = call.options["data"] as? JSValue {
|
|
208
|
+
do {
|
|
209
|
+
try request.setRequestBody(data, dataType)
|
|
210
|
+
} catch {
|
|
211
|
+
// Explicitly reject if the http request body was not set successfully,
|
|
212
|
+
// so as to not send a known malformed request, and to provide the developer with additional context.
|
|
213
|
+
call.reject(error.localizedDescription, (error as NSError).domain, error, nil)
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let urlRequest = request.getUrlRequest()
|
|
219
|
+
let urlSession = request.getUrlSession(call)
|
|
220
|
+
let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
|
|
221
|
+
urlSession.invalidateAndCancel()
|
|
222
|
+
|
|
223
|
+
if let error = error {
|
|
224
|
+
call.reject(error.localizedDescription, (error as NSError).domain, error, nil)
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
setCookiesFromResponse(response as! HTTPURLResponse, config)
|
|
229
|
+
|
|
230
|
+
let type = ResponseType(rawValue: responseType) ?? .default
|
|
231
|
+
call.resolve(self.buildResponse(data, response as! HTTPURLResponse, responseType: type))
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
task.resume()
|
|
235
|
+
}
|
|
236
|
+
}
|