@capacitor/android 8.1.0 → 8.1.1-dev-20260305T150856.0

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.
@@ -35,8 +35,6 @@ import androidx.webkit.WebViewFeature;
35
35
  import com.getcapacitor.android.R;
36
36
  import com.getcapacitor.annotation.CapacitorPlugin;
37
37
  import com.getcapacitor.annotation.Permission;
38
- import com.getcapacitor.cordova.MockCordovaInterfaceImpl;
39
- import com.getcapacitor.cordova.MockCordovaWebViewImpl;
40
38
  import com.getcapacitor.util.HostMask;
41
39
  import com.getcapacitor.util.InternalUtils;
42
40
  import com.getcapacitor.util.PermissionHelper;
@@ -53,13 +51,9 @@ import java.util.LinkedList;
53
51
  import java.util.List;
54
52
  import java.util.Map;
55
53
  import java.util.Set;
54
+ import java.util.function.Function;
56
55
  import java.util.regex.Matcher;
57
56
  import java.util.regex.Pattern;
58
- import org.apache.cordova.ConfigXmlParser;
59
- import org.apache.cordova.CordovaPreferences;
60
- import org.apache.cordova.CordovaWebView;
61
- import org.apache.cordova.PluginEntry;
62
- import org.apache.cordova.PluginManager;
63
57
  import org.json.JSONException;
64
58
 
