@capacitor/android 8.3.5-nightly-20260529T161937.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.
@@ -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.getActivity().runOnUiThread(() -> {
74
- String js = queue.popAndEncodeAsJs();
75
- if (js != null) {
76
- webView.evaluateJavascript(js, null);
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
 
@@ -164,18 +164,13 @@ public class SystemBars extends Plugin {
164
164
  }
165
165
 
166
166
  private void initSafeAreaCSSVariables() {
167
- WindowInsetsCompat insets;
168
-
169
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
167
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
170
168
  View v = (View) this.getBridge().getWebView().getParent();
171
- insets = ViewCompat.getRootWindowInsets(v);
172
- } else {
173
- insets = WindowInsetsCompat.CONSUMED;
174
- }
175
-
176
- if (insets != null) {
177
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
178
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
169
+ WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
170
+ if (insets != null) {
171
+ Insets safeAreaInsets = calcSafeAreaInsets(insets);
172
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
173
+ }
179
174
  }
180
175
  }
181
176
 
@@ -191,8 +186,10 @@ public class SystemBars extends Plugin {
191
186
  // We need to correct for a possible shown IME
192
187
  v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
193
188
 
194
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
195
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
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
+ }
196
193
 
197
194
  return new WindowInsetsCompat.Builder(insets)
198
195
  .setInsets(
@@ -224,8 +221,10 @@ public class SystemBars extends Plugin {
224
221
  .setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
225
222
  .build();
226
223
 
227
- Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
228
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
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
+ }
229
228
 
230
229
  return newInsets;
231
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-nightly-20260529T161937.0",
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-nightly-20260529T161937.0"
26
+ "@capacitor/core": "^8.3.0"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"