@capacitor-plus/ios 8.3.9 → 8.3.11

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.
@@ -10,6 +10,12 @@ import Cordova
10
10
 
11
11
  public fileprivate(set) var webView: WKWebView?
12
12
 
13
+ // WKHTTPCookieStore does not retain observers, so we hold a strong reference here
14
+ // (else it deallocs immediately and `cookiesDidChange` never fires) plus the store
15
+ // it was added to, so the observer can be removed in `deinit` as the docs require.
16
+ private var cookieObserver: CapacitorWKCookieObserver?
17
+ private weak var cookieObserverStore: WKHTTPCookieStore?
18
+
13
19
  public var isStatusBarVisible = true
14
20
  public var statusBarStyle: UIStatusBarStyle = .default
15
21
  public var statusBarAnimation: UIStatusBarAnimation = .fade
@@ -27,6 +33,12 @@ import Cordova
27
33
  return false
28
34
  }()
29
35
 
36
+ deinit {
37
+ if let cookieObserver = cookieObserver {
38
+ cookieObserverStore?.remove(cookieObserver)
39
+ }
40
+ }
41
+
30
42
  override public final func loadView() {
31
43
  // load the configuration and set the logging flag
32
44
  let configDescriptor = instanceDescriptor()
@@ -118,7 +130,11 @@ import Cordova
118
130
  */
119
131
  open func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
120
132
  let webViewConfiguration = WKWebViewConfiguration()
121
- webViewConfiguration.websiteDataStore.httpCookieStore.add(CapacitorWKCookieObserver())
133
+ let cookieObserver = CapacitorWKCookieObserver()
134
+ let cookieStore = webViewConfiguration.websiteDataStore.httpCookieStore
135
+ cookieStore.add(cookieObserver)
136
+ self.cookieObserver = cookieObserver
137
+ self.cookieObserverStore = cookieStore
122
138
  webViewConfiguration.allowsInlineMediaPlayback = true
123
139
  webViewConfiguration.suppressesIncrementalRendering = false
124
140
  webViewConfiguration.allowsAirPlayForMediaPlayback = true
@@ -13,6 +13,7 @@ NS_SWIFT_NAME(InstanceConfiguration)
13
13
  @property (nonatomic, readonly, nonnull) NSArray<NSString*> *allowedNavigationHostnames;
14
14
  @property (nonatomic, readonly, nonnull) NSURL *localURL;
15
15
  @property (nonatomic, readonly, nonnull) NSURL *serverURL;
16
+ @property (nonatomic, readonly, nullable) NSURL *configURL;
16
17
  @property (nonatomic, readonly, nullable) NSString *errorPath;
17
18
  @property (nonatomic, readonly, nonnull) NSDictionary *pluginConfigurations;
18
19
  @property (nonatomic, readonly) BOOL loggingEnabled;
@@ -49,6 +49,13 @@
49
49
  else {
50
50
  _serverURL = _localURL;
51
51
  }
52
+
53
+ if (descriptor.configUrl != nil) {
54
+ _configURL = descriptor.configUrl;
55
+ }
56
+ else {
57
+ _configURL = [[NSURL alloc] initWithString:(@"capacitor.config.json")];
58
+ }
52
59
  _errorPath = descriptor.errorPath;
53
60
  // extract the one value we care about from the cordova configuration
54
61
  _cordovaDeployDisabled = [descriptor cordovaDeployDisabled];
@@ -68,6 +68,11 @@ NS_SWIFT_NAME(InstanceDescriptor)
68
68
  @discussion Defaults to nil, in which case the server URL will be constructed from @c urlScheme and @c urlHostname. If set, it will override the other properties. Set by @c server.url in the configuration file.
69
69
  */
70
70
  @property (nonatomic, copy, nullable) NSString *serverURL;
71
+ /**
72
+ @brief The file URL from which Capacitor will load configuration
73
+ @discussion Defaults to @c capacitor.config.json located at the root of the application bundle.
74
+ */
75
+ @property (nonatomic, copy, nullable) NSURL *configUrl;
71
76
  /**
72
77
  @brief The JSON dictionary that contains the plugin-specific configuration information.
73
78
  @discussion Set by @c plugins in the configuration file.
@@ -30,6 +30,8 @@ internal extension InstanceDescriptor {
30
30
  // swiftlint:disable function_body_length
31
31
  // swiftlint:disable:next identifier_name
32
32
  @objc func _parseConfiguration(at capacitorURL: URL?, cordovaConfiguration cordovaURL: URL?) {
33
+ configUrl = capacitorURL
34
+
33
35
  // sanity check that the app directory is valid
34
36
  var isDirectory: ObjCBool = ObjCBool(false)
35
37
  if warnings.contains(.missingAppDir) == false,
@@ -305,9 +305,9 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol {
305
305
  func registerPlugins() {
306
306
  var pluginList: [AnyClass] = [CAPHttpPlugin.self, CAPConsolePlugin.self, CAPWebViewPlugin.self, CAPCookiesPlugin.self, CAPSystemBarsPlugin.self]
307
307
 
308
- if autoRegisterPlugins {
308
+ if autoRegisterPlugins && config.configURL != nil {
309
309
  do {
310
- if let pluginJSON = Bundle.main.url(forResource: "capacitor.config", withExtension: "json") {
310
+ if let pluginJSON = Bundle.main.url(forResource: (config.configURL!.path as NSString).deletingPathExtension, withExtension: "json") {
311
311
  let pluginData = try Data(contentsOf: pluginJSON)
312
312
  let registrationList = try JSONDecoder().decode(RegistrationList.self, from: pluginData)
313
313
 
@@ -172,7 +172,7 @@ open class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {
172
172
  }
173
173
 
174
174
  public func getRequestData(_ body: JSValue, _ contentType: String, _ dataType: String? = nil) throws -> Data? {
175
- if dataType == "file" {
175
+ if dataType == "file" || dataType == "binary" {
176
176
  guard let stringData = body as? String else {
177
177
  throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as string")
178
178
  }
@@ -44,6 +44,33 @@ var nativeBridge = (function (exports) {
44
44
  reader.onerror = reject;
45
45
  reader.readAsBinaryString(file);
46
46
  });
47
+ const readArrayBufferAsBase64 = (arrayBuffer) => {
48
+ const bytes = new Uint8Array(arrayBuffer);
49
+ const chunkSize = 0x8000;
50
+ let binary = '';
51
+ for (let i = 0; i < bytes.length; i += chunkSize) {
52
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
53
+ }
54
+ return btoa(binary);
55
+ };
56
+ const readBlobAsBase64 = (blob) => new Promise((resolve, reject) => {
57
+ const reader = new FileReader();
58
+ reader.onload = () => {
59
+ const result = reader.result;
60
+ resolve(result.indexOf(',') >= 0 ? result.split(',')[1] : result);
61
+ };
62
+ reader.onerror = reject;
63
+ reader.readAsDataURL(blob);
64
+ });
65
+ const readDataViewAsBase64 = (dataView) => readArrayBufferAsBase64(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength));
66
+ const base64StringToArrayBuffer = (base64) => {
67
+ const binary = atob(base64);
68
+ const bytes = new Uint8Array(binary.length);
69
+ for (let i = 0; i < binary.length; i++) {
70
+ bytes[i] = binary.charCodeAt(i);
71
+ }
72
+ return bytes.buffer;
73
+ };
47
74
  const convertFormData = async (formData) => {
48
75
  const newFormData = [];
49
76
  for (const pair of formData.entries()) {
@@ -65,9 +92,38 @@ var nativeBridge = (function (exports) {
65
92
  return newFormData;
66
93
  };
67
94
  const convertBody = async (body, contentType) => {
68
- if (body instanceof ReadableStream || body instanceof Uint8Array) {
95
+ if (body instanceof File) {
96
+ const fileData = await readFileAsBase64(body);
97
+ return {
98
+ data: fileData,
99
+ type: 'file',
100
+ headers: { 'Content-Type': body.type },
101
+ };
102
+ }
103
+ else if (body instanceof Blob) {
104
+ return {
105
+ data: await readBlobAsBase64(body),
106
+ type: 'binary',
107
+ headers: { 'Content-Type': contentType || body.type || 'application/octet-stream' },
108
+ };
109
+ }
110
+ else if (body instanceof ArrayBuffer) {
111
+ return {
112
+ data: readArrayBufferAsBase64(body),
113
+ type: 'binary',
114
+ headers: { 'Content-Type': contentType || 'application/octet-stream' },
115
+ };
116
+ }
117
+ else if (ArrayBuffer.isView(body)) {
118
+ return {
119
+ data: readDataViewAsBase64(body),
120
+ type: 'binary',
121
+ headers: { 'Content-Type': contentType || 'application/octet-stream' },
122
+ };
123
+ }
124
+ if ((typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) || body instanceof Uint8Array) {
69
125
  let encodedData;
70
- if (body instanceof ReadableStream) {
126
+ if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {
71
127
  const reader = body.getReader();
72
128
  const chunks = [];
73
129
  while (true) {
@@ -87,7 +143,9 @@ var nativeBridge = (function (exports) {
87
143
  else {
88
144
  encodedData = body;
89
145
  }
90
- let data = new TextDecoder().decode(encodedData);
146
+ let data = (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('image')) || contentType === 'application/octet-stream'
147
+ ? readDataViewAsBase64(encodedData)
148
+ : new TextDecoder().decode(encodedData);
91
149
  let type;
92
150
  if (contentType === 'application/json') {
93
151
  try {
@@ -102,7 +160,7 @@ var nativeBridge = (function (exports) {
102
160
  type = 'formData';
103
161
  }
104
162
  else if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('image')) {
105
- type = 'image';
163
+ type = 'binary';
106
164
  }
107
165
  else if (contentType === 'application/octet-stream') {
108
166
  type = 'binary';
@@ -128,14 +186,6 @@ var nativeBridge = (function (exports) {
128
186
  type: 'formData',
129
187
  };
130
188
  }
131
- else if (body instanceof Blob) {
132
- const fileData = await readFileAsBase64(body);
133
- return {
134
- data: fileData,
135
- type: 'file',
136
- headers: { 'Content-Type': body.type },
137
- };
138
- }
139
189
  return { data: body, type: 'json' };
140
190
  };
141
191
  const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_';
@@ -535,15 +585,15 @@ var nativeBridge = (function (exports) {
535
585
  data: requestData,
536
586
  dataType: type,
537
587
  headers: nativeHeaders,
588
+ responseType: 'arraybuffer',
538
589
  });
539
590
  const contentType = nativeResponse.headers['Content-Type'] || nativeResponse.headers['content-type'];
540
- let data = (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('application/json'))
541
- ? JSON.stringify(nativeResponse.data)
542
- : nativeResponse.data;
543
591
  // use null data for 204 No Content HTTP response
544
- if (nativeResponse.status === 204) {
545
- data = null;
546
- }
592
+ const data = nativeResponse.status === 204
593
+ ? null
594
+ : (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('application/json'))
595
+ ? JSON.stringify(nativeResponse.data)
596
+ : base64StringToArrayBuffer(nativeResponse.data);
547
597
  // intercept & parse response before returning
548
598
  const response = new Response(data, {
549
599
  headers: nativeResponse.headers,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor-plus/ios",
3
- "version": "8.3.9",
3
+ "version": "8.3.11",
4
4
  "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
5
5
  "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
6
6
  "author": "Capgo Team <support@capgo.app> (https://capgo.app)",