JCEF vs JxBrowser

本文对比了基于Chromium的Java库JCEF和JxBrowser,两者都可用于在Java应用中嵌入Web浏览器。JCEF是开源的,需要自行构建和维护,而JxBrowser是商业产品,提供更全面的支持和服务。JxBrowser在功能上更丰富,如DOM操作、JavaScript与Java交互、离屏渲染等,并且在单独进程中运行Chromium,降低了对主应用的影响。选择哪个取决于项目需求、预算和维护能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当寻找一种可以在 Java 中显示 HTML、执行 JavaScript 或使用 OAuth2 协议的解决方案时,人们通常会寻找一种成熟的可嵌入浏览器。 如果您选择 Chromium,则可以使用 JCEF 或 JxBrowser 进行集成。

我们收集了最常见的比较点并为您编写了本指南。 为了帮助您在库之间进行选择,我们比较了它们的架构、功能和所需的集成工作。

Getting Started 入门

JCEF 是 JxBrowser的开源替代品。 它基于 Chromium 嵌入式框架 (CEF),允许您将 Web 浏览器嵌入到 Java Swing 桌面应用程序中。

要开始使用 JCEF,您需要自己构建它。 这个过程分为三个部分:

  1. 配置环境
  2. 编译二进制文件和 Java 类。
  3. 将其全部打包到 JAR 中并将其添加到您的应用程序中。

JxBrowser 是一个商业专有库。 要开始使用 JxBrowser,请将单个依赖项添加到您的 Gradle 或 Maven 应用程序。 或者下载库并将 JxBrowser 添加到类路径中。

JxBrowser JAR 文件包含所有必要的二进制文件,并且不需要开发人员执行额外操作。适用于 macOS 的二进制文件已经过公证,适用于Windows 的二进制文件已经过签署。

里面是什么

JxBrowser 和 JCEF 都在底层使用 Chromium。

JCEF 建立在 CEF 之上。 这是一个著名的 C++ 框架,它也绑定了其他编程语言。

JxBrowser 使用专有的内部解决方案进行 Chromium 集成。 它不基于 CEF。 自 2007 年以来,我们一直在开发它,并在 DotNetBrowser 中使用它。

被支持的UI工具包

JCEF 提供了一个 Swing 组件。 如果您使用 JavaFX 或 SWT 开发应用程序,则需要使用集成桥。 它们是用于 JavaFX 的 SwingNode 和用于 SWT 的 SWT_AWT 桥。

JxBrowser 为所有主要的 UI 工具包提供原生组件:JavaFX、Swing 和 SWT。 在我们的快速入门指南中可查看如何使用任何工具包创建简单的应用程序。

我们的客户还在 Eclipse RCPIntelliJ IDEA 和 NetBeans 插件中使用 JxBrowser。

嵌入桌面

编写一个简单的桌面应用程序所需的工作量对于这两个库来说是相似的。 下面是一个带有地址栏和 JCEF 浏览器的示例:

import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefMessageRouter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
 * This is a simple application with the address bar and JCEF.
 */
public final class JcefExample {

    private static final String URL = "https://teamdev.com";
    private static final boolean OFFSCREEN = false;
    private static final boolean TRANSPARENT = false;

    public static void main(String[] args) {
        if (!CefApp.startup(args)) {
            System.out.println("Startup initialization failed!");
            return;
        }

        CefSettings settings = new CefSettings();
        settings.windowless_rendering_enabled = OFFSCREEN;
        CefApp cefApp = CefApp.getInstance(settings);
        CefClient client = cefApp.createClient();
        client.addMessageRouter(CefMessageRouter.create());
        CefBrowser browser = client.createBrowser(URL, OFFSCREEN, TRANSPARENT);

        JTextField address = new JTextField(URL);
        address.addActionListener(e -> browser.loadURL(address.getText()));

        JFrame frame = new JFrame("JCEF");
        frame.add(address, BorderLayout.NORTH);
        frame.add(browser.getUIComponent(), BorderLayout.CENTER);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.setSize(1280, 900);
        frame.setVisible(true);
    }
}

