【问题标题】:Cannot call JavaFX from WebView JavaScript on Windows (VirtualBox)无法在 Windows (VirtualBox) 上从 WebView JavaScript 调用 JavaFX
【发布时间】:2017-01-08 20:24:17
【问题描述】:

以下代码适用于 Linux,但回调不适用于 Windows(VirtualBox VM)。你能告诉我为什么吗?

Java:

    public class WebViewTest extends Application {
      private Label label = new Label ("...");
      public static void main (String[] args) {
        launch (args);
      }
      @Override
      public void start (Stage stage) throws Exception {
        WebView webView = new WebView ();
        WebEngine webEngine = webView.getEngine ();
        webEngine.setJavaScriptEnabled (true);
        JSObject window = (JSObject) webView.getEngine ().executeScript ("window");
        window.setMember ("java", new Callback ());
        webEngine.load (getClass ().getResource ("WebViewTest.html").toString ());
        BorderPane pane = new BorderPane ();
        pane.setCenter (webView);
        pane.setBottom (label);
        Scene scene = new Scene (pane);
        stage.setScene (scene);
        stage.show ();
      }
      public class Callback {
        public void click () {
        label.setText ("Clicked :-)");
      }
    }
  }

HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>Test</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <button onclick="window.java.click ();">Test</button>
  </body>
</html>

【问题讨论】:

  • 你检查过Firebug会发生什么吗?
  • 我不知道如何在 JavaFX WebView 中使用 Firebug。但是,经过一些调试,window.java 在 Windows 上的值为 undefined
  • 我评论中的链接将告诉您如何将 Firebug 与 JavaFX webview 一起使用。
  • 好的,谢谢,但是简单的手动调试已经告诉我 java 回调没有定义,这就是我卡住的地方。就像没有调用 window.setMember 一样。
  • 尝试先加载 HTML,然后附加 Java 桥。毕竟 JavaScript 只能在存在的 DOM 上执行。

标签: javascript java javafx webview


【解决方案1】:

诀窍是将回调创建为类字段:

private Callback callback = new Callback ();

然后:

webEngine.load (getClass ().getResource ("WebViewTest.html").toString ());
JSObject window = (JSObject) webView.getEngine ().executeScript ("window");
// BUG // window.setMember ("java", new Callback ());
window.setMember ("java", callback);

也许在 Windows 上有一些滥用垃圾收集?我不知道...

【讨论】:

  • window.setMember(...) 可能正在使用弱引用存储回调(例如,通过 WeakHashMap);虽然这似乎不太可能。
【解决方案2】:

window 对象在将新 DOM 加载到 Web 引擎时可能会被替换。尝试在文档加载时设置回调:

Callback callback = new Callback();
webEngine.documentProperty().addListener((obs, oldDoc, newDoc) -> {
    if (newDoc != null) {
        JSObject window = (JSObject) webView.getEngine ().executeScript ("window");
        window.setMember ("java", callback);                
    }
});

(可以看到window对象在加载HTML之前改变了System.out.println(System.identityHashCode(webView.getEngine ().executeScript ("window")),在文档监听器中改变了System.out.println(System.identityHashCode(window))。)

【讨论】:

  • 当我将一些 Java 函数桥接到 JavaFx 的 WebView 时,您帮助了我。我不知道为什么我的“window.utility”对象随机变为“未定义”。我以为我是由于我无法捕捉到的一些 JavaFx 的内部程序。你的回答让我大开眼界!
【解决方案3】:

我遇到了类似的问题,在深入挖掘之后,我发现你应该在渲染你的 html 之后调用window.setMember ("java", new Callback ());,所以这应该可以工作:

JSObject window = (JSObject) webView.getEngine ().executeScript ("window");
webEngine.load (getClass ().getResource ("WebViewTest.html").toString ())
window.setMember ("java", new Callback ());

另请注意,如果您执行重新加载或导航到另一个页面,您将再次失去您的功能。一个可靠的解决方案是:

webEngine.documentProperty().addListener(((observable, oldValue, newValue) -> {
   if (Objects.nonNull(newValue)) {
        JSObject window = (JSObject) webEngine.executeScript("window");
        window.setMember("engine", callback);
    }
}));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2015-12-02
    • 2017-06-04
    • 2013-10-25
    • 2015-09-06
    • 1970-01-01
    相关资源
    最近更新 更多