@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.
@@ -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 self.serverUrl != nil && self.serverUrl?.scheme != localUrl.scheme {
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 (isRelativeURL(this._url)) {
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 = method;
563
- if (isRelativeURL(url)) {
564
- return win.CapacitorWebXMLHttpRequest.open.call(this, method, url);
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 (isRelativeURL(this._url)) {
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 (isRelativeURL(this._url)) {
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 (isRelativeURL(this._url)) {
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 (isRelativeURL(this._url)) {
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.6.0",
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.6.0"
28
+ "@capacitor/core": "^5.7.0"
29
29
  },
30
30
  "publishConfig": {
31
31
  "access": "public"