@capacitor-plus/android 8.0.7 → 8.3.2
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/build.gradle +1 -1
- package/capacitor/src/main/assets/native-bridge.js +4 -0
- package/capacitor/src/main/java/com/getcapacitor/Bridge.java +2 -2
- package/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java +10 -4
- package/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +23 -8
- package/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java +103 -28
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java +45 -3
- package/package.json +3 -3
package/capacitor/build.gradle
CHANGED
|
@@ -53,7 +53,7 @@ android {
|
|
|
53
53
|
buildTypes {
|
|
54
54
|
release {
|
|
55
55
|
minifyEnabled false
|
|
56
|
-
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
56
|
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
lintOptions {
|
|
@@ -505,6 +505,10 @@ var nativeBridge = (function (exports) {
|
|
|
505
505
|
if (typeof resource === 'string') {
|
|
506
506
|
return await win.CapacitorWebFetch(createProxyUrl(resource, win), options);
|
|
507
507
|
}
|
|
508
|
+
else if (resource instanceof URL) {
|
|
509
|
+
const modifiedURL = new URL(createProxyUrl(resource.toString(), win));
|
|
510
|
+
return await win.CapacitorWebFetch(modifiedURL, options);
|
|
511
|
+
}
|
|
508
512
|
else if (resource instanceof Request) {
|
|
509
513
|
const modifiedRequest = new Request(createProxyUrl(resource.url, win), resource);
|
|
510
514
|
return await win.CapacitorWebFetch(modifiedRequest, options);
|
|
@@ -434,7 +434,7 @@ public class Bridge {
|
|
|
434
434
|
PackageManager pm = getContext().getPackageManager();
|
|
435
435
|
PackageInfo pInfo = InternalUtils.getPackageInfo(pm, getContext().getPackageName());
|
|
436
436
|
versionCode = Integer.toString((int) PackageInfoCompat.getLongVersionCode(pInfo));
|
|
437
|
-
versionName = pInfo.versionName;
|
|
437
|
+
versionName = pInfo.versionName != null ? pInfo.versionName : "";
|
|
438
438
|
} catch (Exception ex) {
|
|
439
439
|
Logger.error("Unable to get package info", ex);
|
|
440
440
|
}
|
|
@@ -628,11 +628,11 @@ public class Bridge {
|
|
|
628
628
|
try {
|
|
629
629
|
URL appUrlObject = new URL(appUrlConfig);
|
|
630
630
|
authorities.add(appUrlObject.getAuthority());
|
|
631
|
+
localUrl = appUrlObject.getProtocol() + "://" + appUrlObject.getAuthority();
|
|
631
632
|
} catch (Exception ex) {
|
|
632
633
|
Logger.error("Provided server url is invalid: " + ex.getMessage());
|
|
633
634
|
return;
|
|
634
635
|
}
|
|
635
|
-
localUrl = appUrlConfig;
|
|
636
636
|
appUrl = appUrlConfig;
|
|
637
637
|
} else {
|
|
638
638
|
appUrl = localUrl;
|
|
@@ -66,7 +66,9 @@ public class BridgeActivity extends AppCompatActivity {
|
|
|
66
66
|
@Override
|
|
67
67
|
public void onSaveInstanceState(Bundle outState) {
|
|
68
68
|
super.onSaveInstanceState(outState);
|
|
69
|
-
bridge
|
|
69
|
+
if (bridge != null) {
|
|
70
|
+
bridge.saveInstanceState(outState);
|
|
71
|
+
}
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
@Override
|
|
@@ -82,8 +84,10 @@ public class BridgeActivity extends AppCompatActivity {
|
|
|
82
84
|
@Override
|
|
83
85
|
public void onRestart() {
|
|
84
86
|
super.onRestart();
|
|
85
|
-
this.bridge
|
|
86
|
-
|
|
87
|
+
if (this.bridge != null) {
|
|
88
|
+
this.bridge.onRestart();
|
|
89
|
+
Logger.debug("App restarted");
|
|
90
|
+
}
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
@Override
|
|
@@ -131,7 +135,9 @@ public class BridgeActivity extends AppCompatActivity {
|
|
|
131
135
|
@Override
|
|
132
136
|
public void onDetachedFromWindow() {
|
|
133
137
|
super.onDetachedFromWindow();
|
|
134
|
-
this.bridge
|
|
138
|
+
if (this.bridge != null) {
|
|
139
|
+
this.bridge.onDetachedFromWindow();
|
|
140
|
+
}
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
/**
|
|
@@ -128,9 +128,22 @@ public class WebViewLocalServer {
|
|
|
128
128
|
return reasonPhrase;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* @deprecated This method may return incorrect headers in concurrent range requests.
|
|
133
|
+
* <p>
|
|
134
|
+
* Use {@link #buildDefaultResponseHeaders()} instead, which returns a copy of the map.
|
|
135
|
+
* </p>
|
|
136
|
+
* This method will be removed in a future major version of Capacitor.
|
|
137
|
+
* </p>
|
|
138
|
+
*/
|
|
139
|
+
@Deprecated(forRemoval = true) // adjust version as appropriate
|
|
131
140
|
public Map<String, String> getResponseHeaders() {
|
|
132
141
|
return responseHeaders;
|
|
133
142
|
}
|
|
143
|
+
|
|
144
|
+
public Map<String, String> buildDefaultResponseHeaders() {
|
|
145
|
+
return new HashMap<>(responseHeaders);
|
|
146
|
+
}
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
WebViewLocalServer(Context context, Bridge bridge, JSInjector jsInjector, ArrayList<String> authorities, boolean html5mode) {
|
|
@@ -326,14 +339,16 @@ public class WebViewLocalServer {
|
|
|
326
339
|
private WebResourceResponse handleLocalRequest(WebResourceRequest request, PathHandler handler) {
|
|
327
340
|
String path = request.getUrl().getPath();
|
|
328
341
|
|
|
329
|
-
|
|
342
|
+
Map<String, String> requestHeaders = request.getRequestHeaders();
|
|
343
|
+
String rangeString = requestHeaders.get("Range") != null ? requestHeaders.get("Range") : requestHeaders.get("range");
|
|
344
|
+
|
|
345
|
+
if (rangeString != null) {
|
|
330
346
|
InputStream responseStream = new LollipopLazyInputStream(handler, request);
|
|
331
347
|
String mimeType = getMimeType(path, responseStream);
|
|
332
|
-
Map<String, String> tempResponseHeaders = handler.
|
|
348
|
+
Map<String, String> tempResponseHeaders = handler.buildDefaultResponseHeaders();
|
|
333
349
|
int statusCode = 206;
|
|
334
350
|
try {
|
|
335
351
|
int totalRange = responseStream.available();
|
|
336
|
-
String rangeString = request.getRequestHeaders().get("Range");
|
|
337
352
|
String[] parts = rangeString.split("=");
|
|
338
353
|
String[] streamParts = parts[1].split("-");
|
|
339
354
|
String fromRange = streamParts[0];
|
|
@@ -365,7 +380,7 @@ public class WebViewLocalServer {
|
|
|
365
380
|
handler.getEncoding(),
|
|
366
381
|
statusCode,
|
|
367
382
|
handler.getReasonPhrase(),
|
|
368
|
-
handler.
|
|
383
|
+
handler.buildDefaultResponseHeaders(),
|
|
369
384
|
responseStream
|
|
370
385
|
);
|
|
371
386
|
}
|
|
@@ -376,7 +391,7 @@ public class WebViewLocalServer {
|
|
|
376
391
|
handler.getEncoding(),
|
|
377
392
|
handler.getStatusCode(),
|
|
378
393
|
handler.getReasonPhrase(),
|
|
379
|
-
handler.
|
|
394
|
+
handler.buildDefaultResponseHeaders(),
|
|
380
395
|
null
|
|
381
396
|
);
|
|
382
397
|
}
|
|
@@ -411,7 +426,7 @@ public class WebViewLocalServer {
|
|
|
411
426
|
handler.getEncoding(),
|
|
412
427
|
statusCode,
|
|
413
428
|
handler.getReasonPhrase(),
|
|
414
|
-
handler.
|
|
429
|
+
handler.buildDefaultResponseHeaders(),
|
|
415
430
|
responseStream
|
|
416
431
|
);
|
|
417
432
|
}
|
|
@@ -442,7 +457,7 @@ public class WebViewLocalServer {
|
|
|
442
457
|
handler.getEncoding(),
|
|
443
458
|
statusCode,
|
|
444
459
|
handler.getReasonPhrase(),
|
|
445
|
-
handler.
|
|
460
|
+
handler.buildDefaultResponseHeaders(),
|
|
446
461
|
responseStream
|
|
447
462
|
);
|
|
448
463
|
}
|
|
@@ -517,7 +532,7 @@ public class WebViewLocalServer {
|
|
|
517
532
|
handler.getEncoding(),
|
|
518
533
|
handler.getStatusCode(),
|
|
519
534
|
handler.getReasonPhrase(),
|
|
520
|
-
handler.
|
|
535
|
+
handler.buildDefaultResponseHeaders(),
|
|
521
536
|
responseStream
|
|
522
537
|
);
|
|
523
538
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
package com.getcapacitor.plugin;
|
|
2
2
|
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.content.pm.PackageInfo;
|
|
3
5
|
import android.content.res.Configuration;
|
|
6
|
+
import android.content.res.Resources;
|
|
4
7
|
import android.os.Build;
|
|
8
|
+
import android.util.TypedValue;
|
|
5
9
|
import android.view.View;
|
|
6
|
-
import android.view.ViewGroup;
|
|
7
10
|
import android.view.Window;
|
|
8
11
|
import android.webkit.JavascriptInterface;
|
|
9
12
|
import android.webkit.WebView;
|
|
@@ -12,6 +15,7 @@ import androidx.core.view.ViewCompat;
|
|
|
12
15
|
import androidx.core.view.WindowCompat;
|
|
13
16
|
import androidx.core.view.WindowInsetsCompat;
|
|
14
17
|
import androidx.core.view.WindowInsetsControllerCompat;
|
|
18
|
+
import androidx.webkit.WebViewCompat;
|
|
15
19
|
import com.getcapacitor.Plugin;
|
|
16
20
|
import com.getcapacitor.PluginCall;
|
|
17
21
|
import com.getcapacitor.PluginMethod;
|
|
@@ -31,6 +35,11 @@ public class SystemBars extends Plugin {
|
|
|
31
35
|
static final String INSETS_HANDLING_CSS = "css";
|
|
32
36
|
static final String INSETS_HANDLING_DISABLE = "disable";
|
|
33
37
|
|
|
38
|
+
// https://issues.chromium.org/issues/40699457
|
|
39
|
+
private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_FIX = 140;
|
|
40
|
+
// https://issues.chromium.org/issues/457682720
|
|
41
|
+
private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX = 144;
|
|
42
|
+
|
|
34
43
|
static final String viewportMetaJSFunction = """
|
|
35
44
|
function capacitorSystemBarsCheckMetaViewport() {
|
|
36
45
|
const meta = document.querySelectorAll("meta[name=viewport]");
|
|
@@ -47,6 +56,9 @@ public class SystemBars extends Plugin {
|
|
|
47
56
|
private boolean insetHandlingEnabled = true;
|
|
48
57
|
private boolean hasViewportCover = false;
|
|
49
58
|
|
|
59
|
+
private String currentStatusBarStyle = STYLE_DEFAULT;
|
|
60
|
+
private String currentGestureBarStyle = STYLE_DEFAULT;
|
|
61
|
+
|
|
50
62
|
@Override
|
|
51
63
|
public void load() {
|
|
52
64
|
getBridge().getWebView().addJavascriptInterface(this, "CapacitorSystemBarsAndroidInterface");
|
|
@@ -73,7 +85,9 @@ public class SystemBars extends Plugin {
|
|
|
73
85
|
@Override
|
|
74
86
|
protected void handleOnConfigurationChanged(Configuration newConfig) {
|
|
75
87
|
super.handleOnConfigurationChanged(newConfig);
|
|
76
|
-
|
|
88
|
+
|
|
89
|
+
setStyle(currentGestureBarStyle, BAR_GESTURE_BAR);
|
|
90
|
+
setStyle(currentStatusBarStyle, BAR_STATUS_BAR);
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
private void initSystemBars() {
|
|
@@ -86,7 +100,7 @@ public class SystemBars extends Plugin {
|
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
initWindowInsetsListener();
|
|
89
|
-
|
|
103
|
+
initSafeAreaCSSVariables();
|
|
90
104
|
|
|
91
105
|
getBridge().executeOnMainThread(() -> {
|
|
92
106
|
setStyle(style, "");
|
|
@@ -143,10 +157,13 @@ public class SystemBars extends Plugin {
|
|
|
143
157
|
|
|
144
158
|
private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
|
|
145
159
|
Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
|
|
160
|
+
if (insets.isVisible(WindowInsetsCompat.Type.ime())) {
|
|
161
|
+
return Insets.of(safeArea.left, safeArea.top, safeArea.right, 0);
|
|
162
|
+
}
|
|
146
163
|
return Insets.of(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom);
|
|
147
164
|
}
|
|
148
165
|
|
|
149
|
-
private void
|
|
166
|
+
private void initSafeAreaCSSVariables() {
|
|
150
167
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
|
|
151
168
|
View v = (View) this.getBridge().getWebView().getParent();
|
|
152
169
|
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
|
|
@@ -158,37 +175,59 @@ public class SystemBars extends Plugin {
|
|
|
158
175
|
}
|
|
159
176
|
|
|
160
177
|
private void initWindowInsetsListener() {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (hasViewportCover) {
|
|
164
|
-
Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
165
|
-
boolean keyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
|
|
178
|
+
ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
|
|
179
|
+
boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
|
|
166
180
|
|
|
167
|
-
|
|
168
|
-
|
|
181
|
+
Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
|
|
182
|
+
Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime());
|
|
183
|
+
boolean keyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
|
|
169
184
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
setViewMargins(v, Insets.NONE);
|
|
174
|
-
}
|
|
185
|
+
if (shouldPassthroughInsets) {
|
|
186
|
+
// We need to correct for a possible shown IME
|
|
187
|
+
v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
|
|
175
188
|
|
|
189
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
190
|
+
Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
176
191
|
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
177
|
-
return WindowInsetsCompat.CONSUMED;
|
|
178
192
|
}
|
|
179
193
|
|
|
180
|
-
return insets
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
194
|
+
return new WindowInsetsCompat.Builder(insets)
|
|
195
|
+
.setInsets(
|
|
196
|
+
WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(),
|
|
197
|
+
Insets.of(
|
|
198
|
+
systemBarsInsets.left,
|
|
199
|
+
systemBarsInsets.top,
|
|
200
|
+
systemBarsInsets.right,
|
|
201
|
+
getBottomInset(systemBarsInsets, keyboardVisible)
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
.build();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
208
|
+
// We need to correct for a possible shown IME
|
|
209
|
+
v.setPadding(
|
|
210
|
+
systemBarsInsets.left,
|
|
211
|
+
systemBarsInsets.top,
|
|
212
|
+
systemBarsInsets.right,
|
|
213
|
+
keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Returning `WindowInsetsCompat.CONSUMED` breaks recalculation of safe area insets
|
|
218
|
+
// So we have to explicitly set insets to `0`
|
|
219
|
+
// See: https://issues.chromium.org/issues/461332423
|
|
220
|
+
WindowInsetsCompat newInsets = new WindowInsetsCompat.Builder(insets)
|
|
221
|
+
.setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
|
|
222
|
+
.build();
|
|
184
223
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
224
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
225
|
+
Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
|
|
226
|
+
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return newInsets;
|
|
230
|
+
});
|
|
192
231
|
}
|
|
193
232
|
|
|
194
233
|
private void injectSafeAreaCSS(int top, int right, int bottom, int left) {
|
|
@@ -231,12 +270,16 @@ public class SystemBars extends Plugin {
|
|
|
231
270
|
Window window = getActivity().getWindow();
|
|
232
271
|
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView());
|
|
233
272
|
if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) {
|
|
273
|
+
currentStatusBarStyle = style;
|
|
234
274
|
windowInsetsControllerCompat.setAppearanceLightStatusBars(!style.equals(STYLE_DARK));
|
|
235
275
|
}
|
|
236
276
|
|
|
237
277
|
if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
|
|
278
|
+
currentGestureBarStyle = style;
|
|
238
279
|
windowInsetsControllerCompat.setAppearanceLightNavigationBars(!style.equals(STYLE_DARK));
|
|
239
280
|
}
|
|
281
|
+
|
|
282
|
+
getActivity().getWindow().getDecorView().setBackgroundColor(getThemeColor(getContext(), android.R.attr.windowBackground));
|
|
240
283
|
}
|
|
241
284
|
|
|
242
285
|
private void setHidden(boolean hide, String bar) {
|
|
@@ -268,4 +311,36 @@ public class SystemBars extends Plugin {
|
|
|
268
311
|
}
|
|
269
312
|
return STYLE_DARK;
|
|
270
313
|
}
|
|
314
|
+
|
|
315
|
+
public int getThemeColor(Context context, int attrRes) {
|
|
316
|
+
TypedValue typedValue = new TypedValue();
|
|
317
|
+
|
|
318
|
+
Resources.Theme theme = context.getTheme();
|
|
319
|
+
theme.resolveAttribute(attrRes, typedValue, true);
|
|
320
|
+
return typedValue.data;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private Integer getWebViewMajorVersion() {
|
|
324
|
+
PackageInfo info = WebViewCompat.getCurrentWebViewPackage(getContext());
|
|
325
|
+
if (info != null && info.versionName != null) {
|
|
326
|
+
String[] versionSegments = info.versionName.split("\\.");
|
|
327
|
+
return Integer.valueOf(versionSegments[0]);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return 0;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
private int getBottomInset(Insets systemBarsInsets, boolean keyboardVisible) {
|
|
334
|
+
if (getWebViewMajorVersion() < WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX) {
|
|
335
|
+
// This is a workaround for webview versions that have a bug
|
|
336
|
+
// that causes the bottom inset to be incorrect if the IME is visible
|
|
337
|
+
// See: https://issues.chromium.org/issues/457682720
|
|
338
|
+
|
|
339
|
+
if (keyboardVisible) {
|
|
340
|
+
return 0;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return systemBarsInsets.bottom;
|
|
345
|
+
}
|
|
271
346
|
}
|
package/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java
CHANGED
|
@@ -24,6 +24,7 @@ import java.util.Iterator;
|
|
|
24
24
|
import java.util.List;
|
|
25
25
|
import java.util.Locale;
|
|
26
26
|
import java.util.Map;
|
|
27
|
+
import java.util.UUID;
|
|
27
28
|
import javax.net.ssl.HttpsURLConnection;
|
|
28
29
|
import javax.net.ssl.SSLSocketFactory;
|
|
29
30
|
import org.json.JSONException;
|
|
@@ -224,7 +225,16 @@ public class CapacitorHttpUrlConnection implements ICapacitorHttpUrlConnection {
|
|
|
224
225
|
this.writeRequestBody(body.toString());
|
|
225
226
|
}
|
|
226
227
|
} else if (bodyType != null && bodyType.equals("formData")) {
|
|
227
|
-
|
|
228
|
+
String boundary = extractBoundaryFromContentType(contentType);
|
|
229
|
+
if (boundary == null) {
|
|
230
|
+
// If no boundary is provided, generate a random one and set the Content-Type header accordingly
|
|
231
|
+
// or otherwise servers will not be able to parse the request body. Browsers do this automatically
|
|
232
|
+
// but here we need to do this manually in order to comply with browser api behavior.
|
|
233
|
+
boundary = UUID.randomUUID().toString();
|
|
234
|
+
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
this.writeFormDataRequestBody(boundary, body.toJSArray());
|
|
228
238
|
} else {
|
|
229
239
|
this.writeRequestBody(body.toString());
|
|
230
240
|
}
|
|
@@ -260,9 +270,8 @@ public class CapacitorHttpUrlConnection implements ICapacitorHttpUrlConnection {
|
|
|
260
270
|
}
|
|
261
271
|
}
|
|
262
272
|
|
|
263
|
-
private void writeFormDataRequestBody(String
|
|
273
|
+
private void writeFormDataRequestBody(String boundary, JSArray entries) throws IOException, JSONException {
|
|
264
274
|
try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) {
|
|
265
|
-
String boundary = contentType.split(";")[1].split("=")[1];
|
|
266
275
|
String lineEnd = "\r\n";
|
|
267
276
|
String twoHyphens = "--";
|
|
268
277
|
|
|
@@ -303,6 +312,39 @@ public class CapacitorHttpUrlConnection implements ICapacitorHttpUrlConnection {
|
|
|
303
312
|
}
|
|
304
313
|
}
|
|
305
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Extracts the boundary value from the `Content-Type` header for multipart/form-data requests, if provided.
|
|
317
|
+
*
|
|
318
|
+
* The boundary value might be surrounded by double quotes (") which will be stripped away.
|
|
319
|
+
*
|
|
320
|
+
* @param contentType The `Content-Type` header string.
|
|
321
|
+
* @return The boundary value if found, otherwise `null`.
|
|
322
|
+
*/
|
|
323
|
+
public static String extractBoundaryFromContentType(String contentType) {
|
|
324
|
+
String boundaryPrefix = "boundary=";
|
|
325
|
+
int boundaryIndex = contentType.indexOf(boundaryPrefix);
|
|
326
|
+
if (boundaryIndex == -1) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Extract the substring starting right after "boundary="
|
|
331
|
+
String boundary = contentType.substring(boundaryIndex + boundaryPrefix.length());
|
|
332
|
+
|
|
333
|
+
// Find the end of the boundary value by looking for the next ";"
|
|
334
|
+
int endIndex = boundary.indexOf(";");
|
|
335
|
+
if (endIndex != -1) {
|
|
336
|
+
boundary = boundary.substring(0, endIndex);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Remove surrounding double quotes if present
|
|
340
|
+
boundary = boundary.trim();
|
|
341
|
+
if (boundary.startsWith("\"") && boundary.endsWith("\"")) {
|
|
342
|
+
boundary = boundary.substring(1, boundary.length() - 1);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return boundary;
|
|
346
|
+
}
|
|
347
|
+
|
|
306
348
|
/**
|
|
307
349
|
* Opens a communications link to the resource referenced by this
|
|
308
350
|
* URL, if such a connection has not already been established.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor-plus/android",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.2",
|
|
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)",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"verify": "./gradlew clean lint build test -b capacitor/build.gradle"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@capacitor-plus/core": "^8.
|
|
27
|
-
"@capacitor/core": "^8.
|
|
26
|
+
"@capacitor-plus/core": "^8.3.0",
|
|
27
|
+
"@capacitor/core": "^8.3.0"
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|