JxBrowser and JCEF
Choosing a solution to embed Chromium into a cross-platform Java desktop application
Join the DZone community and get the full member experience.
Join For FreeWhen looking for a solution to display HTML, execute JavaScript, or use OAuth2 protocol in Java, one often looks for a full-fledged embeddable browser. If you go for Chromium, you can either use JCEF or JxBrowser for integration.
We have gathered the most common comparison points and compiled this guide for you. To help you choose between the libraries, we compare their architecture, functionality, and required integration efforts.
Getting Started
JCEF is an open-source alternative to JxBrowser. It is based on Chromium Embedded Framework (CEF) and allows you to embed a web browser into Java Swing desktop applications.
To start using JCEF, you need to build it yourself. In a nutshell, this process has three steps:
- Configure the environment.
- Compile binaries and Java classes.
- Package it all to JAR and add it to your application.
For this, you can use the official build instruction, it's brief but sufficient to start you off.
JxBrowser is a commercial proprietary library. It's distributed as a single Gradle/Maven dependency or as JAR files.
JxBrowser JAR files contain all necessary binaries and require no additional actions from the developers. The binaries for macOS are notarized and the binaries for Windows are signed.
What's Inside
Both JxBrowser and JCEF use Chromium under the hood.
JCEF is built on top of CEF. This is a well-known C++ framework that has bindings for other programming languages too. The most notorious one would be CefSharp.
JxBrowser uses a proprietary in-house solution for Chromium integration. It is not based on CEF. The same integration layer is also used for DotNetBrowser.
Supported UI Toolkits
JCEF provides a Swing component. If you develop your application using JavaFX or SWT, you will need to use integration bridges. These are SwingNode for JavaFX, and SWT_AWT bridge for SWT.
JxBrowser provides native components for all major UI toolkits: JavaFX, Swing, and SWT. The Quick Start guide demonstrates how to create a simple application for all supported toolkits.
Both libraries are used for creating IDE plug-ins. For example, JetBrains chooses JCEF for IntelliJ platform. And Google chooses JxBrowser for the Flutter plugin.
Embedding for Desktop
The effort required to write a simple desktop application is similar for both libraries. Here is an example with an address bar and the JCEF browser:
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);
}
}
And here’s the same application with 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());
});
}
}
Embedding for Headless
JCEF is not an option for applications without a user interface. It requires a visible Swing UI, otherwise, the browser is not initialized completely.
JxBrowser supports creating functional browsers without a Java window.
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 and Features
JCEF provides a variety of features for managing Chromium networking, printing, handling downloads, etc. But many of the features available in CEF are not yet ported to Java.
JxBrowser provides more features than JCEF. Here're some of them.
Working With DOM
JCEF doesn't have direct access to DOM, it's intentionally designed this way. JxBrowser supports direct access to DOM:
// 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.Interaction Between JavaScript and Java
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));
And JavaScript:
// 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());
Proprietary Codecs and Widewine
The proprietary technologies such as H264 and AAC codecs are disabled by default in both libraries. In the case of JCEF, they're not included in the binaries. To enable them, one must rebuild CEF.
In JxBrowser, the codecs can be enabled programmatically.
EngineOptions options =
EngineOptions.newBuilder(HARDWARE_ACCELERATED)
.enableProprietaryFeature(ProprietaryFeature.AAC)
.enableProprietaryFeature(ProprietaryFeature.H_264)
.enableProprietaryFeature(ProprietaryFeature.WIDEVINE)
.build();
Engine engine = Engine.newInstance(options);
And More
There are more features that are not yet available in JCEF. Some of them are:
- Managing Chromium profiles;
- Managing passwords;
- Auto-filling web forms on a web page;
- The Print Preview dialog;
- SSO support out of the box;
- The <datalist> HTML tag in the off-screen rendering mode;
- Drag-and-drop in the off-screen rendering mode;
- WebRTC and screen sharing;
Architecture
The main architectural difference between the libraries is a processing model. JCEF launches Chromium inside the Java process. While JxBrowser launches Chromium in a separate native process.
The JCEF’s model allows you to initialize Chromium faster, but it has major drawbacks:
- Chromium consumes the memory and CPU of the Java process. The more Chromium instances you create, the more resources are taken from your application.
- Any error or unexpected behavior in Chromium might cause a JVM crash and terminate your Java application with the potential user data lost.
- The Java process becomes susceptible to security vulnerabilities in Chromium.
JxBrowser runs Chromium in a separate process and communicates with it through the IPC. This way, Chromium does not affect the memory usage of the Java process.
If Chromium crashes, the Java process will continue running. JxBrowser even provides the API to let your application know when Chromium crashes. This gives you the ability to restart the browser and restore a user session.
Getting Help
JCEF is an open-source project. If you need help, you can ask your question on the forum or create an issue in the bug tracker. If there is a feature you’d like to have, you can contribute.
JxBrowser is a commercial product by TeamDev. The source code is not available, but the company provides support services. Clients with an active Standard Support subscription can use all new JxBrowser versions for free and receive technical support from JxBrowser engineers directly.]
Updates and Release Cycle
In 2021, JCEF rolled out five releases. Every new release comes with a Chromium version upgrade. The lack of release notes makes it hard to analyze what else is included in the new version.
JxBrowser had 12 releases in 2021. Every release comes with fixes and improvements that are described in detail in the Release Notes. The Chromium is upgraded to the latest stable version within 3–4 weeks after its official release. These upgrades include the latest security patches and fixed vulnerabilities.
Summary
Being open-source and free, JCEF may be a viable solution for open-source, low-budget, or academic projects.
However, it still comes with maintenance costs. Your development team will need time and expertise to cover what is not covered by the JCEF community:
- Maintain the build infrastructure for different platforms.
- Regularly build and package new versions of JCEF.
- Notarize and sign binaries.
- Fix issues and implement new features.
JxBrowser requires no maintenance. You can start using it in five minutes. The library offers more features and native support for all UI toolkits. And if there's an issue or a missing feature, there's technical support.
Published at DZone with permission of Vladyslav Lubenskyi. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments