Skip to content

Commit

Permalink
feat(android): Use addWebMessageListener where available (#5427)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcesarmobile authored Jul 20, 2022
1 parent e8bdef3 commit c2dfe80
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 7 deletions.
2 changes: 2 additions & 0 deletions android/capacitor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ext {
androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.2.0'
androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.8.0'
androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.4.1'
androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.4.0'
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3'
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0'
Expand Down Expand Up @@ -64,6 +65,7 @@ dependencies {
implementation "androidx.activity:activity:$androidxActivityVersion"
implementation "androidx.fragment:fragment:$androidxFragmentVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation "androidx.webkit:webkit:$androidxWebkitVersion"
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
Expand Down
8 changes: 8 additions & 0 deletions android/capacitor/src/main/assets/native-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,18 @@ const nativeBridge = (function (exports) {
}
return null;
};
if (win === null || win === void 0 ? void 0 : win.androidBridge) {
win.androidBridge.onmessage = function (event) {
returnResult(JSON.parse(event.data));
};
}
/**
* Process a response from the native layer.
*/
cap.fromNative = result => {
returnResult(result);
};
const returnResult = (result) => {
var _a, _b;
if (cap.isLoggingEnabled && result.pluginId !== 'Console') {
cap.logFromNative(result);
Expand Down
31 changes: 28 additions & 3 deletions android/capacitor/src/main/java/com/getcapacitor/Bridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.cordova.ConfigXmlParser;
import org.apache.cordova.CordovaPreferences;
import org.apache.cordova.CordovaWebView;
Expand Down Expand Up @@ -97,6 +99,7 @@ public class Bridge {
private String appUrl;
private String appUrlConfig;
private HostMask appAllowNavigationMask;
private Set<String> allowedOriginRules = new HashSet<String>();
// A reference to the main WebView for the app
private final WebView webView;
public final MockCordovaInterfaceImpl cordovaInterface;
Expand Down Expand Up @@ -186,6 +189,7 @@ private Bridge(

// Initialize web view and message handler for it
this.initWebView();
this.setAllowedOriginRules();
this.msgHandler = new MessageHandler(this, webView, pluginManager);

// Grab any intent info that our app was launched with
Expand All @@ -198,6 +202,25 @@ private Bridge(
this.loadWebView();
}

private void setAllowedOriginRules() {
String[] appAllowNavigationConfig = this.config.getAllowNavigation();
String authority = this.getHost();
String scheme = this.getScheme();
allowedOriginRules.add(scheme + "://" + authority);
if (this.getServerUrl() != null) {
allowedOriginRules.add(this.getServerUrl());
}
if (appAllowNavigationConfig != null) {
for (String allowNavigation : appAllowNavigationConfig) {
if (!allowNavigation.startsWith("http")) {
allowedOriginRules.add("https://" + allowNavigation);
} else {
allowedOriginRules.add(allowNavigation);
}
}
}
}

public App getApp() {
return app;
}
Expand All @@ -207,14 +230,13 @@ private void loadWebView() {
String[] appAllowNavigationConfig = this.config.getAllowNavigation();

ArrayList<String> authorities = new ArrayList<>();

if (appAllowNavigationConfig != null) {
authorities.addAll(Arrays.asList(appAllowNavigationConfig));
}
this.appAllowNavigationMask = HostMask.Parser.parse(appAllowNavigationConfig);

String authority = this.getHost();
authorities.add(authority);

String scheme = this.getScheme();

localUrl = scheme + "://" + authority;
Expand All @@ -241,7 +263,6 @@ private void loadWebView() {
if (appUrlPath != null && !appUrlPath.trim().isEmpty()) {
appUrl += appUrlPath;
}

final boolean html5mode = this.config.isHTML5Mode();

// Start the local web server
Expand Down Expand Up @@ -1267,6 +1288,10 @@ public HostMask getAppAllowNavigationMask() {
return appAllowNavigationMask;
}

public Set<String> getAllowedOriginRules() {
return allowedOriginRules;
}

public BridgeWebViewClient getWebViewClient() {
return this.webViewClient;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package com.getcapacitor;

import android.net.Uri;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import androidx.webkit.JavaScriptReplyProxy;
import androidx.webkit.WebMessageCompat;
import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
import org.apache.cordova.PluginManager;

/**
Expand All @@ -13,13 +18,31 @@ public class MessageHandler {
private Bridge bridge;
private WebView webView;
private PluginManager cordovaPluginManager;
private JavaScriptReplyProxy javaScriptReplyProxy;

public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
this.bridge = bridge;
this.webView = webView;
this.cordovaPluginManager = cordovaPluginManager;

webView.addJavascriptInterface(this, "androidBridge");
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)) {
try {
WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener);
} catch (Exception ex) {
webView.addJavascriptInterface(this, "androidBridge");
}
} else {
webView.addJavascriptInterface(this, "androidBridge");
}
}

/**
Expand Down Expand Up @@ -100,9 +123,13 @@ public void sendResponseMessage(PluginCall call, PluginResult successResult, Plu

boolean isValidCallbackId = !call.getCallbackId().equals(PluginCall.CALLBACK_ID_DANGLING);
if (isValidCallbackId) {
final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")";
final WebView webView = this.webView;
webView.post(() -> webView.evaluateJavascript(runScript, null));
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));
}
} else {
bridge.getApp().fireRestoredResult(data);
}
Expand Down
10 changes: 10 additions & 0 deletions core/native-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,20 @@ const initBridge = (w: any): void => {
return null;
};

if (win?.androidBridge) {
win.androidBridge.onmessage = function (event) {
returnResult(JSON.parse(event.data));
};
}

/**
* Process a response from the native layer.
*/
cap.fromNative = result => {
returnResult(result);
};

const returnResult = (result: any) => {
if (cap.isLoggingEnabled && result.pluginId !== 'Console') {
cap.logFromNative(result);
}
Expand Down
1 change: 1 addition & 0 deletions core/src/definitions-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export interface WindowCapacitor {
WEBVIEW_SERVER_URL?: string;
androidBridge?: {
postMessage(data: string): void;
onmessage?: (event: { data: string }) => void;
};
webkit?: {
messageHandlers?: {
Expand Down
8 changes: 8 additions & 0 deletions ios/Capacitor/Capacitor/assets/native-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,18 @@ const nativeBridge = (function (exports) {
}
return null;
};
if (win === null || win === void 0 ? void 0 : win.androidBridge) {
win.androidBridge.onmessage = function (event) {
returnResult(JSON.parse(event.data));
};
}
/**
* Process a response from the native layer.
*/
cap.fromNative = result => {
returnResult(result);
};
const returnResult = (result) => {
var _a, _b;
if (cap.isLoggingEnabled && result.pluginId !== 'Console') {
cap.logFromNative(result);
Expand Down

0 comments on commit c2dfe80

Please sign in to comment.