Skip to content

Commit ce56a1d

Browse files
authored
Merge branch 'main' into catsjuice/fix/missing-xhr-prototype
2 parents c55392c + 17fe053 commit ce56a1d

26 files changed

+268
-29
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
# [7.1.0](https://github.com/ionic-team/capacitor/compare/7.0.1...7.1.0) (2025-03-12)
7+
8+
### Bug Fixes
9+
10+
- **android:** add EdgeToEdge compatibility ([#7871](https://github.com/ionic-team/capacitor/issues/7871)) ([64a8bc4](https://github.com/ionic-team/capacitor/commit/64a8bc40de2522c75a94a40cba6c8ccd82481cb8))
11+
- **android:** sanitize portable file name ([#7894](https://github.com/ionic-team/capacitor/issues/7894)) ([5f09297](https://github.com/ionic-team/capacitor/commit/5f092970e33da1ec896efc4e2a5ae3fb77fca658))
12+
- **cli:** don't run bundle if not installed ([#7896](https://github.com/ionic-team/capacitor/issues/7896)) ([ee55f6c](https://github.com/ionic-team/capacitor/commit/ee55f6c54639c1a61fa4f9eed1f366ba2d968b86))
13+
- **core:** use getPlatform instead of platform in cordova.js ([#7902](https://github.com/ionic-team/capacitor/issues/7902)) ([277db7b](https://github.com/ionic-team/capacitor/commit/277db7b48caaf870eefdf701ea99332c4338d7ed))
14+
- **http:** boundary not added for Request objects ([#7897](https://github.com/ionic-team/capacitor/issues/7897)) ([bdaa6f3](https://github.com/ionic-team/capacitor/commit/bdaa6f3c38c33f3a021ac61f2de89101a5b66cff))
15+
- **ios:** don't check isMediaExtension on range requests ([#7868](https://github.com/ionic-team/capacitor/issues/7868)) ([028caa5](https://github.com/ionic-team/capacitor/commit/028caa5378d359fb1004098aa93a24ad0f49a4ae))
16+
- **ios:** listen for CapacitorViewDidAppear ([#7850](https://github.com/ionic-team/capacitor/issues/7850)) ([e24ffb7](https://github.com/ionic-team/capacitor/commit/e24ffb7d4de0bf3d53e92537f21c864f121c1fad))
17+
- **ios:** Reset plugin listeners when WebView process is terminated ([#7905](https://github.com/ionic-team/capacitor/issues/7905)) ([d039157](https://github.com/ionic-team/capacitor/commit/d0391576726955b2c1b484f1ca9a03465b9ef67e))
18+
19+
### Features
20+
21+
- Add function to inject external JS into WebView before document load ([#7864](https://github.com/ionic-team/capacitor/issues/7864)) ([ec0954c](https://github.com/ionic-team/capacitor/commit/ec0954c197543e913939f3ab9c4bcb172bfa3530))
22+
- **android:** add adjustMarginsForEdgeToEdge configuration option ([#7885](https://github.com/ionic-team/capacitor/issues/7885)) ([1ea86d1](https://github.com/ionic-team/capacitor/commit/1ea86d166afd315e72847c5e734a8c175fb90e04))
23+
- **cli:** add more configurations to build command ([#7769](https://github.com/ionic-team/capacitor/issues/7769)) ([90f95d1](https://github.com/ionic-team/capacitor/commit/90f95d1a829f3d87cb46af827b5bfaac319a9694))
24+
625
## [7.0.1](https://github.com/ionic-team/capacitor/compare/7.0.0...7.0.1) (2025-01-21)
726

827
### Bug Fixes

android/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
# [7.1.0](https://github.com/ionic-team/capacitor/compare/7.0.1...7.1.0) (2025-03-12)
7+
8+
### Bug Fixes
9+
10+
- **android:** add EdgeToEdge compatibility ([#7871](https://github.com/ionic-team/capacitor/issues/7871)) ([64a8bc4](https://github.com/ionic-team/capacitor/commit/64a8bc40de2522c75a94a40cba6c8ccd82481cb8))
11+
- **android:** sanitize portable file name ([#7894](https://github.com/ionic-team/capacitor/issues/7894)) ([5f09297](https://github.com/ionic-team/capacitor/commit/5f092970e33da1ec896efc4e2a5ae3fb77fca658))
12+
- **http:** boundary not added for Request objects ([#7897](https://github.com/ionic-team/capacitor/issues/7897)) ([bdaa6f3](https://github.com/ionic-team/capacitor/commit/bdaa6f3c38c33f3a021ac61f2de89101a5b66cff))
13+
14+
### Features
15+
16+
- Add function to inject external JS into WebView before document load ([#7864](https://github.com/ionic-team/capacitor/issues/7864)) ([ec0954c](https://github.com/ionic-team/capacitor/commit/ec0954c197543e913939f3ab9c4bcb172bfa3530))
17+
- **android:** add adjustMarginsForEdgeToEdge configuration option ([#7885](https://github.com/ionic-team/capacitor/issues/7885)) ([1ea86d1](https://github.com/ionic-team/capacitor/commit/1ea86d166afd315e72847c5e734a8c175fb90e04))
18+
619
## [7.0.1](https://github.com/ionic-team/capacitor/compare/7.0.0...7.0.1) (2025-01-21)
720

821
**Note:** Version bump only for package @capacitor/android

android/capacitor/src/main/assets/native-bridge.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,15 @@ var nativeBridge = (function (exports) {
468468
if (doPatchHttp) {
469469
// fetch patch
470470
window.fetch = async (resource, options) => {
471+
const headers = new Headers(options === null || options === void 0 ? void 0 : options.headers);
472+
const contentType = headers.get('Content-Type') || headers.get('content-type');
473+
if ((options === null || options === void 0 ? void 0 : options.body) instanceof FormData &&
474+
(contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/form-data')) &&
475+
!contentType.includes('boundary')) {
476+
headers.delete('Content-Type');
477+
headers.delete('content-type');
478+
options.headers = headers;
479+
}
471480
const request = new Request(resource, options);
472481
if (request.url.startsWith(`${cap.getServerUrl()}/`)) {
473482
return win.CapacitorWebFetch(resource, options);

android/capacitor/src/main/java/com/getcapacitor/Bridge.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ public class Bridge {
121121
private HostMask appAllowNavigationMask;
122122
private Set<String> allowedOriginRules = new HashSet<String>();
123123
private ArrayList<String> authorities = new ArrayList<>();
124+
private ArrayList<String> miscJSFileInjections = new ArrayList<String>();
125+
private Boolean canInjectJS = true;
124126
// A reference to the main WebView for the app
125127
private final WebView webView;
126128
public final MockCordovaInterfaceImpl cordovaInterface;
@@ -1017,14 +1019,28 @@ private JSInjector getJSInjector() {
10171019
String cordovaPluginsJS = JSExport.getCordovaPluginJS(context);
10181020
String cordovaPluginsFileJS = JSExport.getCordovaPluginsFileJS(context);
10191021
String localUrlJS = "window.WEBVIEW_SERVER_URL = '" + localUrl + "';";
1022+
String miscJS = JSExport.getMiscFileJS(miscJSFileInjections, context);
10201023

1021-
return new JSInjector(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS);
1024+
miscJSFileInjections = new ArrayList<>();
1025+
canInjectJS = false;
1026+
1027+
return new JSInjector(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, miscJS);
10221028
} catch (Exception ex) {
10231029
Logger.error("Unable to export Capacitor JS. App will not function!", ex);
10241030
}
10251031
return null;
10261032
}
10271033

1034+
/**
1035+
* Inject JavaScript from an external file before the WebView loads.
1036+
* @param path relative to public folder
1037+
*/
1038+
public void injectScriptBeforeLoad(String path) {
1039+
if (canInjectJS) {
1040+
miscJSFileInjections.add(path);
1041+
}
1042+
}
1043+
10281044
/**
10291045
* Restore any saved bundle state data
10301046
* @param savedInstanceState
@@ -1589,9 +1605,9 @@ public Bridge create() {
15891605
config
15901606
);
15911607

1592-
if (webView instanceof CapacitorWebView) {
1593-
CapacitorWebView capacitorWebView = (CapacitorWebView) webView;
1608+
if (webView instanceof CapacitorWebView capacitorWebView) {
15941609
capacitorWebView.setBridge(bridge);
1610+
capacitorWebView.edgeToEdgeHandler(bridge);
15951611
}
15961612

15971613
bridge.setCordovaWebView(mockWebView);

android/capacitor/src/main/java/com/getcapacitor/CapConfig.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public class CapConfig {
5454
private String errorPath;
5555
private boolean zoomableWebView = false;
5656
private boolean resolveServiceWorkerRequests = true;
57+
private String adjustMarginsForEdgeToEdge = "disable";
5758

5859
// Embedded
5960
private String startPath;
@@ -181,6 +182,7 @@ private CapConfig(Builder builder) {
181182
this.errorPath = builder.errorPath;
182183
this.zoomableWebView = builder.zoomableWebView;
183184
this.resolveServiceWorkerRequests = builder.resolveServiceWorkerRequests;
185+
this.adjustMarginsForEdgeToEdge = builder.adjustMarginsForEdgeToEdge;
184186

185187
// Embedded
186188
this.startPath = builder.startPath;
@@ -285,6 +287,7 @@ private void deserializeConfig(@Nullable Context context) {
285287
webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug);
286288
zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false));
287289
resolveServiceWorkerRequests = JSONUtils.getBoolean(configJSON, "android.resolveServiceWorkerRequests", true);
290+
adjustMarginsForEdgeToEdge = JSONUtils.getString(configJSON, "android.adjustMarginsForEdgeToEdge", "disable");
288291

289292
String logBehavior = JSONUtils.getString(
290293
configJSON,
@@ -401,6 +404,10 @@ public boolean isUsingLegacyBridge() {
401404
return useLegacyBridge;
402405
}
403406

407+
public String adjustMarginsForEdgeToEdge() {
408+
return adjustMarginsForEdgeToEdge;
409+
}
410+
404411
public int getMinWebViewVersion() {
405412
if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) {
406413
Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION);
@@ -581,6 +588,7 @@ public static class Builder {
581588
private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION;
582589
private boolean zoomableWebView = false;
583590
private boolean resolveServiceWorkerRequests = true;
591+
private String adjustMarginsForEdgeToEdge = "disable";
584592

585593
// Embedded
586594
private String startPath = null;

android/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.getcapacitor;
22

33
import android.content.Context;
4+
import android.os.Build;
45
import android.util.AttributeSet;
6+
import android.util.TypedValue;
57
import android.view.KeyEvent;
68
import android.view.inputmethod.BaseInputConnection;
79
import android.view.inputmethod.EditorInfo;
@@ -18,7 +20,6 @@ public class CapacitorWebView extends WebView {
1820

1921
public CapacitorWebView(Context context, AttributeSet attrs) {
2022
super(context, attrs);
21-
edgeToEdgeHandler();
2223
}
2324

2425
public void setBridge(Bridge bridge) {
@@ -54,19 +55,35 @@ public boolean dispatchKeyEvent(KeyEvent event) {
5455
return super.dispatchKeyEvent(event);
5556
}
5657

57-
private void edgeToEdgeHandler() {
58-
ViewCompat.setOnApplyWindowInsetsListener(this, (v, windowInsets) -> {
59-
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
58+
public void edgeToEdgeHandler(Bridge bridge) {
59+
String configEdgeToEdge = bridge.getConfig().adjustMarginsForEdgeToEdge();
6060

61-
MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
62-
mlp.leftMargin = insets.left;
63-
mlp.bottomMargin = insets.bottom;
64-
mlp.rightMargin = insets.right;
65-
mlp.topMargin = insets.top;
66-
v.setLayoutParams(mlp);
61+
if (configEdgeToEdge.equals("disable")) return;
6762

68-
// Don't pass window insets to children
69-
return WindowInsetsCompat.CONSUMED;
70-
});
63+
boolean autoMargins = false;
64+
boolean forceMargins = configEdgeToEdge.equals("force");
65+
66+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && configEdgeToEdge.equals("auto")) {
67+
TypedValue value = new TypedValue();
68+
boolean foundOptOut = getContext().getTheme().resolveAttribute(android.R.attr.windowOptOutEdgeToEdgeEnforcement, value, true);
69+
boolean optOutValue = value.data != 0; // value is set to -1 on true as of Android 15, so we have to do this.
70+
71+
autoMargins = !(foundOptOut && optOutValue);
72+
}
73+
74+
if (forceMargins || autoMargins) {
75+
ViewCompat.setOnApplyWindowInsetsListener(this, (v, windowInsets) -> {
76+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
77+
MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
78+
mlp.leftMargin = insets.left;
79+
mlp.bottomMargin = insets.bottom;
80+
mlp.rightMargin = insets.right;
81+
mlp.topMargin = insets.top;
82+
v.setLayoutParams(mlp);
83+
84+
// Don't pass window insets to children
85+
return WindowInsetsCompat.CONSUMED;
86+
});
87+
}
7188
}
7289
}

android/capacitor/src/main/java/com/getcapacitor/FileUtils.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ private static String getCopyFilePath(Uri uri, Context context) {
219219
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
220220
cursor.moveToFirst();
221221
String name = (cursor.getString(nameIndex));
222-
File file = new File(context.getFilesDir(), name);
222+
String fileName = sanitizeFilename(name);
223+
File file = new File(context.getFilesDir(), fileName);
223224
try {
224225
InputStream inputStream = context.getContentResolver().openInputStream(uri);
225226
FileOutputStream outputStream = new FileOutputStream(file);
@@ -289,4 +290,14 @@ private static String getPathToNonPrimaryVolume(Context context, String tag) {
289290
}
290291
return null;
291292
}
293+
294+
private static String sanitizeFilename(String displayName) {
295+
String[] badCharacters = new String[] { "..", "/" };
296+
String[] segments = displayName.split("/");
297+
String fileName = segments[segments.length - 1];
298+
for (String suspString : badCharacters) {
299+
fileName = fileName.replace(suspString, "_");
300+
}
301+
return fileName;
302+
}
292303
}

android/capacitor/src/main/java/com/getcapacitor/JSExport.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ public static String getGlobalJS(Context context, boolean loggingEnabled, boolea
2121
return "window.Capacitor = { DEBUG: " + isDebug + ", isLoggingEnabled: " + loggingEnabled + ", Plugins: {} };";
2222
}
2323

24+
public static String getMiscFileJS(ArrayList<String> paths, Context context) {
25+
List<String> lines = new ArrayList<>();
26+
27+
for (String path : paths) {
28+
try {
29+
String fileContent = readFileFromAssets(context.getAssets(), "public/" + path);
30+
lines.add(fileContent);
31+
} catch (IOException ex) {
32+
Logger.error("Unable to read public/" + path);
33+
}
34+
}
35+
36+
return TextUtils.join("\n", lines);
37+
}
38+
2439
public static String getCordovaJS(Context context) {
2540
String fileContent = "";
2641
try {

android/capacitor/src/main/java/com/getcapacitor/JSInjector.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class JSInjector {
2020
private String cordovaPluginsJS;
2121
private String cordovaPluginsFileJS;
2222
private String localUrlJS;
23+
private String miscJS;
2324

2425
public JSInjector(
2526
String globalJS,
@@ -29,6 +30,19 @@ public JSInjector(
2930
String cordovaPluginsJS,
3031
String cordovaPluginsFileJS,
3132
String localUrlJS
33+
) {
34+
this(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, null);
35+
}
36+
37+
public JSInjector(
38+
String globalJS,
39+
String bridgeJS,
40+
String pluginJS,
41+
String cordovaJS,
42+
String cordovaPluginsJS,
43+
String cordovaPluginsFileJS,
44+
String localUrlJS,
45+
String miscJS
3246
) {
3347
this.globalJS = globalJS;
3448
this.bridgeJS = bridgeJS;
@@ -37,6 +51,7 @@ public JSInjector(
3751
this.cordovaPluginsJS = cordovaPluginsJS;
3852
this.cordovaPluginsFileJS = cordovaPluginsFileJS;
3953
this.localUrlJS = localUrlJS;
54+
this.miscJS = miscJS;
4055
}
4156

4257
/**
@@ -45,7 +60,7 @@ public JSInjector(
4560
* @return
4661
*/
4762
public String getScriptString() {
48-
return (
63+
String scriptString =
4964
globalJS +
5065
"\n\n" +
5166
localUrlJS +
@@ -58,8 +73,13 @@ public String getScriptString() {
5873
"\n\n" +
5974
cordovaPluginsFileJS +
6075
"\n\n" +
61-
cordovaPluginsJS
62-
);
76+
cordovaPluginsJS;
77+
78+
if (miscJS != null) {
79+
scriptString += "\n\n" + miscJS;
80+
}
81+
82+
return scriptString;
6383
}
6484

6585
/**

android/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@capacitor/android",
3-
"version": "7.0.1",
3+
"version": "7.1.0",
44
"description": "Capacitor: Cross-platform apps with JavaScript and the web",
55
"homepage": "https://capacitorjs.com",
66
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
@@ -23,7 +23,7 @@
2323
"verify": "./gradlew clean lint build test -b capacitor/build.gradle"
2424
},
2525
"peerDependencies": {
26-
"@capacitor/core": "^7.0.0"
26+
"@capacitor/core": "^7.1.0"
2727
},
2828
"publishConfig": {
2929
"access": "public"

0 commit comments

Comments
 (0)