diff --git a/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java b/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java index b36cffe04b..75e3ace0de 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java +++ b/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java @@ -45,6 +45,7 @@ public class CapConfig { private boolean webContentsDebuggingEnabled = false; private boolean loggingEnabled = true; private boolean initialFocus = true; + private boolean useLegacyBridge = false; private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION; private String errorPath; @@ -128,6 +129,7 @@ private CapConfig(Builder builder) { this.webContentsDebuggingEnabled = builder.webContentsDebuggingEnabled; this.loggingEnabled = builder.loggingEnabled; this.initialFocus = builder.initialFocus; + this.useLegacyBridge = builder.useLegacyBridge; this.minWebViewVersion = builder.minWebViewVersion; this.errorPath = builder.errorPath; @@ -186,6 +188,7 @@ private void deserializeConfig(@Nullable Context context) { ); minWebViewVersion = JSONUtils.getInt(configJSON, "android.minWebViewVersion", DEFAULT_ANDROID_WEBVIEW_VERSION); captureInput = JSONUtils.getBoolean(configJSON, "android.captureInput", captureInput); + useLegacyBridge = JSONUtils.getBoolean(configJSON, "android.useLegacyBridge", useLegacyBridge); webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug); String logBehavior = JSONUtils.getString( @@ -284,6 +287,10 @@ public boolean isInitialFocus() { return initialFocus; } + public boolean isUsingLegacyBridge() { + return useLegacyBridge; + } + public int getMinWebViewVersion() { if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) { Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION); @@ -450,6 +457,7 @@ public static class Builder { private Boolean webContentsDebuggingEnabled = null; private boolean loggingEnabled = true; private boolean initialFocus = false; + private boolean useLegacyBridge = false; private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION; // Embedded @@ -545,6 +553,11 @@ public Builder setCaptureInput(boolean captureInput) { return this; } + public Builder setUseLegacyBridge(boolean useLegacyBridge) { + this.useLegacyBridge = useLegacyBridge; + return this; + } + public Builder setWebContentsDebuggingEnabled(boolean webContentsDebuggingEnabled) { this.webContentsDebuggingEnabled = webContentsDebuggingEnabled; return this; diff --git a/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java b/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java index 76b4831bdc..5e661989ad 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java +++ b/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java @@ -25,16 +25,15 @@ public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPlugi this.webView = webView; this.cordovaPluginManager = cordovaPluginManager; - WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> { - if (isMainFrame) { - postMessage(message.getData()); - javaScriptReplyProxy = replyProxy; - } else { - Logger.warn("Plugin execution is allowed in Main Frame only"); - } - }; - - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && !bridge.getConfig().isUsingLegacyBridge()) { + WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> { + if (isMainFrame) { + postMessage(message.getData()); + javaScriptReplyProxy = replyProxy; + } else { + Logger.warn("Plugin execution is allowed in Main Frame only"); + } + }; try { WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener); } catch (Exception ex) { @@ -123,12 +122,12 @@ public void sendResponseMessage(PluginCall call, PluginResult successResult, Plu boolean isValidCallbackId = !call.getCallbackId().equals(PluginCall.CALLBACK_ID_DANGLING); if (isValidCallbackId) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && javaScriptReplyProxy != null) { + if (bridge.getConfig().isUsingLegacyBridge()) { + legacySendResponseMessage(data); + } else if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && javaScriptReplyProxy != null) { javaScriptReplyProxy.postMessage(data.toString()); } else { - final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")"; - final WebView webView = this.webView; - webView.post(() -> webView.evaluateJavascript(runScript, null)); + legacySendResponseMessage(data); } } else { bridge.getApp().fireRestoredResult(data); @@ -141,6 +140,12 @@ public void sendResponseMessage(PluginCall call, PluginResult successResult, Plu } } + private void legacySendResponseMessage(PluginResult data) { + final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")"; + final WebView webView = this.webView; + webView.post(() -> webView.evaluateJavascript(runScript, null)); + } + private void callPluginMethod(String callbackId, String pluginId, String methodName, JSObject methodData) { PluginCall call = new PluginCall(this, pluginId, callbackId, methodName, methodData); bridge.callPluginMethod(pluginId, methodName, call); diff --git a/cli/src/declarations.ts b/cli/src/declarations.ts index 9a1b5694f0..febbb42fae 100644 --- a/cli/src/declarations.ts +++ b/cli/src/declarations.ts @@ -263,6 +263,15 @@ export interface CapacitorConfig { */ releaseType?: 'AAB' | 'APK'; }; + + /** + * Use legacy [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)) + * instead of the new and more secure [addWebMessageListener](https://developer.android.com/reference/androidx/webkit/WebViewCompat#addWebMessageListener(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E,androidx.webkit.WebViewCompat.WebMessageListener)) + * + * @since 4.5.0 + * @default false + */ + useLegacyBridge: boolean; }; ios?: {