@capacitor/android 8.3.5-nightly-20260601T165419.0 → 8.3.5
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/src/main/java/com/getcapacitor/Bridge.java +6 -0
- package/capacitor/src/main/java/com/getcapacitor/Plugin.java +2 -1
- package/capacitor/src/main/java/com/getcapacitor/PluginConfig.java +0 -11
- package/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +26 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java +8 -6
- package/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java +20 -37
- package/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java +0 -20
- package/package.json +2 -2
|
@@ -387,6 +387,12 @@ public class Bridge {
|
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
public boolean launchIntent(Uri url) {
|
|
390
|
+
// The proxy returns a remote body at the app origin, so block it before plugins can allow it.
|
|
391
|
+
String path = url.getPath();
|
|
392
|
+
if (path != null && path.startsWith(CAPACITOR_HTTP_INTERCEPTOR_START)) {
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
|
|
390
396
|
/*
|
|
391
397
|
* Give plugins the chance to handle the url
|
|
392
398
|
*/
|
|
@@ -1003,7 +1003,8 @@ public class Plugin {
|
|
|
1003
1003
|
* Give the plugins a chance to take control when a URL is about to be loaded in the WebView.
|
|
1004
1004
|
* Returning true causes the WebView to abort loading the URL.
|
|
1005
1005
|
* Returning false causes the WebView to continue loading the URL.
|
|
1006
|
-
* Returning null will defer to the default Capacitor policy
|
|
1006
|
+
* Returning null will defer to the default Capacitor policy.
|
|
1007
|
+
* Not called for Capacitor's internal HTTP proxy path, which is always blocked.
|
|
1007
1008
|
*/
|
|
1008
1009
|
@SuppressWarnings("unused")
|
|
1009
1010
|
public Boolean shouldOverrideLoad(Uri url) {
|
|
@@ -65,17 +65,6 @@ public class PluginConfig {
|
|
|
65
65
|
return JSONUtils.getInt(config, configKey, defaultValue);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
/**
|
|
69
|
-
* Get a double value for a plugin in the Capacitor config.
|
|
70
|
-
*
|
|
71
|
-
* @param configKey The key of the value to retrieve
|
|
72
|
-
* @param defaultValue A default value to return if the key does not exist in the config
|
|
73
|
-
* @return The value from the config, if key exists. Default value returned if not
|
|
74
|
-
*/
|
|
75
|
-
public double getDouble(String configKey, double defaultValue) {
|
|
76
|
-
return JSONUtils.getDouble(config, configKey, defaultValue);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
68
|
/**
|
|
80
69
|
* Get a string array value for a plugin in the Capacitor config.
|
|
81
70
|
*
|
|
@@ -185,6 +185,11 @@ public class WebViewLocalServer {
|
|
|
185
185
|
Uri loadingUrl = request.getUrl();
|
|
186
186
|
|
|
187
187
|
if (null != loadingUrl.getPath() && loadingUrl.getPath().startsWith(Bridge.CAPACITOR_HTTP_INTERCEPTOR_START)) {
|
|
188
|
+
// Only fetch/XHR should reach the proxy; a document would run remote content at the app origin.
|
|
189
|
+
boolean httpEnabled = bridge.getConfig().getPluginConfiguration("CapacitorHttp").getBoolean("enabled", false);
|
|
190
|
+
if (!httpEnabled || isDocumentRequest(request)) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
188
193
|
Logger.debug("Handling CapacitorHttp request: " + loadingUrl);
|
|
189
194
|
try {
|
|
190
195
|
return handleCapacitorHttpRequest(request);
|
|
@@ -210,6 +215,24 @@ public class WebViewLocalServer {
|
|
|
210
215
|
}
|
|
211
216
|
}
|
|
212
217
|
|
|
218
|
+
/** isForMainFrame() is false for an iframe and a fetch alike; only navigations send this header. */
|
|
219
|
+
private boolean isDocumentRequest(WebResourceRequest request) {
|
|
220
|
+
if (request.isForMainFrame()) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
Map<String, String> headers = request.getRequestHeaders();
|
|
224
|
+
if (headers == null) {
|
|
225
|
+
// The proxy needs the headers too, so the request fails there anyway.
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
for (String header : headers.keySet()) {
|
|
229
|
+
if ("Upgrade-Insecure-Requests".equalsIgnoreCase(header)) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
213
236
|
private boolean isLocalFile(Uri uri) {
|
|
214
237
|
String path = uri.getPath();
|
|
215
238
|
return path.startsWith(capacitorContentStart) || path.startsWith(capacitorFileStart);
|
|
@@ -333,6 +356,9 @@ public class WebViewLocalServer {
|
|
|
333
356
|
int responseCode = connection.getResponseCode();
|
|
334
357
|
String reasonPhrase = getReasonPhraseFromResponseCode(responseCode);
|
|
335
358
|
|
|
359
|
+
// Nothing should render this. If anything does, sandbox keeps it inert and off the app origin.
|
|
360
|
+
responseHeaders.put("Content-Security-Policy", "sandbox; frame-ancestors 'none'");
|
|
361
|
+
|
|
336
362
|
return new WebResourceResponse(mimeType, encoding, responseCode, reasonPhrase, responseHeaders, inputStream);
|
|
337
363
|
}
|
|
338
364
|
|
|
@@ -70,12 +70,14 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
|
|
|
70
70
|
|
|
71
71
|
@Override
|
|
72
72
|
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
|
|
73
|
-
cordova
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
cordova
|
|
74
|
+
.getActivity()
|
|
75
|
+
.runOnUiThread(() -> {
|
|
76
|
+
String js = queue.popAndEncodeAsJs();
|
|
77
|
+
if (js != null) {
|
|
78
|
+
webView.evaluateJavascript(js, null);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
|
|
@@ -16,7 +16,6 @@ import androidx.core.view.WindowCompat;
|
|
|
16
16
|
import androidx.core.view.WindowInsetsCompat;
|
|
17
17
|
import androidx.core.view.WindowInsetsControllerCompat;
|
|
18
18
|
import androidx.webkit.WebViewCompat;
|
|
19
|
-
import com.getcapacitor.Logger;
|
|
20
19
|
import com.getcapacitor.Plugin;
|
|
21
20
|
import com.getcapacitor.PluginCall;
|
|
22
21
|
import com.getcapacitor.PluginMethod;
|
|
@@ -33,7 +32,6 @@ public class SystemBars extends Plugin {
|
|
|
33
32
|
static final String BAR_STATUS_BAR = "StatusBar";
|
|
34
33
|
static final String BAR_GESTURE_BAR = "NavigationBar";
|
|
35
34
|
|
|
36
|
-
// TODO: In Cap 9, add an additional option "full"
|
|
37
35
|
static final String INSETS_HANDLING_CSS = "css";
|
|
38
36
|
static final String INSETS_HANDLING_DISABLE = "disable";
|
|
39
37
|
|
|
@@ -55,7 +53,7 @@ public class SystemBars extends Plugin {
|
|
|
55
53
|
capacitorSystemBarsCheckMetaViewport();
|
|
56
54
|
""";
|
|
57
55
|
|
|
58
|
-
private
|
|
56
|
+
private boolean insetHandlingEnabled = true;
|
|
59
57
|
private boolean hasViewportCover = false;
|
|
60
58
|
|
|
61
59
|
private String currentStatusBarStyle = STYLE_DEFAULT;
|
|
@@ -96,15 +94,9 @@ public class SystemBars extends Plugin {
|
|
|
96
94
|
String style = getConfig().getString("style", STYLE_DEFAULT).toUpperCase(Locale.US);
|
|
97
95
|
boolean hidden = getConfig().getBoolean("hidden", false);
|
|
98
96
|
|
|
99
|
-
String
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
} else {
|
|
103
|
-
Logger.warn(
|
|
104
|
-
"SystemBars",
|
|
105
|
-
"Unknown insetsHandling value '" + configuredInsetsHandling + "'. Falling back to '" + INSETS_HANDLING_CSS + "'."
|
|
106
|
-
);
|
|
107
|
-
insetsHandling = INSETS_HANDLING_CSS;
|
|
97
|
+
String insetsHandling = getConfig().getString("insetsHandling", "css");
|
|
98
|
+
if (insetsHandling.equals(INSETS_HANDLING_DISABLE)) {
|
|
99
|
+
insetHandlingEnabled = false;
|
|
108
100
|
}
|
|
109
101
|
|
|
110
102
|
initWindowInsetsListener();
|
|
@@ -154,15 +146,13 @@ public class SystemBars extends Plugin {
|
|
|
154
146
|
|
|
155
147
|
@JavascriptInterface
|
|
156
148
|
public void onDOMReady() {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
hasViewportCover = res.equals("true");
|
|
149
|
+
getActivity().runOnUiThread(() -> {
|
|
150
|
+
this.bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> {
|
|
151
|
+
hasViewportCover = res.equals("true");
|
|
161
152
|
|
|
162
|
-
|
|
163
|
-
});
|
|
153
|
+
getBridge().getWebView().requestApplyInsets();
|
|
164
154
|
});
|
|
165
|
-
}
|
|
155
|
+
});
|
|
166
156
|
}
|
|
167
157
|
|
|
168
158
|
private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
|
|
@@ -174,16 +164,9 @@ public class SystemBars extends Plugin {
|
|
|
174
164
|
}
|
|
175
165
|
|
|
176
166
|
private void initSafeAreaCSSVariables() {
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
181
|
-
View v = (View) this.getBridge().getWebView().getParent();
|
|
182
|
-
insets = ViewCompat.getRootWindowInsets(v);
|
|
183
|
-
} else {
|
|
184
|
-
insets = WindowInsetsCompat.CONSUMED;
|
|
185
|
-
}
|
|
186
|
-
|
|
167
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
|
|
168
|
+
View v = (View) this.getBridge().getWebView().getParent();
|
|
169
|
+
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
|
|
187
170
|
if (insets != null) {
|
|
188
171
|
Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
189
172
|
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
@@ -192,10 +175,6 @@ public class SystemBars extends Plugin {
|
|
|
192
175
|
}
|
|
193
176
|
|
|
194
177
|
private void initWindowInsetsListener() {
|
|
195
|
-
if (INSETS_HANDLING_DISABLE.equals(insetsHandling)) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
178
|
ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
|
|
200
179
|
boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
|
|
201
180
|
|
|
@@ -207,8 +186,10 @@ public class SystemBars extends Plugin {
|
|
|
207
186
|
// We need to correct for a possible shown IME
|
|
208
187
|
v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
|
|
209
188
|
|
|
210
|
-
|
|
211
|
-
|
|
189
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
190
|
+
Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
191
|
+
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
192
|
+
}
|
|
212
193
|
|
|
213
194
|
return new WindowInsetsCompat.Builder(insets)
|
|
214
195
|
.setInsets(
|
|
@@ -240,8 +221,10 @@ public class SystemBars extends Plugin {
|
|
|
240
221
|
.setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
|
|
241
222
|
.build();
|
|
242
223
|
|
|
243
|
-
|
|
244
|
-
|
|
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
|
+
}
|
|
245
228
|
|
|
246
229
|
return newInsets;
|
|
247
230
|
});
|
|
@@ -75,26 +75,6 @@ public class JSONUtils {
|
|
|
75
75
|
return defaultValue;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
/**
|
|
79
|
-
* Get a double value from the given JSON object.
|
|
80
|
-
*
|
|
81
|
-
* @param jsonObject A JSON object to search
|
|
82
|
-
* @param key A key to fetch from the JSON object
|
|
83
|
-
* @param defaultValue A default value to return if the key cannot be found
|
|
84
|
-
* @return The value at the given key in the JSON object, or the default value
|
|
85
|
-
*/
|
|
86
|
-
public static double getDouble(JSONObject jsonObject, String key, double defaultValue) {
|
|
87
|
-
String k = getDeepestKey(key);
|
|
88
|
-
try {
|
|
89
|
-
JSONObject o = getDeepestObject(jsonObject, key);
|
|
90
|
-
return o.getDouble(k);
|
|
91
|
-
} catch (JSONException ignore) {
|
|
92
|
-
// value was not found
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return defaultValue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
78
|
/**
|
|
99
79
|
* Get a JSON object value from the given JSON object.
|
|
100
80
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/android",
|
|
3
|
-
"version": "8.3.5
|
|
3
|
+
"version": "8.3.5",
|
|
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)",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"verify": "./gradlew clean lint build test -b capacitor/build.gradle"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@capacitor/core": "^8.3.0
|
|
26
|
+
"@capacitor/core": "^8.3.0"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|