65
59
  /**
@@ -125,9 +119,6 @@ public class Bridge {
125
119
  private Boolean canInjectJS = true;
126
120
  // A reference to the main WebView for the app
127
121
  private final WebView webView;
128
- public final MockCordovaInterfaceImpl cordovaInterface;
129
- private CordovaWebView cordovaWebView;
130
- private CordovaPreferences preferences;
131
122
  private BridgeWebViewClient webViewClient;
132
123
  private App app;
133
124
 
@@ -147,6 +138,8 @@ public class Bridge {
147
138
  // A map of Plugin Id's to PluginHandle's
148
139
  private Map<String, PluginHandle> plugins = new HashMap<>();
149
140
 
141
+ private Map<String, MessageHandler.Interceptor> interceptors = new HashMap<>();
142
+
150
143
  // Stored plugin calls that we're keeping around to call again someday
151
144
  private Map<String, PluginCall> savedCalls = new HashMap<>();
152
145
 
@@ -169,26 +162,6 @@ public class Bridge {
169
162
  // A pre-determined path to load the bridge
170
163
  private ServerPath serverPath;
171
164
 
172
- /**
173
- * Create the Bridge with a reference to the main {@link Activity} for the
174
- * app, and a reference to the {@link WebView} our app will use.
175
- * @param context
176
- * @param webView
177
- * @deprecated Use {@link Bridge.Builder} to create Bridge instances
178
- */
179
- @Deprecated
180
- public Bridge(
181
- AppCompatActivity context,
182
- WebView webView,
183
- List<Class<? extends Plugin>> initialPlugins,
184
- MockCordovaInterfaceImpl cordovaInterface,
185
- PluginManager pluginManager,
186
- CordovaPreferences preferences,
187
- CapConfig config
188
- ) {
189
- this(context, null, null, webView, initialPlugins, new ArrayList<>(), cordovaInterface, pluginManager, preferences, config);
190
- }
191
-
192
165
  private Bridge(
193
166
  AppCompatActivity context,
194
167
  ServerPath serverPath,
@@ -196,9 +169,6 @@ public class Bridge {
196
169
  WebView webView,
197
170
  List<Class<? extends Plugin>> initialPlugins,
198
171
  List<Plugin> pluginInstances,
199
- MockCordovaInterfaceImpl cordovaInterface,
200
- PluginManager pluginManager,
201
- CordovaPreferences preferences,
202
172
  CapConfig config
203
173
  ) {
204
174
  this.app = new App();
@@ -209,8 +179,6 @@ public class Bridge {
209
179
  this.webViewClient = new BridgeWebViewClient(this);
210
180
  this.initialPlugins = initialPlugins;
211
181
  this.pluginInstances = pluginInstances;
212
- this.cordovaInterface = cordovaInterface;
213
- this.preferences = preferences;
214
182
 
215
183
  // Start our plugin execution threads and handlers
216
184
  handlerThread.start();
@@ -218,11 +186,10 @@ public class Bridge {
218
186
 
219
187
  this.config = config != null ? config : CapConfig.loadDefault(getActivity());
220
188
  Logger.init(this.config);
221
-
222
189
  // Initialize web view and message handler for it
223
190
  this.initWebView();
224
191
  this.setAllowedOriginRules();
225
- this.msgHandler = new MessageHandler(this, webView, pluginManager);
192
+ this.msgHandler = new MessageHandler(this, webView);
226
193
 
227
194
  // Grab any intent info that our app was launched with
228
195
  Intent intent = context.getIntent();
@@ -450,12 +417,30 @@ public class Bridge {
450
417
  return false;
451
418
  }
452
419
 
420
+ private Plugin cordova() {
421
+ PluginHandle handle = getPlugin("__CordovaHandle");
422
+ if (handle != null) {
423
+ return handle.getInstance();
424
+ }
425
+ return null;
426
+ }
427
+
453
428
  public boolean isDeployDisabled() {
454
- return preferences.getBoolean("DisableDeploy", false);
429
+ Plugin cordova = this.cordova();
430
+ if (cordova != null) {
431
+ return cordova.hasPermission("DisableDeploy");
432
+ } else {
433
+ return false;
434
+ }
455
435
  }
456
436
 
457
437
  public boolean shouldKeepRunning() {
458
- return preferences.getBoolean("KeepRunning", true);
438
+ Plugin cordova = this.cordova();
439
+ if (cordova != null) {
440
+ return cordova.hasPermission("KeepRunning");
441
+ } else {
442
+ return false;
443
+ }
459
444
  }
460
445
 
461
446
  public void handleAppUrlLoadError(Exception ex) {
@@ -474,10 +459,6 @@ public class Bridge {
474
459
  return (getActivity().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
475
460
  }
476
461
 
477
- protected void setCordovaWebView(CordovaWebView cordovaWebView) {
478
- this.cordovaWebView = cordovaWebView;
479
- }
480
-
481
462
  /**
482
463
  * Get the Context for the App
483
464
  * @return
@@ -567,6 +548,14 @@ public class Bridge {
567
548
  return this.config;
568
549
  }
569
550
 
551
+ public MessageHandler.Interceptor getCallInterceptor(String type) {
552
+ return this.interceptors.get(type);
553
+ }
554
+
555
+ public void registerInterceptor(String type, MessageHandler.Interceptor interceptor) {
556
+ this.interceptors.put(type, interceptor);
557
+ }
558
+
570
559
  public void reset() {
571
560
  savedCalls = new HashMap<>();
572
561
  for (PluginHandle handle : this.plugins.values()) {
@@ -1132,11 +1121,14 @@ public class Bridge {
1132
1121
  if (plugin == null) {
1133
1122
  boolean permissionHandled = false;
1134
1123
  Logger.debug("Unable to find a Capacitor plugin to handle permission requestCode, trying Cordova plugins " + requestCode);
1135
- try {
1136
- permissionHandled = cordovaInterface.handlePermissionResult(requestCode, permissions, grantResults);
1137
- } catch (JSONException e) {
1138
- Logger.debug("Error on Cordova plugin permissions request " + e.getMessage());
1124
+ PluginHandle cordovaHandle = getPlugin("__CordovaPlugin");
1125
+
1126
+ if (cordovaHandle != null) {
1127
+ Plugin cordovaPlugin = cordovaHandle.getInstance();
1128
+ cordovaPlugin.handleRequestPermissionsResult(requestCode, permissions, grantResults);
1129
+ permissionHandled = cordovaPlugin.hasDefinedRequiredPermissions();
1139
1130
  }
1131
+
1140
1132
  return permissionHandled;
1141
1133
  }
1142
1134
 
@@ -1271,7 +1263,13 @@ public class Bridge {
1271
1263
 
1272
1264
  if (plugin == null || plugin.getInstance() == null) {
1273
1265
  Logger.debug("Unable to find a Capacitor plugin to handle requestCode, trying Cordova plugins " + requestCode);
1274
- return cordovaInterface.onActivityResult(requestCode, resultCode, data);
1266
+ PluginHandle cordovaHandle = getPlugin("__CordovaPlugin");
1267
+ if (cordovaHandle != null) {
1268
+ Plugin cordovaPlugin = cordovaHandle.getInstance();
1269
+ cordovaPlugin.handleOnActivityResult(requestCode, resultCode, data);
1270
+ // This is a bit hacky but required to return the boolean out of the cordova interface
1271
+ return cordovaPlugin.hasRequiredPermissions();
1272
+ }
1275
1273
  }
1276
1274
 
1277
1275
  // deprecated, to be removed
@@ -1301,10 +1299,6 @@ public class Bridge {
1301
1299
  for (PluginHandle plugin : plugins.values()) {
1302
1300
  plugin.getInstance().handleOnNewIntent(intent);
1303
1301
  }
1304
-
1305
- if (cordovaWebView != null) {
1306
- cordovaWebView.onNewIntent(intent);
1307
- }
1308
1302
  }
1309
1303
 
1310
1304
  /**
@@ -1333,10 +1327,6 @@ public class Bridge {
1333
1327
  for (PluginHandle plugin : plugins.values()) {
1334
1328
  plugin.getInstance().handleOnStart();
1335
1329
  }
1336
-
1337
- if (cordovaWebView != null) {
1338
- cordovaWebView.handleStart();
1339
- }
1340
1330
  }
1341
1331
 
1342
1332
  /**
@@ -1346,10 +1336,6 @@ public class Bridge {
1346
1336
  for (PluginHandle plugin : plugins.values()) {
1347
1337
  plugin.getInstance().handleOnResume();
1348
1338
  }
1349
-
1350
- if (cordovaWebView != null) {
1351
- cordovaWebView.handleResume(this.shouldKeepRunning());
1352
- }
1353
1339
  }
1354
1340
 
1355
1341
  /**
@@ -1359,11 +1345,6 @@ public class Bridge {
1359
1345
  for (PluginHandle plugin : plugins.values()) {
1360
1346
  plugin.getInstance().handleOnPause();
1361
1347
  }
1362
-
1363
- if (cordovaWebView != null) {
1364
- boolean keepRunning = this.shouldKeepRunning() || cordovaInterface.getActivityResultCallback() != null;
1365
- cordovaWebView.handlePause(keepRunning);
1366
- }
1367
1348
  }
1368
1349
 
1369
1350
  /**
@@ -1373,10 +1354,6 @@ public class Bridge {
1373
1354
  for (PluginHandle plugin : plugins.values()) {
1374
1355
  plugin.getInstance().handleOnStop();
1375
1356
  }
1376
-
1377
- if (cordovaWebView != null) {
1378
- cordovaWebView.handleStop();
1379
- }
1380
1357
  }
1381
1358
 
1382
1359
  /**
@@ -1388,10 +1365,6 @@ public class Bridge {
1388
1365
  }
1389
1366
 
1390
1367
  handlerThread.quitSafely();
1391
-
1392
- if (cordovaWebView != null) {
1393
- cordovaWebView.handleDestroy();
1394
- }
1395
1368
  }
1396
1369
 
1397
1370
  /**
@@ -1578,49 +1551,54 @@ public class Bridge {
1578
1551
 
1579
1552
  public Bridge create() {
1580
1553
  // Cordova initialization
1581
- ConfigXmlParser parser = new ConfigXmlParser();
1582
- parser.parse(activity.getApplicationContext());
1583
- CordovaPreferences preferences = parser.getPreferences();
1584
- preferences.setPreferencesBundle(activity.getIntent().getExtras());
1585
- List<PluginEntry> pluginEntries = parser.getPluginEntries();
1586
-
1587
- MockCordovaInterfaceImpl cordovaInterface = new MockCordovaInterfaceImpl(activity);
1588
- if (instanceState != null) {
1589
- cordovaInterface.restoreInstanceState(instanceState);
1590
- }
1591
-
1592
1554
  WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview);
1593
- MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext());
1594
- mockWebView.init(cordovaInterface, pluginEntries, preferences, webView);
1595
- PluginManager pluginManager = mockWebView.getPluginManager();
1596
- cordovaInterface.onCordovaInit(pluginManager);
1597
1555
 
1598
1556
  // Bridge initialization
1599
- Bridge bridge = new Bridge(
1600
- activity,
1601
- serverPath,
1602
- fragment,
1603
- webView,
1604
- plugins,
1605
- pluginInstances,
1606
- cordovaInterface,
1607
- pluginManager,
1608
- preferences,
1609
- config
1610
- );
1557
+ Bridge bridge = new Bridge(activity, serverPath, fragment, webView, plugins, pluginInstances, config);
1611
1558
 
1612
1559
  if (webView instanceof CapacitorWebView capacitorWebView) {
1613
1560
  capacitorWebView.setBridge(bridge);
1614
1561
  }
1615
1562
 
1616
- bridge.setCordovaWebView(mockWebView);
1617
1563
  bridge.setWebViewListeners(webViewListeners);
1618
1564
  bridge.setRouteProcessor(routeProcessor);
1619
1565
 
1620
1566
  if (instanceState != null) {
1567
+ PluginHandle maybeCordova = bridge.getPlugin("__CordovaPlugin");
1568
+ if (maybeCordova != null) {
1569
+ maybeCordova.getInstance().restoreState(instanceState);
1570
+ }
1621
1571
  bridge.restoreInstanceState(instanceState);
1622
1572
  }
1623
1573
 
1574
+ bridge.registerInterceptor("message", (postData) -> {
1575
+ try {
1576
+ String callbackId = postData.getString("callbackId");
1577
+ String pluginId = postData.getString("pluginId");
1578
+ String methodName = postData.getString("methodName");
1579
+ JSObject methodData = postData.getJSObject("options", new JSObject());
1580
+
1581
+ Logger.verbose(
1582
+ Logger.tags("Plugin"),
1583
+ "To native (Capacitor plugin): callbackId: " +
1584
+ callbackId +
1585
+ ", pluginId: " +
1586
+ pluginId +
1587
+ ", methodName: " +
1588
+ methodName
1589
+ );
1590
+
1591
+ PluginCall call = new PluginCall(bridge.msgHandler, pluginId, callbackId, methodName, methodData);
1592
+ bridge.callPluginMethod(pluginId, methodName, call);
1593
+ } catch (JSONException e) {
1594
+ Logger.error(e.getMessage());
1595
+ }
1596
+ });
1597
+
1598
+ bridge.registerInterceptor("js.error", (postData) -> {
1599
+ Logger.error("JavaScript Error: " + postData.toString());
1600
+ });
1601
+
1624
1602
  return bridge;
1625
1603
  }
1626
1604
  }
@@ -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.saveInstanceState(outState);
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.onRestart();
86
- Logger.debug("App restarted");
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.onDetachedFromWindow();
138
+ if (this.bridge != null) {
139
+ this.bridge.onDetachedFromWindow();
140
+ }
135
141
  }
136
142
 
137
143
  /**
@@ -5,7 +5,7 @@ import android.webkit.WebView;
5
5
  import androidx.webkit.JavaScriptReplyProxy;
6
6
  import androidx.webkit.WebViewCompat;
7
7
  import androidx.webkit.WebViewFeature;
8
- import org.apache.cordova.PluginManager;
8
+ import java.util.function.Function;
9
9
 
10
10
  /**
11
11
  * MessageHandler handles messages from the WebView, dispatching them
@@ -13,15 +13,18 @@ import org.apache.cordova.PluginManager;
13
13
  */
14
14
  public class MessageHandler {
15
15
 
16
+ @FunctionalInterface
17
+ public interface Interceptor {
18
+ void intercept(JSObject object);
19
+ }
20
+
16
21
  private Bridge bridge;
17
22
  private WebView webView;
18
- private PluginManager cordovaPluginManager;
19
23
  private JavaScriptReplyProxy javaScriptReplyProxy;
20
24
 
21
- public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
25
+ public MessageHandler(Bridge bridge, WebView webView) {
22
26
  this.bridge = bridge;
23
27
  this.webView = webView;
24
- this.cordovaPluginManager = cordovaPluginManager;
25
28
 
26
29
  if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && !bridge.getConfig().isUsingLegacyBridge()) {
27
30
  WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
@@ -42,6 +45,11 @@ public class MessageHandler {
42
45
  }
43
46
  }
44
47
 
48
+ @Deprecated
49
+ public MessageHandler(Bridge bridge, WebView webView, Object cordovaPluginManager) {
50
+ this(bridge, webView);
51
+ }
52
+
45
53
  /**
46
54
  * The main message handler that will be called from JavaScript
47
55
  * to send a message to the native bridge.
@@ -55,43 +63,11 @@ public class MessageHandler {
55
63
 
56
64
  String type = postData.getString("type");
57
65
 
58
- boolean typeIsNotNull = type != null;
59
- boolean isCordovaPlugin = typeIsNotNull && type.equals("cordova");
60
- boolean isJavaScriptError = typeIsNotNull && type.equals("js.error");
61
-
62
- String callbackId = postData.getString("callbackId");
63
-
64
- if (isCordovaPlugin) {
65
- String service = postData.getString("service");
66
- String action = postData.getString("action");
67
- String actionArgs = postData.getString("actionArgs");
68
-
69
- Logger.verbose(
70
- Logger.tags("Plugin"),
71
- "To native (Cordova plugin): callbackId: " +
72
- callbackId +
73
- ", service: " +
74
- service +
75
- ", action: " +
76
- action +
77
- ", actionArgs: " +
78
- actionArgs
79
- );
80
-
81
- this.callCordovaPluginMethod(callbackId, service, action, actionArgs);
82
- } else if (isJavaScriptError) {
83
- Logger.error("JavaScript Error: " + jsonStr);
84
- } else {
85
- String pluginId = postData.getString("pluginId");
86
- String methodName = postData.getString("methodName");
87
- JSObject methodData = postData.getJSObject("options", new JSObject());
88
-
89
- Logger.verbose(
90
- Logger.tags("Plugin"),
91
- "To native (Capacitor plugin): callbackId: " + callbackId + ", pluginId: " + pluginId + ", methodName: " + methodName
92
- );
66
+ if (type == null) type = "message";
93
67
 
94
- this.callPluginMethod(callbackId, pluginId, methodName, methodData);
68
+ Interceptor interceptor = bridge.getCallInterceptor(type);
69
+ if (interceptor != null) {
70
+ interceptor.intercept(postData);
95
71
  }
96
72
  } catch (Exception ex) {
97
73
  Logger.error("Post message error:", ex);
@@ -148,10 +124,4 @@ public class MessageHandler {
148
124
  PluginCall call = new PluginCall(this, pluginId, callbackId, methodName, methodData);
149
125
  bridge.callPluginMethod(pluginId, methodName, call);
150
126
  }
151
-
152
- private void callCordovaPluginMethod(String callbackId, String service, String action, String actionArgs) {
153
- bridge.execute(() -> {
154
- cordovaPluginManager.exec(service, action, callbackId, actionArgs);
155
- });
156
- }
157
127
  }
@@ -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) {
@@ -329,7 +342,7 @@ public class WebViewLocalServer {
329
342
  if (request.getRequestHeaders().get("Range") != null) {
330
343
  InputStream responseStream = new LollipopLazyInputStream(handler, request);
331
344
  String mimeType = getMimeType(path, responseStream);
332
- Map<String, String> tempResponseHeaders = handler.getResponseHeaders();
345
+ Map<String, String> tempResponseHeaders = handler.buildDefaultResponseHeaders();
333
346
  int statusCode = 206;
334
347
  try {
335
348
  int totalRange = responseStream.available();
@@ -337,6 +350,13 @@ public class WebViewLocalServer {
337
350
  String[] parts = rangeString.split("=");
338
351
  String[] streamParts = parts[1].split("-");
339
352
  String fromRange = streamParts[0];
353
+ int bytesToSkip;
354
+ try {
355
+ bytesToSkip = Integer.parseInt(fromRange);
356
+ if (bytesToSkip > 0) {
357
+ responseStream.skip(bytesToSkip);
358
+ }
359
+ } catch (NumberFormatException ignored) {}
340
360
  int range = totalRange - 1;
341
361
  if (streamParts.length > 1) {
342
362
  range = Integer.parseInt(streamParts[1]);
@@ -365,7 +385,7 @@ public class WebViewLocalServer {
365
385
  handler.getEncoding(),
366
386
  statusCode,
367
387
  handler.getReasonPhrase(),
368
- handler.getResponseHeaders(),
388
+ handler.buildDefaultResponseHeaders(),
369
389
  responseStream
370
390
  );
371
391
  }
@@ -376,7 +396,7 @@ public class WebViewLocalServer {
376
396
  handler.getEncoding(),
377
397
  handler.getStatusCode(),
378
398
  handler.getReasonPhrase(),
379
- handler.getResponseHeaders(),
399
+ handler.buildDefaultResponseHeaders(),
380
400
  null
381
401
  );
382
402
  }
@@ -411,7 +431,7 @@ public class WebViewLocalServer {
411
431
  handler.getEncoding(),
412
432
  statusCode,
413
433
  handler.getReasonPhrase(),
414
- handler.getResponseHeaders(),
434
+ handler.buildDefaultResponseHeaders(),
415
435
  responseStream
416
436
  );
417
437
  }
@@ -442,7 +462,7 @@ public class WebViewLocalServer {
442
462
  handler.getEncoding(),
443
463
  statusCode,
444
464
  handler.getReasonPhrase(),
445
- handler.getResponseHeaders(),
465
+ handler.buildDefaultResponseHeaders(),
446
466
  responseStream
447
467
  );
448
468
  }
@@ -517,7 +537,7 @@ public class WebViewLocalServer {
517
537
  handler.getEncoding(),
518
538
  handler.getStatusCode(),
519
539
  handler.getReasonPhrase(),
520
- handler.getResponseHeaders(),
540
+ handler.buildDefaultResponseHeaders(),
521
541
  responseStream
522
542
  );
523
543
  }
@@ -0,0 +1,148 @@
1
+ package com.getcapacitor.cordova;
2
+
3
+ import android.content.Intent;
4
+ import android.os.Bundle;
5
+ import android.webkit.WebView;
6
+ import com.getcapacitor.Logger;
7
+ import com.getcapacitor.Plugin;
8
+ import com.getcapacitor.android.R;
9
+ import com.getcapacitor.annotation.CapacitorPlugin;
10
+ import java.util.List;
11
+ import org.apache.cordova.ConfigXmlParser;
12
+ import org.apache.cordova.CordovaInterface;
13
+ import org.apache.cordova.CordovaPreferences;
14
+ import org.apache.cordova.CordovaWebView;
15
+ import org.apache.cordova.PluginEntry;
16
+ import org.apache.cordova.PluginManager;
17
+ import org.json.JSONException;
18
+
19
+ @CapacitorPlugin(name = "__CordovaPlugin")
20
+ public class CordovaPlugin extends Plugin {
21
+
22
+ private MockCordovaInterfaceImpl cordovaInterface;
23
+ private CordovaWebView webView;
24
+ private CordovaPreferences preferences;
25
+
26
+ private boolean pluginHadActivityResult = false;
27
+ private boolean pluginHadPermissionResult = false;
28
+
29
+ @Override
30
+ public void load() {
31
+ ConfigXmlParser parser = new ConfigXmlParser();
32
+ parser.parse(getActivity().getApplicationContext());
33
+ preferences = parser.getPreferences();
34
+ preferences.setPreferencesBundle(getActivity().getIntent().getExtras());
35
+ List<PluginEntry> pluginEntries = parser.getPluginEntries();
36
+
37
+ cordovaInterface = new MockCordovaInterfaceImpl(getActivity());
38
+
39
+ MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(getActivity().getApplicationContext());
40
+ mockWebView.init(cordovaInterface, pluginEntries, preferences, bridge.getWebView());
41
+ webView = mockWebView;
42
+ PluginManager pluginManager = mockWebView.getPluginManager();
43
+ cordovaInterface.onCordovaInit(pluginManager);
44
+
45
+ bridge.registerInterceptor("cordova", (postData) -> {
46
+ String callbackId = postData.getString("callbackId");
47
+
48
+ String service = postData.getString("service");
49
+ String action = postData.getString("action");
50
+ String actionArgs = postData.getString("actionArgs");
51
+
52
+ Logger.verbose(
53
+ Logger.tags("Plugin"),
54
+ "To native (Cordova plugin): callbackId: " +
55
+ callbackId +
56
+ ", service: " +
57
+ service +
58
+ ", action: " +
59
+ action +
60
+ ", actionArgs: " +
61
+ actionArgs
62
+ );
63
+
64
+ bridge.execute(() -> {
65
+ pluginManager.exec(service, action, callbackId, actionArgs);
66
+ });
67
+ });
68
+ }
69
+
70
+ @Override
71
+ protected void restoreState(Bundle state) {
72
+ if (state != null) {
73
+ cordovaInterface.restoreInstanceState(state);
74
+ }
75
+ }
76
+
77
+ @Override
78
+ protected void handleRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
79
+ try {
80
+ pluginHadPermissionResult = cordovaInterface.handlePermissionResult(requestCode, permissions, grantResults);
81
+ } catch (JSONException e) {
82
+ Logger.debug("Error on Cordova plugin permissions request " + e.getMessage());
83
+ }
84
+ }
85
+
86
+ @Override
87
+ public boolean hasPermission(String permission) {
88
+ if (permission.equals("DisableDeploy")) {
89
+ return preferences.getBoolean(permission, false);
90
+ }
91
+
92
+ if (permission.equals("KeepRunning")) {
93
+ return preferences.getBoolean(permission, true);
94
+ }
95
+
96
+ return false;
97
+ }
98
+
99
+ @Override
100
+ public boolean hasDefinedRequiredPermissions() {
101
+ boolean currentPermissionResult = pluginHadPermissionResult;
102
+ pluginHadPermissionResult = false;
103
+ return currentPermissionResult;
104
+ }
105
+
106
+ @Override
107
+ protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {
108
+ pluginHadActivityResult = cordovaInterface.onActivityResult(requestCode, resultCode, data);
109
+ }
110
+
111
+ @Override
112
+ public boolean hasRequiredPermissions() {
113
+ boolean currentActivityResult = pluginHadActivityResult;
114
+ pluginHadActivityResult = false;
115
+ return currentActivityResult;
116
+ }
117
+
118
+ @Override
119
+ protected void handleOnNewIntent(Intent intent) {
120
+ webView.onNewIntent(intent);
121
+ }
122
+
123
+ @Override
124
+ protected void handleOnStart() {
125
+ webView.handleStart();
126
+ }
127
+
128
+ @Override
129
+ protected void handleOnResume() {
130
+ webView.handleResume(bridge.shouldKeepRunning());
131
+ }
132
+
133
+ @Override
134
+ protected void handleOnPause() {
135
+ boolean keepRunning = bridge.shouldKeepRunning() || cordovaInterface.getActivityResultCallback() != null;
136
+ webView.handlePause(keepRunning);
137
+ }
138
+
139
+ @Override
140
+ protected void handleOnStop() {
141
+ webView.handleStop();
142
+ }
143
+
144
+ @Override
145
+ protected void handleOnDestroy() {
146
+ webView.handleDestroy();
147
+ }
148
+ }
@@ -7,7 +7,7 @@ import org.apache.cordova.CordovaInterfaceImpl;
7
7
  import org.apache.cordova.CordovaPlugin;
8
8
  import org.json.JSONException;
9
9
 
10
- public class MockCordovaInterfaceImpl extends CordovaInterfaceImpl {
10
+ class MockCordovaInterfaceImpl extends CordovaInterfaceImpl {
11
11
 
12
12
  public MockCordovaInterfaceImpl(AppCompatActivity activity) {
13
13
  super(activity, Executors.newCachedThreadPool());
@@ -20,7 +20,7 @@ import org.apache.cordova.PluginEntry;
20
20
  import org.apache.cordova.PluginManager;
21
21
  import org.apache.cordova.PluginResult;
22
22
 
23
- public class MockCordovaWebViewImpl implements CordovaWebView {
23
+ class MockCordovaWebViewImpl implements CordovaWebView {
24
24
 
25
25
  private Context context;
26
26
  private PluginManager pluginManager;
@@ -32,7 +32,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
32
32
  private WebView webView;
33
33
  private boolean hasPausedEver;
34
34
 
35
- public MockCordovaWebViewImpl(Context context) {
35
+ MockCordovaWebViewImpl(Context context) {
36
36
  this.context = context;
37
37
  }
38
38
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/android",
3
- "version": "8.1.0",
3
+ "version": "8.1.1-dev-20260305T150856.0",
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.1.0"
26
+ "@capacitor/core": "^8.1.0-dev-20260305T150856.0"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"