Cannot call JavaFX from WebView JavaScript on Windows (VirtualBox)

和自甴很熟 提交于 2019-12-25 07:48:11

问题


The following code works on Linux, but the callback does not work on Windows (VirtualBox VM). Can you please tell me why?

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>

回答1:


The trick was to create the Callback as a class field:

private Callback callback = new Callback ();

And then:

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

Maybe there is some abusive garbage collecting on Windows? I don't know...




回答2:


The window object is likely replaced when a new DOM is loaded into the web engine. Try setting the callback when the document is loaded:

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

(You can see that the window object changes by System.out.println(System.identityHashCode(webView.getEngine ().executeScript ("window")) before loading the HTML, and System.out.println(System.identityHashCode(window)) in the document listener.)




回答3:


I had a similar problem and after digging deep, I found out that you are supposed to call window.setMember ("java", new Callback ()); after rendering your html so this should work:

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

Also note that if you perform a reload or if you navigate to another page, you will lose your functionality again. A solid solution will be:

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


来源:https://stackoverflow.com/questions/41537474/cannot-call-javafx-from-webview-javascript-on-windows-virtualbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!