这是与 JxBrowser 相同的应用程序:

import static com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED;

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

/**
 * This is a simple application with the address bar and JxBrowser.
 */
public final class JxBrowserExample {

    private static final String URL = "https://teamdev.com";

    public static void main(String[] args) {
        Engine engine = Engine.newInstance(HARDWARE_ACCELERATED);
        Browser browser = engine.newBrowser();

        SwingUtilities.invokeLater(() -> {
            final BrowserView view = BrowserView.newInstance(browser);

            JTextField address = new JTextField(URL);
            address.addActionListener(e -> browser.navigation().loadUrl(address.getText()));

            JFrame frame = new JFrame("JxBrowser");
            frame.add(address, BorderLayout.NORTH);
            frame.add(view, BorderLayout.CENTER);
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            frame.setSize(1280, 900);
            frame.setVisible(true);

            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    engine.close();
                }
            });

            browser.navigation().loadUrl(address.getText());
        });
    }
}

无头嵌入

如果您的应用程序在没有 UI 的情况下运行,那么 JCEF 并不适合您。 它需要一个可见的 Swing UI,否则,浏览器不会完全初始化。

使用 JxBrowser,您可以创建具有真正离屏渲染的功能齐全的浏览器。 请看:

import static com.teamdev.jxbrowser.engine.RenderingMode.OFF_SCREEN;

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.ui.Bitmap;
import com.teamdev.jxbrowser.view.swing.graphics.BitmapImage;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

/**
 * An example of the JxBrowser launched without UI.
 */
public final class ServerApplicationExample {

    public static void main(String[] args) {
        Engine engine = Engine.newInstance(OFF_SCREEN);
        Browser browser = engine.newBrowser();
        browser.resize(1280, 1024);

        browser.navigation().loadUrlAndWait("https://teamdev.com");

        // The browser is up and running. Let's take a screenshot and check.
        Bitmap bitmap = browser.bitmap();
        BufferedImage image = BitmapImage.toToolkit(bitmap);
        try {
            ImageIO.write(image, "PNG", new File("screenshot.png"));
        } catch (IOException e) {
            System.out.println("Failed to save an image. " + e.getMessage());
        }
    }
}

应用程序接口(API) 与功能

JCEF provides a variety of features for managing Chromium networking, printing, handling downloads, etc.

JCEF 提供了多种功能来管理 Chromium 网络、打印、处理下载等。

使用 JxBrowser,您可以做同样的事情,甚至更多。 在本节中,我们将演示 JCEF 中没有的功能。

使用 DOM

说到 DOM,您可以将浏览器的全部功能封装到一个可理解的 Java API 中。 浏览此示例或查看指南

// Find nodes in the DOM tree. By a tag name.
List<Element> links = document.findElementsByTagName("a");
// By a CSS selector.
Optional<Element> logo = document.findElementByCssSelector("#logo");
// Or even through JavaScript.
FormElement form = document.frame().executeJavaScript("document.forms[0]");
// Access the attributes.
links.forEach(link -> link.putAttribute("target", "blank"));
// Submit a form.
form.submit();
// Scroll to the element.
logo.ifPresent(l -> l.scrollIntoView(BOTTOM));

JavaScript 和 Java 之间的交互

从 Java 执行 JavaScript 代码,从 JavaScript 调用 Java 方法。 并享受自动类型转换。 浏览此示例或查看指南

// Obtain objects from JavaScript. As a String.
String string = frame.executeJavaScript("'A string literal'");
// As an array.
JsArray array = frame.executeJavaScript("[0, 1, 2, 3, 4]");
// Or as a generic JavaScript object.
JsObject window = frame.executeJavaScript("window");
// Pass any Java object to the JavaScript world.
window.putProperty("java", new MyJavaObject());

模拟用户输入

通过模拟用户交互来加强您的自动化测试和工具。 浏览此示例或查看指南

