@capacitor/ios 4.5.0 → 4.5.1-dev-20221117T024619.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/CAPBridgeViewController.swift +1 -0
- package/Capacitor/Capacitor/CAPWebView.swift +1 -0
- package/Capacitor/Capacitor/Plugins/CapacitorCookieManager.swift +69 -16
- package/Capacitor/Capacitor/Plugins/CapacitorCookies.swift +9 -8
- package/Capacitor/Capacitor/Plugins/CapacitorHttp.swift +1 -1
- package/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift +22 -1
- package/Capacitor/Capacitor/WebViewDelegationHandler.swift +3 -3
- package/Capacitor/Capacitor/assets/native-bridge.js +28 -24
- package/package.json +3 -3
|
@@ -105,6 +105,7 @@ import Cordova
|
|
|
105
105
|
*/
|
|
106
106
|
open func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
|
|
107
107
|
let webViewConfiguration = WKWebViewConfiguration()
|
|
108
|
+
webViewConfiguration.websiteDataStore.httpCookieStore.add(CapacitorWKCookieObserver())
|
|
108
109
|
webViewConfiguration.allowsInlineMediaPlayback = true
|
|
109
110
|
webViewConfiguration.suppressesIncrementalRendering = false
|
|
110
111
|
webViewConfiguration.allowsAirPlayForMediaPlayback = true
|
|
@@ -125,6 +125,7 @@ extension CAPWebView {
|
|
|
125
125
|
|
|
126
126
|
public func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
|
|
127
127
|
let webViewConfiguration = WKWebViewConfiguration()
|
|
128
|
+
webViewConfiguration.websiteDataStore.httpCookieStore.add(CapacitorWKCookieObserver())
|
|
128
129
|
webViewConfiguration.allowsInlineMediaPlayback = true
|
|
129
130
|
webViewConfiguration.suppressesIncrementalRendering = false
|
|
130
131
|
webViewConfiguration.allowsAirPlayForMediaPlayback = true
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import Foundation
|
|
2
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
|
+
|
|
3
16
|
public class CapacitorCookieManager {
|
|
4
17
|
var config: InstanceConfiguration?
|
|
5
18
|
|
|
@@ -11,12 +24,22 @@ public class CapacitorCookieManager {
|
|
|
11
24
|
return self.config?.serverURL
|
|
12
25
|
}
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
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 {
|
|
16
33
|
return getServerUrl()
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
|
|
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 {
|
|
20
43
|
return getServerUrl()
|
|
21
44
|
}
|
|
22
45
|
|
|
@@ -31,22 +54,25 @@ public class CapacitorCookieManager {
|
|
|
31
54
|
return value.removingPercentEncoding!
|
|
32
55
|
}
|
|
33
56
|
|
|
34
|
-
public func setCookie(_
|
|
35
|
-
let url = getServerUrl()!
|
|
57
|
+
public func setCookie(_ domain: String, _ action: String) {
|
|
58
|
+
let url = getServerUrl(domain)!
|
|
36
59
|
let jar = HTTPCookieStorage.shared
|
|
37
|
-
let field = ["Set-Cookie":
|
|
60
|
+
let field = ["Set-Cookie": action]
|
|
38
61
|
let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
|
|
39
|
-
jar.setCookies(cookies, for: url, mainDocumentURL:
|
|
62
|
+
jar.setCookies(cookies, for: url, mainDocumentURL: nil)
|
|
63
|
+
syncCookiesToWebView()
|
|
40
64
|
}
|
|
41
65
|
|
|
42
|
-
public func setCookie(_ url: URL, _ key: String, _ value: String) {
|
|
66
|
+
public func setCookie(_ url: URL, _ key: String, _ value: String, _ expires: String?, _ path: String?) {
|
|
43
67
|
let jar = HTTPCookieStorage.shared
|
|
44
|
-
let field = ["Set-Cookie": "\(key)=\(value)"]
|
|
68
|
+
let field = ["Set-Cookie": "\(key)=\(value); expires=\(expires ?? ""); path=\(path ?? "/")"]
|
|
45
69
|
let cookies = HTTPCookie.cookies(withResponseHeaderFields: field, for: url)
|
|
46
|
-
jar.setCookies(cookies, for: url, mainDocumentURL:
|
|
70
|
+
jar.setCookies(cookies, for: url, mainDocumentURL: nil)
|
|
71
|
+
syncCookiesToWebView()
|
|
47
72
|
}
|
|
48
73
|
|
|
49
74
|
public func getCookiesAsMap(_ url: URL) -> [String: String] {
|
|
75
|
+
syncCookiesToWebView()
|
|
50
76
|
var cookiesMap: [String: String] = [:]
|
|
51
77
|
let jar = HTTPCookieStorage.shared
|
|
52
78
|
if let cookies = jar.cookies(for: url) {
|
|
@@ -58,6 +84,7 @@ public class CapacitorCookieManager {
|
|
|
58
84
|
}
|
|
59
85
|
|
|
60
86
|
public func getCookies() -> String {
|
|
87
|
+
syncCookiesToWebView()
|
|
61
88
|
let jar = HTTPCookieStorage.shared
|
|
62
89
|
guard let url = self.getServerUrl() else { return "" }
|
|
63
90
|
guard let cookies = jar.cookies(for: url) else { return "" }
|
|
@@ -66,20 +93,46 @@ public class CapacitorCookieManager {
|
|
|
66
93
|
|
|
67
94
|
public func deleteCookie(_ url: URL, _ key: String) {
|
|
68
95
|
let jar = HTTPCookieStorage.shared
|
|
69
|
-
let cookie = jar.cookies(for: url)?.first(where: { (cookie) -> Bool in
|
|
96
|
+
if let cookie = jar.cookies(for: url)?.first(where: { (cookie) -> Bool in
|
|
70
97
|
return cookie.name == key
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
}) {
|
|
99
|
+
jar.deleteCookie(cookie)
|
|
100
|
+
DispatchQueue.main.async {
|
|
101
|
+
WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
74
104
|
}
|
|
75
105
|
|
|
76
106
|
public func clearCookies(_ url: URL) {
|
|
77
107
|
let jar = HTTPCookieStorage.shared
|
|
78
|
-
jar.cookies(for: url)?.forEach({ (cookie) in
|
|
108
|
+
jar.cookies(for: url)?.forEach({ (cookie) in
|
|
109
|
+
jar.deleteCookie(cookie)
|
|
110
|
+
DispatchQueue.main.async {
|
|
111
|
+
WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
79
114
|
}
|
|
80
115
|
|
|
81
116
|
public func clearAllCookies() {
|
|
82
117
|
let jar = HTTPCookieStorage.shared
|
|
83
|
-
jar.cookies?.forEach({ (cookie) in
|
|
118
|
+
jar.cookies?.forEach({ (cookie) in
|
|
119
|
+
jar.deleteCookie(cookie)
|
|
120
|
+
DispatchQueue.main.async {
|
|
121
|
+
WKWebsiteDataStore.default().httpCookieStore.delete(cookie)
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public func syncCookiesToWebView() {
|
|
127
|
+
if let cookies = HTTPCookieStorage.shared.cookies {
|
|
128
|
+
for cookie in cookies {
|
|
129
|
+
DispatchQueue.main.async {
|
|
130
|
+
WKWebsiteDataStore.default()
|
|
131
|
+
.httpCookieStore
|
|
132
|
+
.setCookie(cookie, completionHandler: nil)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
}
|
|
84
137
|
}
|
|
85
138
|
}
|
|
@@ -9,7 +9,7 @@ public class CAPCookiesPlugin: CAPPlugin {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
@objc func getCookies(_ call: CAPPluginCall) {
|
|
12
|
-
guard let url = cookieManager!.getServerUrl(call) else { return call.reject("Invalid URL / Server URL")}
|
|
12
|
+
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid URL / Server URL")}
|
|
13
13
|
call.resolve(cookieManager!.getCookiesAsMap(url))
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -17,22 +17,23 @@ public class CAPCookiesPlugin: CAPPlugin {
|
|
|
17
17
|
guard let key = call.getString("key") else { return call.reject("Must provide key") }
|
|
18
18
|
guard let value = call.getString("value") else { return call.reject("Must provide value") }
|
|
19
19
|
|
|
20
|
-
let url = cookieManager!.getServerUrl(call)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid domain") }
|
|
21
|
+
|
|
22
|
+
let expires = call.getString("expires", "")
|
|
23
|
+
let path = call.getString("path", "")
|
|
24
|
+
cookieManager!.setCookie(url, key, cookieManager!.encode(value), expires, path)
|
|
25
|
+
call.resolve()
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
@objc func deleteCookie(_ call: CAPPluginCall) {
|
|
28
29
|
guard let key = call.getString("key") else { return call.reject("Must provide key") }
|
|
29
|
-
guard let url = cookieManager!.getServerUrl(call) else { return call.reject("Invalid URL / Server URL")}
|
|
30
|
+
guard let url = cookieManager!.getServerUrl(call.getString("url")) else { return call.reject("Invalid URL / Server URL")}
|
|
30
31
|
cookieManager!.deleteCookie(url, key)
|
|
31
32
|
call.resolve()
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
@objc func clearCookies(_ call: CAPPluginCall) {
|
|
35
|
-
let url = cookieManager!.getServerUrl(call)
|
|
36
|
+
let url = cookieManager!.getServerUrl(call.getString("url"))
|
|
36
37
|
if url != nil {
|
|
37
38
|
cookieManager!.clearCookies(url!)
|
|
38
39
|
call.resolve()
|
|
@@ -8,7 +8,7 @@ public class CAPHttpPlugin: CAPPlugin {
|
|
|
8
8
|
guard var _ = URL(string: url) else { return call.reject("Invalid URL"); }
|
|
9
9
|
|
|
10
10
|
do {
|
|
11
|
-
try HttpRequestHandler.request(call, httpMethod)
|
|
11
|
+
try HttpRequestHandler.request(call, httpMethod, self.bridge?.config)
|
|
12
12
|
} catch let error {
|
|
13
13
|
call.reject(error.localizedDescription)
|
|
14
14
|
}
|
|
@@ -97,6 +97,24 @@ class HttpRequestHandler {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
private static func setCookiesFromResponse(_ response: HTTPURLResponse, _ config: InstanceConfiguration?) {
|
|
101
|
+
let headers = response.allHeaderFields
|
|
102
|
+
if let cookies = headers["Set-Cookie"] as? String {
|
|
103
|
+
for cookie in cookies.components(separatedBy: ",") {
|
|
104
|
+
let domainComponents = cookie.lowercased().components(separatedBy: "domain=")
|
|
105
|
+
if domainComponents.count > 1 {
|
|
106
|
+
CapacitorCookieManager(config).setCookie(
|
|
107
|
+
domainComponents[1].components(separatedBy: ";")[0],
|
|
108
|
+
cookie
|
|
109
|
+
)
|
|
110
|
+
} else {
|
|
111
|
+
CapacitorCookieManager(config).setCookie("", cookie)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
CapacitorCookieManager(config).syncCookiesToWebView()
|
|
116
|
+
}
|
|
117
|
+
|
|
100
118
|
private static func buildResponse(_ data: Data?, _ response: HTTPURLResponse, responseType: ResponseType = .default) -> [String: Any] {
|
|
101
119
|
var output = [:] as [String: Any]
|
|
102
120
|
|
|
@@ -122,7 +140,7 @@ class HttpRequestHandler {
|
|
|
122
140
|
return output
|
|
123
141
|
}
|
|
124
142
|
|
|
125
|
-
public static func request(_ call: CAPPluginCall, _ httpMethod: String?) throws {
|
|
143
|
+
public static func request(_ call: CAPPluginCall, _ httpMethod: String?, _ config: InstanceConfiguration?) throws {
|
|
126
144
|
guard let urlString = call.getString("url") else { throw URLError(.badURL) }
|
|
127
145
|
let method = httpMethod ?? call.getString("method", "GET")
|
|
128
146
|
|
|
@@ -161,10 +179,13 @@ class HttpRequestHandler {
|
|
|
161
179
|
let urlSession = request.getUrlSession(call)
|
|
162
180
|
let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
|
|
163
181
|
urlSession.invalidateAndCancel()
|
|
182
|
+
|
|
164
183
|
if error != nil {
|
|
165
184
|
return
|
|
166
185
|
}
|
|
167
186
|
|
|
187
|
+
setCookiesFromResponse(response as! HTTPURLResponse, config)
|
|
188
|
+
|
|
168
189
|
let type = ResponseType(rawValue: responseType) ?? .default
|
|
169
190
|
call.resolve(self.buildResponse(data, response as! HTTPURLResponse, responseType: type))
|
|
170
191
|
}
|
|
@@ -256,9 +256,9 @@ internal class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDel
|
|
|
256
256
|
return
|
|
257
257
|
} else if type == "CapacitorCookies.set" {
|
|
258
258
|
// swiftlint:disable force_cast
|
|
259
|
-
let
|
|
260
|
-
let
|
|
261
|
-
CapacitorCookieManager(bridge!.config).setCookie(
|
|
259
|
+
let action = payload["action"] as! String
|
|
260
|
+
let domain = payload["domain"] as! String
|
|
261
|
+
CapacitorCookieManager(bridge!.config).setCookie(domain, action)
|
|
262
262
|
completionHandler("")
|
|
263
263
|
// swiftlint:enable force_cast
|
|
264
264
|
// Don't present prompt
|
|
@@ -311,25 +311,24 @@ const nativeBridge = (function (exports) {
|
|
|
311
311
|
},
|
|
312
312
|
set: function (val) {
|
|
313
313
|
const cookiePairs = val.split(';');
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
314
|
+
const domainSection = val.toLowerCase().split('domain=')[1];
|
|
315
|
+
const domain = cookiePairs.length > 1 &&
|
|
316
|
+
domainSection != null &&
|
|
317
|
+
domainSection.length > 0
|
|
318
|
+
? domainSection.split(';')[0].trim()
|
|
319
|
+
: '';
|
|
320
|
+
if (platform === 'ios') {
|
|
321
|
+
// Use prompt to synchronously set cookies.
|
|
322
|
+
// https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323
|
|
323
|
+
const payload = {
|
|
324
|
+
type: 'CapacitorCookies.set',
|
|
325
|
+
action: val,
|
|
326
|
+
domain,
|
|
327
|
+
};
|
|
328
|
+
prompt(JSON.stringify(payload));
|
|
329
|
+
}
|
|
330
|
+
else if (typeof win.CapacitorCookiesAndroidInterface !== 'undefined') {
|
|
331
|
+
win.CapacitorCookiesAndroidInterface.setCookie(domain, val);
|
|
333
332
|
}
|
|
334
333
|
},
|
|
335
334
|
});
|
|
@@ -426,7 +425,8 @@ const nativeBridge = (function (exports) {
|
|
|
426
425
|
};
|
|
427
426
|
// XHR patch abort
|
|
428
427
|
window.XMLHttpRequest.prototype.abort = function () {
|
|
429
|
-
if (this._url == null ||
|
|
428
|
+
if (this._url == null ||
|
|
429
|
+
!(this._url.startsWith('http:') || this._url.startsWith('https:'))) {
|
|
430
430
|
return win.CapacitorWebXMLHttpRequest.abort.call(this);
|
|
431
431
|
}
|
|
432
432
|
this.readyState = 0;
|
|
@@ -480,14 +480,16 @@ const nativeBridge = (function (exports) {
|
|
|
480
480
|
};
|
|
481
481
|
// XHR patch set request header
|
|
482
482
|
window.XMLHttpRequest.prototype.setRequestHeader = function (header, value) {
|
|
483
|
-
if (this._url == null ||
|
|
483
|
+
if (this._url == null ||
|
|
484
|
+
!(this._url.startsWith('http:') || this._url.startsWith('https:'))) {
|
|
484
485
|
return win.CapacitorWebXMLHttpRequest.setRequestHeader.call(this, header, value);
|
|
485
486
|
}
|
|
486
487
|
this._headers[header] = value;
|
|
487
488
|
};
|
|
488
489
|
// XHR patch send
|
|
489
490
|
window.XMLHttpRequest.prototype.send = function (body) {
|
|
490
|
-
if (this._url == null ||
|
|
491
|
+
if (this._url == null ||
|
|
492
|
+
!(this._url.startsWith('http:') || this._url.startsWith('https:'))) {
|
|
491
493
|
return win.CapacitorWebXMLHttpRequest.send.call(this, body);
|
|
492
494
|
}
|
|
493
495
|
try {
|
|
@@ -543,7 +545,8 @@ const nativeBridge = (function (exports) {
|
|
|
543
545
|
};
|
|
544
546
|
// XHR patch getAllResponseHeaders
|
|
545
547
|
window.XMLHttpRequest.prototype.getAllResponseHeaders = function () {
|
|
546
|
-
if (this._url == null ||
|
|
548
|
+
if (this._url == null ||
|
|
549
|
+
!(this._url.startsWith('http:') || this._url.startsWith('https:'))) {
|
|
547
550
|
return win.CapacitorWebXMLHttpRequest.getAllResponseHeaders.call(this);
|
|
548
551
|
}
|
|
549
552
|
let returnString = '';
|
|
@@ -556,7 +559,8 @@ const nativeBridge = (function (exports) {
|
|
|
556
559
|
};
|
|
557
560
|
// XHR patch getResponseHeader
|
|
558
561
|
window.XMLHttpRequest.prototype.getResponseHeader = function (name) {
|
|
559
|
-
if (this._url == null ||
|
|
562
|
+
if (this._url == null ||
|
|
563
|
+
!(this._url.startsWith('http:') || this._url.startsWith('https:'))) {
|
|
560
564
|
return win.CapacitorWebXMLHttpRequest.getResponseHeader.call(this, name);
|
|
561
565
|
}
|
|
562
566
|
return this._headers[name];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/ios",
|
|
3
|
-
"version": "4.5.0",
|
|
3
|
+
"version": "4.5.1-dev-20221117T024619.0",
|
|
4
4
|
"description": "Capacitor: Cross-platform apps with JavaScript and the web",
|
|
5
5
|
"homepage": "https://capacitorjs.com",
|
|
6
6
|
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .."
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@capacitor/core": "^4.
|
|
28
|
+
"@capacitor/core": "^4.5.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "6c509ade89ed4e09169bfd3d3a79fac2b9fe0c4d"
|
|
34
34
|
}
|