macOS 下 JavaFX WebView 的显示不正确

Bad display for JavaFX WebView under macOS

我们使用 JavaFX WebView 作为我们的应用内浏览器。它在 Windows 10.

下运行良好

但是,当我们运行在macOS Catalina 10.15.7下,都显示没了发丝。该应用程序 运行 Java 8.


这是我们简单的应用内浏览器的代码。

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();
  
        // 
        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);
                                }
                            }
                        }
                    }
                });
                
                // 
                // 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;
        }
    }
}

知道为什么会这样吗?有什么我可以解决的吗?谢谢

this answer 中所述,您可以尝试使用其他用户代理。前段时间,当我遇到与 Java 1.8.0_66:

类似的问题时,我使用了以下用户代理(在 macOS 上模拟 Firefox)
webView.getEngine().setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:54.0) Gecko/20100101 Firefox/54.0");

这对某些站点有帮助,但对所有站点都没有帮助(例如,Google 地图在上述用户代理中使用了正确的字体,但由于其他问题没有完全加载)。更新到 Java 9(当时是 9.0.1_11)得到了更好的结果。后来我尝试了以下方法:

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);
}

但实际上一个月前我从尝试修复 JavaFX WebView 到学习如何使用 Java Chromium Embedded Framework (JCEF)

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

它在集成期间肯定有更多的开销,但看起来很有希望。

一开始我对 WebView 非常热情,但随着时间的推移遇到了很多错误。首先,我等待错误被修复,但随后出现了更多错误。最后让我沮丧的是登录在某些网站上无法可靠地工作(可能是因为他们使用 Google's reCAPTCHA)。 所以请注意,用户代理修复可能只是暂时有效,如果它能正常工作的话。