@capacitor/ios 5.6.0 → 5.7.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.
- package/Capacitor/Capacitor/CapacitorBridge.swift +2 -0
- package/Capacitor/Capacitor/Plugins/DefaultPlugins.m +1 -0
- package/Capacitor/Capacitor/Plugins/WebView.swift +7 -0
- package/Capacitor/Capacitor/WebViewAssetHandler.swift +79 -3
- package/Capacitor/Capacitor/assets/native-bridge.js +49 -9
- package/package.json +2 -2
|
@@ -90,6 +90,8 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol {
|
|
|
90
90
|
static let tmpVCAppeared = Notification(name: Notification.Name(rawValue: "tmpViewControllerAppeared"))
|
|
91
91
|
public static let capacitorSite = "https://capacitorjs.com/"
|
|
92
92
|
public static let fileStartIdentifier = "/_capacitor_file_"
|
|
93
|
+
public static let httpInterceptorStartIdentifier = "/_capacitor_http_interceptor_"
|
|
94
|
+
public static let httpsInterceptorStartIdentifier = "/_capacitor_https_interceptor_"
|
|
93
95
|
public static let defaultScheme = "capacitor"
|
|
94
96
|
|
|
95
97
|
var webViewAssetHandler: WebViewAssetHandler
|
|
@@ -24,6 +24,7 @@ CAP_PLUGIN(CAPConsolePlugin, "Console",
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
CAP_PLUGIN(CAPWebViewPlugin, "WebView",
|
|
27
|
+
CAP_PLUGIN_METHOD(setServerAssetPath, CAPPluginReturnPromise);
|
|
27
28
|
CAP_PLUGIN_METHOD(setServerBasePath, CAPPluginReturnPromise);
|
|
28
29
|
CAP_PLUGIN_METHOD(getServerBasePath, CAPPluginReturnPromise);
|
|
29
30
|
CAP_PLUGIN_METHOD(persistServerBasePath, CAPPluginReturnPromise);
|
|
@@ -3,6 +3,13 @@ import Foundation
|
|
|
3
3
|
@objc(CAPWebViewPlugin)
|
|
4
4
|
public class CAPWebViewPlugin: CAPPlugin {
|
|
5
5
|
|
|
6
|
+
@objc func setServerAssetPath(_ call: CAPPluginCall) {
|
|
7
|
+
if let path = call.getString("path"), let viewController = bridge?.viewController as? CAPBridgeViewController {
|
|
8
|
+
viewController.setServerBasePath(path: Bundle.main.url(forResource: path, withExtension: nil)?.path ?? path)
|
|
9
|
+
call.resolve()
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
@objc func setServerBasePath(_ call: CAPPluginCall) {
|
|
7
14
|
if let path = call.getString("path"), let viewController = bridge?.viewController as? CAPBridgeViewController {
|
|
8
15
|
viewController.setServerBasePath(path: path)
|
|
@@ -20,10 +20,25 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
|
|
|
20
20
|
self.serverUrl = serverUrl
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
private func isUsingLiveReload(_ localUrl: URL) -> Bool {
|
|
24
|
+
return self.serverUrl != nil && self.serverUrl?.scheme != localUrl.scheme
|
|
25
|
+
}
|
|
26
|
+
|
|
23
27
|
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
|
|
24
28
|
let startPath: String
|
|
25
29
|
let url = urlSchemeTask.request.url!
|
|
26
30
|
let stringToLoad = url.path
|
|
31
|
+
let localUrl = URL.init(string: url.absoluteString)!
|
|
32
|
+
|
|
33
|
+
if url.path.starts(with: CapacitorBridge.httpInterceptorStartIdentifier) {
|
|
34
|
+
handleCapacitorHttpRequest(urlSchemeTask, localUrl, false)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if url.path.starts(with: CapacitorBridge.httpsInterceptorStartIdentifier) {
|
|
39
|
+
handleCapacitorHttpRequest(urlSchemeTask, localUrl, true)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
27
42
|
|
|
28
43
|
if stringToLoad.starts(with: CapacitorBridge.fileStartIdentifier) {
|
|
29
44
|
startPath = stringToLoad.replacingOccurrences(of: CapacitorBridge.fileStartIdentifier, with: "")
|
|
@@ -31,7 +46,6 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
|
|
|
31
46
|
startPath = router.route(for: stringToLoad)
|
|
32
47
|
}
|
|
33
48
|
|
|
34
|
-
let localUrl = URL.init(string: url.absoluteString)!
|
|
35
49
|
let fileUrl = URL.init(fileURLWithPath: startPath)
|
|
36
50
|
|
|
37
51
|
do {
|
|
@@ -43,9 +57,9 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
|
|
|
43
57
|
]
|
|
44
58
|
|
|
45
59
|
// if using live reload, then set CORS headers
|
|
46
|
-
if
|
|
60
|
+
if isUsingLiveReload(localUrl) {
|
|
47
61
|
headers["Access-Control-Allow-Origin"] = self.serverUrl?.absoluteString
|
|
48
|
-
headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
|
|
62
|
+
headers["Access-Control-Allow-Methods"] = "GET, HEAD, OPTIONS, TRACE"
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
if let rangeString = urlSchemeTask.request.value(forHTTPHeaderField: "Range"),
|
|
@@ -121,6 +135,68 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler {
|
|
|
121
135
|
return false
|
|
122
136
|
}
|
|
123
137
|
|
|
138
|
+
func handleCapacitorHttpRequest(_ urlSchemeTask: WKURLSchemeTask, _ localUrl: URL, _ isHttpsRequest: Bool) {
|
|
139
|
+
var urlRequest = urlSchemeTask.request
|
|
140
|
+
guard let url = urlRequest.url else { return }
|
|
141
|
+
var targetUrl = url.absoluteString
|
|
142
|
+
.replacingOccurrences(of: CapacitorBridge.httpInterceptorStartIdentifier, with: "")
|
|
143
|
+
.replacingOccurrences(of: CapacitorBridge.httpsInterceptorStartIdentifier, with: "")
|
|
144
|
+
// Only replace first occurrence of the scheme
|
|
145
|
+
if let range = targetUrl.range(of: localUrl.scheme ?? InstanceDescriptorDefaults.scheme) {
|
|
146
|
+
targetUrl = targetUrl.replacingCharacters(in: range, with: isHttpsRequest ? "https" : "http")
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Only replace first occurrence of the hostname
|
|
150
|
+
if let range = targetUrl.range(of: (localUrl.host ?? InstanceDescriptorDefaults.hostname) + "/") {
|
|
151
|
+
targetUrl = targetUrl.replacingCharacters(in: range, with: "")
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
urlRequest.url = URL(string: targetUrl.removingPercentEncoding ?? targetUrl)
|
|
155
|
+
|
|
156
|
+
let urlSession = URLSession.shared
|
|
157
|
+
let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
|
|
158
|
+
if let error = error {
|
|
159
|
+
urlSchemeTask.didFailWithError(error)
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if let response = response as? HTTPURLResponse {
|
|
164
|
+
let existingHeaders = response.allHeaderFields
|
|
165
|
+
var newHeaders: [AnyHashable: Any] = [:]
|
|
166
|
+
|
|
167
|
+
// if using live reload, then set CORS headers
|
|
168
|
+
if self.isUsingLiveReload(url) {
|
|
169
|
+
newHeaders = [
|
|
170
|
+
"Access-Control-Allow-Origin": self.serverUrl?.absoluteString ?? "",
|
|
171
|
+
"Access-Control-Allow-Methods": "GET, HEAD, OPTIONS, TRACE"
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if let mergedHeaders = existingHeaders.merging(newHeaders, uniquingKeysWith: { (current, _) in current }) as? [String: String] {
|
|
176
|
+
|
|
177
|
+
if let responseUrl = response.url {
|
|
178
|
+
if let modifiedResponse = HTTPURLResponse(
|
|
179
|
+
url: responseUrl,
|
|
180
|
+
statusCode: response.statusCode,
|
|
181
|
+
httpVersion: nil,
|
|
182
|
+
headerFields: mergedHeaders
|
|
183
|
+
) {
|
|
184
|
+
urlSchemeTask.didReceive(modifiedResponse)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if let data = data {
|
|
189
|
+
urlSchemeTask.didReceive(data)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
urlSchemeTask.didFinish()
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
task.resume()
|
|
198
|
+
}
|
|
199
|
+
|
|
124
200
|
let mimeTypes = [
|
|
125
201
|
"aaf": "application/octet-stream",
|
|
126
202
|
"aca": "application/octet-stream",
|
|
@@ -130,6 +130,26 @@ var nativeBridge = (function (exports) {
|
|
|
130
130
|
}
|
|
131
131
|
return { data: body, type: 'json' };
|
|
132
132
|
};
|
|
133
|
+
const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_';
|
|
134
|
+
const CAPACITOR_HTTPS_INTERCEPTOR = '/_capacitor_https_interceptor_';
|
|
135
|
+
// TODO: export as Cap function
|
|
136
|
+
const isRelativeOrProxyUrl = (url) => !url ||
|
|
137
|
+
!(url.startsWith('http:') || url.startsWith('https:')) ||
|
|
138
|
+
url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1 ||
|
|
139
|
+
url.indexOf(CAPACITOR_HTTPS_INTERCEPTOR) > -1;
|
|
140
|
+
// TODO: export as Cap function
|
|
141
|
+
const createProxyUrl = (url, win) => {
|
|
142
|
+
var _a, _b;
|
|
143
|
+
if (isRelativeOrProxyUrl(url))
|
|
144
|
+
return url;
|
|
145
|
+
let proxyUrl = new URL(url);
|
|
146
|
+
const isHttps = proxyUrl.protocol === 'https:';
|
|
147
|
+
const originalHost = encodeURIComponent(proxyUrl.host);
|
|
148
|
+
const originalPathname = proxyUrl.pathname;
|
|
149
|
+
proxyUrl = new URL((_b = (_a = win.Capacitor) === null || _a === void 0 ? void 0 : _a.getServerUrl()) !== null && _b !== void 0 ? _b : '');
|
|
150
|
+
proxyUrl.pathname = `${isHttps ? CAPACITOR_HTTPS_INTERCEPTOR : CAPACITOR_HTTP_INTERCEPTOR}/${originalHost}${originalPathname}`;
|
|
151
|
+
return proxyUrl.toString();
|
|
152
|
+
};
|
|
133
153
|
const initBridge = (w) => {
|
|
134
154
|
const getPlatformId = (win) => {
|
|
135
155
|
var _a, _b;
|
|
@@ -279,6 +299,10 @@ var nativeBridge = (function (exports) {
|
|
|
279
299
|
callback(result.path);
|
|
280
300
|
});
|
|
281
301
|
};
|
|
302
|
+
IonicWebView.setServerAssetPath = (path) => {
|
|
303
|
+
var _a;
|
|
304
|
+
(_a = Plugins === null || Plugins === void 0 ? void 0 : Plugins.WebView) === null || _a === void 0 ? void 0 : _a.setServerAssetPath({ path });
|
|
305
|
+
};
|
|
282
306
|
IonicWebView.setServerBasePath = (path) => {
|
|
283
307
|
var _a;
|
|
284
308
|
(_a = Plugins === null || Plugins === void 0 ? void 0 : Plugins.WebView) === null || _a === void 0 ? void 0 : _a.setServerBasePath({ path });
|
|
@@ -472,6 +496,15 @@ var nativeBridge = (function (exports) {
|
|
|
472
496
|
if (request.url.startsWith(`${cap.getServerUrl()}/`)) {
|
|
473
497
|
return win.CapacitorWebFetch(resource, options);
|
|
474
498
|
}
|
|
499
|
+
if (!(options === null || options === void 0 ? void 0 : options.method) ||
|
|
500
|
+
options.method.toLocaleUpperCase() === 'GET' ||
|
|
501
|
+
options.method.toLocaleUpperCase() === 'HEAD' ||
|
|
502
|
+
options.method.toLocaleUpperCase() === 'OPTIONS' ||
|
|
503
|
+
options.method.toLocaleUpperCase() === 'TRACE') {
|
|
504
|
+
const modifiedResource = createProxyUrl(resource.toString(), win);
|
|
505
|
+
const response = await win.CapacitorWebFetch(modifiedResource, options);
|
|
506
|
+
return response;
|
|
507
|
+
}
|
|
475
508
|
const tag = `CapacitorHttp fetch ${Date.now()} ${resource}`;
|
|
476
509
|
console.time(tag);
|
|
477
510
|
try {
|
|
@@ -542,12 +575,11 @@ var nativeBridge = (function (exports) {
|
|
|
542
575
|
});
|
|
543
576
|
xhr.readyState = 0;
|
|
544
577
|
const prototype = win.CapacitorWebXMLHttpRequest.prototype;
|
|
545
|
-
const isRelativeURL = (url) => !url || !(url.startsWith('http:') || url.startsWith('https:'));
|
|
546
578
|
const isProgressEventAvailable = () => typeof ProgressEvent !== 'undefined' &&
|
|
547
579
|
ProgressEvent.prototype instanceof Event;
|
|
548
580
|
// XHR patch abort
|
|
549
581
|
prototype.abort = function () {
|
|
550
|
-
if (
|
|
582
|
+
if (isRelativeOrProxyUrl(this._url)) {
|
|
551
583
|
return win.CapacitorWebXMLHttpRequest.abort.call(this);
|
|
552
584
|
}
|
|
553
585
|
this.readyState = 0;
|
|
@@ -558,10 +590,18 @@ var nativeBridge = (function (exports) {
|
|
|
558
590
|
};
|
|
559
591
|
// XHR patch open
|
|
560
592
|
prototype.open = function (method, url) {
|
|
593
|
+
this._method = method.toLocaleUpperCase();
|
|
561
594
|
this._url = url;
|
|
562
|
-
this._method
|
|
563
|
-
|
|
564
|
-
|
|
595
|
+
if (!this._method ||
|
|
596
|
+
this._method === 'GET' ||
|
|
597
|
+
this._method === 'HEAD' ||
|
|
598
|
+
this._method === 'OPTIONS' ||
|
|
599
|
+
this._method === 'TRACE') {
|
|
600
|
+
if (isRelativeOrProxyUrl(url)) {
|
|
601
|
+
return win.CapacitorWebXMLHttpRequest.open.call(this, method, url);
|
|
602
|
+
}
|
|
603
|
+
this._url = createProxyUrl(this._url, win);
|
|
604
|
+
return win.CapacitorWebXMLHttpRequest.open.call(this, method, this._url);
|
|
565
605
|
}
|
|
566
606
|
setTimeout(() => {
|
|
567
607
|
this.dispatchEvent(new Event('loadstart'));
|
|
@@ -570,14 +610,14 @@ var nativeBridge = (function (exports) {
|
|
|
570
610
|
};
|
|
571
611
|
// XHR patch set request header
|
|
572
612
|
prototype.setRequestHeader = function (header, value) {
|
|
573
|
-
if (
|
|
613
|
+
if (isRelativeOrProxyUrl(this._url)) {
|
|
574
614
|
return win.CapacitorWebXMLHttpRequest.setRequestHeader.call(this, header, value);
|
|
575
615
|
}
|
|
576
616
|
this._headers[header] = value;
|
|
577
617
|
};
|
|
578
618
|
// XHR patch send
|
|
579
619
|
prototype.send = function (body) {
|
|
580
|
-
if (
|
|
620
|
+
if (isRelativeOrProxyUrl(this._url)) {
|
|
581
621
|
return win.CapacitorWebXMLHttpRequest.send.call(this, body);
|
|
582
622
|
}
|
|
583
623
|
const tag = `CapacitorHttp XMLHttpRequest ${Date.now()} ${this._url}`;
|
|
@@ -706,7 +746,7 @@ var nativeBridge = (function (exports) {
|
|
|
706
746
|
};
|
|
707
747
|
// XHR patch getAllResponseHeaders
|
|
708
748
|
prototype.getAllResponseHeaders = function () {
|
|
709
|
-
if (
|
|
749
|
+
if (isRelativeOrProxyUrl(this._url)) {
|
|
710
750
|
return win.CapacitorWebXMLHttpRequest.getAllResponseHeaders.call(this);
|
|
711
751
|
}
|
|
712
752
|
let returnString = '';
|
|
@@ -719,7 +759,7 @@ var nativeBridge = (function (exports) {
|
|
|
719
759
|
};
|
|
720
760
|
// XHR patch getResponseHeader
|
|
721
761
|
prototype.getResponseHeader = function (name) {
|
|
722
|
-
if (
|
|
762
|
+
if (isRelativeOrProxyUrl(this._url)) {
|
|
723
763
|
return win.CapacitorWebXMLHttpRequest.getResponseHeader.call(this, name);
|
|
724
764
|
}
|
|
725
765
|
for (const key in this._headers) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/ios",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.1",
|
|
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,7 +25,7 @@
|
|
|
25
25
|
"xc:build:CapacitorCordova": "cd CapacitorCordova && xcodebuild && cd .."
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@capacitor/core": "^5.
|
|
28
|
+
"@capacitor/core": "^5.7.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|