Java 应用程序和网页中的 Javascript 之间的通信

当使用 WebView 显示你自己的自定义网页并且此网页包含 Javascript 时,可能需要在 Java 程序和网页中的 Javascript 之间建立双向通信。

此示例显示如何设置此类通信。

网页应显示输入字段和按钮。单击该按钮时,输入字段中的值将发送到 Java 应用程序,Java 应用程序将对其进行处理。在处理之后,结果被发送到 Javascript,Javascript 又在网页上显示结果。

基本原则是,对于从 Javascript 到 Java 的通信,在 Java 中创建一个对象,该对象被设置到网页中。而对于另一个方向,在 Javascript 中创建一个对象并从网页中提取。

以下代码显示了 Java 部分,我将它保存在一个文件中:

package com.sothawo.test;

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

import java.io.File;
import java.net.URL;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
public class WebViewApplication extends Application {

    /** for communication to the Javascript engine. */
    private JSObject javascriptConnector;

    /** for communication from the Javascript engine. */
    private JavaConnector javaConnector = new JavaConnector();;

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = new File("./js-sample.html").toURI().toURL();

        WebView webView = new WebView();
        final WebEngine webEngine = webView.getEngine();

        // set up the listener
        webEngine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
            if (Worker.State.SUCCEEDED == newValue) {
                // set an interface object named 'javaConnector' in the web engine's page
                JSObject window = (JSObject) webEngine.executeScript("window");
                window.setMember("javaConnector", javaConnector);

                // get the Javascript connector object. 
                javascriptConnector = (JSObject) webEngine.executeScript("getJsConnector()");
            }
        });

        Scene scene = new Scene(webView, 300, 150);
        primaryStage.setScene(scene);
        primaryStage.show();

        // now load the page
        webEngine.load(url.toString());
    }

    public class JavaConnector {
        /**
         * called when the JS side wants a String to be converted.
         *
         * @param value
         *         the String to convert
         */
        public void toLowerCase(String value) {
            if (null != value) {
                javascriptConnector.call("showResult", value.toLowerCase());
            }
        }
    }
}

加载页面后,通过以下调用将 JavaConnector 对象(由内部类定义并创建为字段)设置到网页中:

JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("javaConnector", javaConnector);

用网页检索 javascriptConnector 对象

javascriptConnector = (JSObject) webEngine.executeScript("getJsConnector()");

当调用 JavaConnectortoLowerCase(String) 方法时,转换传入的值,然后通过 javascriptConnector 对象发回。

这是 html 和 javascript 代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Sample</title>
    </head>
    <body>
        <main>
    
            <div><input id="input" type="text"></div>
            <button onclick="sendToJava();">to lower case</button>
            <div id="result"></div>
    
        </main>
    
        <script type="text/javascript">
            function sendToJava () {
                var s = document.getElementById('input').value;
                javaConnector.toLowerCase(s);
            };
    
            var jsConnector = {
                showResult: function (result) {
                    document.getElementById('result').innerHTML = result;
                }
            };
    
            function getJsConnector() {
                return jsConnector;
            };
        </script>
    </body>
</html>

sendToJava 函数调用由 Java 代码设置的 JavaConnector 的方法:

function sendToJava () {
    var s = document.getElementById('input').value;
    javaConnector.toLowerCase(s);
};

并且 Java 代码调用以检索 javascriptConnector 的函数只返回 jsConnector 对象:

var jsConnector = {
    showResult: function (result) {
        document.getElementById('result').innerHTML = result;
    }
};
    
function getJsConnector() {
    return jsConnector;
};

Java 和 Javascript 之间的调用的参数类型不仅限于字符串。有关可能的类型和转换的更多信息,请参阅 JSObject API 文档