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 文件