Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42642

Bad display for JavaFX WebView under macOS

We are using JavaFX WebView as our in-app browser. It works well under Windows 10.

enter image description here

However, when we run in under macOS Catalina 10.15.7, all display gone hair wire. The app is run on Java 8.

enter image description here


Here's the code for our simple in-app browser.

SimpleSwingBrowser.java

public class SimpleSwingBrowser extends JDialog {
 
    private final JFXPanel jfxPanel = new JFXPanel();
    private WebEngine engine;
    private String loadedURL = null;
    private final JPanel panel = new JPanel(new BorderLayout());
 
    public SimpleSwingBrowser() {
        super(JStock.instance(), JDialog.ModalityType.APPLICATION_MODAL);
        initComponents();
    }

    
    private void initComponents() {
        createScene();
  
        // http://stackoverflow.com/questions/11269632/javafx-hmtleditor-doesnt-react-on-return-key
        jfxPanel.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                if (e.getKeyChar() == 10) {
                    e.setKeyChar((char) 13);
                    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e);
                }
            }
        });

        panel.add(jfxPanel, BorderLayout.CENTER);
        
        getContentPane().add(panel);
        
        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-460)/2, (screenSize.height-680)/2, 460, 680);
    }
    
    private void createScene() {
 
        Platform.runLater(new Runnable() {
            @Override 
            public void run() {
                final WebView view = new WebView();
                engine = view.getEngine();
                
                engine.titleProperty().addListener(new ChangeListener<String>() {
                    @Override
                    public void changed(ObservableValue<? extends String> observable, String oldValue, final String newValue) {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override 
                            public void run() {
                                SimpleSwingBrowser.this.setTitle(newValue);
                            }
                        });
                    }
                });
 
                engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {

                    @Override
                    public void changed(ObservableValue<? extends State> observable, State oldValue, final State newValue) {
                        if (newValue == FAILED) {
                            final int result = JOptionPane.showConfirmDialog(
                                panel,
                                MessagesBundle.getString("error_message_unable_connect_to_internet"),
                                MessagesBundle.getString("error_title_unable_connect_to_internet"),
                                JOptionPane.YES_NO_OPTION);
                            
                            if (result == JOptionPane.YES_OPTION) {
                                if (loadedURL != null) {
                                    engine.load(loadedURL);
                                }
                            }
                        }
                    }
                });
                
                // http://stackoverflow.com/questions/11206942/how-to-hide-scrollbars-in-the-javafx-webview
                // hide webview scrollbars whenever they appear.
                view.getChildrenUnmodifiable().addListener(new ListChangeListener<Node>() {
                    @Override 
                    public void onChanged(Change<? extends Node> change) {
                        Set<Node> deadSeaScrolls = view.lookupAll(".scroll-bar");
                        for (Node scroll : deadSeaScrolls) {
                            scroll.setVisible(false);
                        }
                    }
                });
                
                jfxPanel.setScene(new Scene(view));
            }
        });
    }
 
    public void loadURL(final String url) {
        Platform.runLater(new Runnable() {
            @Override 
            public void run() {
                String tmp = toURL(url);
                
                if (tmp == null) {
                    tmp = toURL("http://" + url);
                }
 
                loadedURL = tmp;
                engine.load(tmp);
            }
        });
    }

    private static String toURL(String str) {
        try {
            return new URL(str).toExternalForm();
        } catch (MalformedURLException exception) {
            return null;
        }
    }
}

Any idea why this happens? Is there anything I can do to resolve? Thanks.

Upvotes: 3

Views: 396

Answers (1)

Pascal
Pascal

Reputation: 122

As also stated in this answer you can try to use another user agent. I used the following user agent (which is simulating Firefox on macOS) some time ago when I had a similar issue with Java 1.8.0_66:

webView.getEngine().setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:54.0) Gecko/20100101 Firefox/54.0");

That did help for some sites but not for all (e.g. Google Maps was using correct font with above user agent but not loading completly due to other issues). Updating to Java 9 (9.0.1_11 at that time) gave better results. Later I tried the following approach:

String userAgent = this.browser.getEngine().getUserAgent();
if (userAgent != null) {
    String[] parts = userAgent.split(" ");
    String manipulatetUserAgent = "";
    for (int i = 0; i < parts.length; i++) {
        if (i > 0) {
            manipulatetUserAgent += " ";
        }
        
        if (parts[i] != null && parts[i].contains("JavaFX")) {
             manipulatetUserAgent += "Version/13.1.1"; // current safari version
        } else {
            manipulatetUserAgent += parts[i];
        }
    }
    this.browser.getEngine().setUserAgent(manipulatetUserAgent);
}

But actually some month ago I went from trying to fix JavaFX WebView to learning how to use Java Chromium Embedded Framework (JCEF) which is

a simple framework for embedding Chromium-based browsers in other applications using the Java programming language.

It certainly has more overhead during integration but it looks promising.

I was really enthusiatic about WebView at the beginning but encountered to many bugs over time. First I waited for the bugs to be fixed, but then more bugs appeared. Last thing that was frustrating me was login not working reliably on some sites (probably because they were using Google's reCAPTCHA). So be aware that the user agent fix may only help temporary if it's working at all.

Upvotes: 1

Related Questions