Point rect = buttonElement.boundingClientRect();
Point center = Point.of(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
browser.dispatch(MousePressed.newBuilder(location)
                             .button(MouseButton.PRIMARY)
                             .build());
browser.dispatch(MouseReleased.newBuilder(location)
                              .button(MouseButton.PRIMARY)
                              .build());

专有编解码器和 Widevine

默认禁用 H264 和 AAC 编解码器等专有技术,但启用它们也非常容易:

EngineOptions options =
        EngineOptions.newBuilder(HARDWARE_ACCELERATED)
                     .enableProprietaryFeature(ProprietaryFeature.AAC)
                     .enableProprietaryFeature(ProprietaryFeature.H_264)
                     .enableProprietaryFeature(ProprietaryFeature.WIDEVINE)
                     .build();
Engine engine = Engine.newInstance(options);

甚至更多

有许多功能您只能在JxBrowser 中找到。 比如:

  • 管理 Chromium 配置文件;
  • 管理密码;
  • 在网页上自动填写网络表单;
  • 打印预览对话框;
  • 开箱即用的 SSO 支持;
  • 离屏渲染模式下的<datalist> HTML标签;
  • 离屏渲染模式下的拖放;
  • WebRTC和屏幕共享;

以及更多

架构

库之间的主要架构差异是处理模型。 JCEF 在 Java 进程中启动 Chromium。 而 JxBrowser 在单独的本机进程中启动 Chromium。

JCEF 的模型允许您更快地初始化 Chromium,但它有几大缺点:

  • Chromium 会消耗 Java 进程的内存和 CPU。 您创建的 Chromium 实例越多,从您的应用程序中占用的资源就越多。
  • Chromium 中的任何错误或意外行为都可能导致 JVM 崩溃并终止您的 Java 应用程序,从而导致潜在的用户数据丢失。
  • Java 进程容易受到 Chromium 中的安全漏洞的影响。

JxBrowser 在单独的进程中运行 Chromium,并通过 IPC 与其通信。 这样,Chromium 就不会影响 Java 进程的内存使用。

如果 Chromium 崩溃,Java 进程将继续运行。 JxBrowser 甚至提供应用程序接口(API) 让您的应用程序知道 Chromium 何时崩溃。 使您能够重新启动浏览器并恢复用户会话。

获取帮助

JCEF 是一个开源项目。 如果您需要帮助,可以在论坛上提问或在错误跟踪器中创建问题。 如果有您想要的功能,请积极提出您的建议和想法

JxBrowser 是为商业公司创建的商业产品。 我们关心我们的客户并提供支持服务。 当您联系我们的客服时,您将直接与我们产品开发的工程师交谈。

如果您发现错误,我们将对其进行修复并在之后为您提供预览版本。 如果缺少某项功能,我们将为您实现并在未来版本之一中发布。

对于高级案例和定制请求,我们将提供最优质的服务。

更新和发布周期

2021 年,JCEF 共推出了五个版本。 每个新版本都附带 Chromium 版本升级。 由于缺少发行说明,因此很难分析新版本中还包含其他哪些内容。

JxBrowser 在 2021 年共推出了 12 个版本。每个版本都附带修复和改进,我们在发行说明中进行了详细描述。 我们会在 Chromium 正式发布后的 3-4 周内将其升级到最新的稳定版本。 这些升级包括最新的安全补丁和修复的漏洞。

总结

就开源和免费方面来讲,JCEF 可能是开源、低预算或学术项目的可行解决方案。

但是,它仍然伴随着维护成本。 您的开发团队将需要更多时间和专业知识来涵盖 JCEF 社区未涵盖的内容:

  • 维护不同平台的构建基础架构。
  • 定期构建和打包新版本的 JCEF。
  • 公证和签署二进制文件。
  • 修复问题并实现新功能。

JxBrowser 不需要维护。 您可以在五分钟内开始使用它。 该库为所有 UI 工具包提供更多功能和原生支持。 如果您缺少该功能、发现问题或有任何疑问,您可以随时与我们联系并获取帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值