For many years, SWT has had a built-in browser component. That is a simplistic component that relies on a web engine from the operating system. The component works well for displaying web pages and handling simple tasks. But it’s not sufficient for more advanced cases where you need to have consistent behavior across platforms, more control over the engine, user data isolation, et cetera.
That’s why many developers look for alternatives like JxBrowser. With a richer API and a single browser engine across platforms, JxBrowser is the most popular replacement for the built-in browser.
In this guide, we give you code examples for replacing every method in
the SWT Browser
API and links to the related JxBrowser documentation.
This guide is about how to migrate to JxBrowser. To learn more about why, checkout the JxBrowser or SWT Browser article where we explain the technical and architectural difference between the solutions.
JxBrowser
JxBrowser is a commercial library that embeds Chromium into Java applications.
It provides a much wider set of features compared to the built-in Browser
, and
web view component that natively supports SWT and Eclipse RCP applications.
On every operating system, the library works with the same version of Chromium that is supplied within the library. This ensures stable and consistent behavior and rendering on every operating system.
Being a commercial software, the library comes with unlimited hours of technical assistance, bug fixes, and the ability to request a new feature.
The API surface of built-in browser and JxBrowser.
Dependencies for SWT projects
Adding JxBrowser to the project is as simple as adding a couple of JAR files to the classpath. For example, an SWT application that runs on Windows will need the following files:
jxbrowser-8.6.0.jar
. This file contains most of the JxBrowser API.jxbrowser-swt-8.6.0.jar
. This file contains the SWT component of JxBrowser.jxbrowser-win64-8.6.0.jar
. This file contains Chromium binaries for 64‑bit Windows.
You can download the necessary files from the JxBrowser 8.6.0 release notes.
If you’re using plain Maven or Gradle, you can add JxBrowser the usual way, by adding dependencies from our Maven repo.
Dependency for Eclipse RCP
If you’re using Apache Tycho, you know that nothing comes easy in life. But we’ve got your back. In our tutorial on adding JxBrowser to Eclipse RCP applications, we cover:
- How to use Maven to download JxBrowser dependencies at build time.
- How to use fragments to distribute Chromium binaries for multiple platforms.
Migration
Thread safety
Like with the other UI components in SWT, you should only use the Browser
in the UI thread.
JxBrowser is thread-safe: you can safely use JxBrowser objects in different threads. But be mindful about calling the JxBrowser API in the UI thread as many of its methods are synchronous. To avoid glitches in user experience, we generally don’t recommend calling JxBrowser in the UI thread.
Creating the browser
In SWT, creating the browser is as simple as it gets. This code snippet adds
the web view component to the parent
and loads a web page:
var browser = new Browser(shell, SWT.NONE);
browser.setUrl("https://www.example.com");
...
// Dispose the browser when it's not needed anymore.
browser.dispose();
In JxBrowser, the similar logic looks like this:
var engine = Engine.newInstance(HARDWARE_ACCELERATED);
var browser = engine.newBrowser();
var view = BrowserView.newInstance(shell, browser);
browser.navigation().loadUrl("https://example.com");
...
// Close the browser when it's not needed anymore.
browser.close();
// Or close the engine. More on the difference in a moment.
engine.close();
As you see, there is more code with JxBrowser, but there is also more control.
Modern browsers have complex process models, security features, and different
ways to render web content. However, the SWT Browser
API doesn’t reflect this
complexity because it wasn’t designed for this. Its idea is to be simple and
engine-agnostic.
JxBrowser, however, is based solely on the Chromium engine and gives you nuanced control over it. Let’s break down the previous code snippet and see what this control includes.
We start by creating an Engine
, which starts the main Chromium process.
You can think of it as opening Google Chrome on your computer:
var engine = Engine.newInstance(HARDWARE_ACCELERATED);
Then, we create a new browser. You can think of it as a single tab in Google
Chrome. As with the tabs, you can create as many Browser
instances as
you need:
var browser = engine.newBrowser();
The created browser object is fully functional. You can’t see it yet, but you can load web pages and fetch information from it:
browser.navigation().loadUrl("https://example.com");
And finally, you can show the browser in the UI by adding an SWT component,
BrowserView
:
var view = BrowserView.newInstance(shell, browser);
We describe this and other architectural details in great detail in our documentation.
Closing the browser
In SWT, you should dispose of the browser when you no longer need it:
browser.dispose();
In JxBrowser, you need to close the browser too, but you have a choice: either a single “tab” or the engine with all created browsers at once:
// You can close a single "tab".
browser.close()
// Or you can close the whole engine, which will automatically
// close all the browsers created within it.
engine.close();
In SWT, you can receive a notification that the browser is closed. It comes only
when a JavaScript closes the page by calling window.close()
:
browser.addCloseWindowListener(event -> {
// The browser has been closed by JavaScript.
});
In JxBrowser, the equivalent event will come regardless of how the browser was closed:
browser.on(BrowserClosed.class, event -> {
// The browser has been closed by JavaScript,
// or by calling browser.close(), or engine.close().
});
Navigation methods
Most of the navigation methods in SWT Browser have a one-to-one counterpart in JxBrowser:
browser.setUrl("https://example.com");
var url = browser.getUrl();
browser.reload();
browser.stop();
browser.back();
browser.forward();
var canGoBack = browser.isBackEnabled();
var canGoForward = browser.isForwardEnabled();
var navigation = browser.navigation();
navigation.loadUrl("https://example.com");
var url = browser.url();
navigation.reload();
navigation.stop();
navigation.goBack();
navigation.goForward();
var canGoBack = navigation.canGoBack();
var canGoForward = navigation.canGoForward();
You can load a URL with a POST payload and additional headers in both browsers. In SWT, you specify data and headers as raw strings. In JxBrowser, we have a higher-level API:
var url = "https://example.com/login";
var postData = "username=user&password=secret";
var headers = new String[] {
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer xyz1234"
};
browser.setUrl(url, postData, headers);
var url = "https://example.com/login";
var formData = FormData.newBuilder()
.addPair(Pair.of("username", "user"))
.addPair(Pair.of("password", "secret"))
.build();
var header = HttpHeader.of("Authorization", "Bearer xyz1234");
var params = LoadUrlParams.newBuilder(url)
.addExtraHeader(header)
.uploadData(formData)
.build();
navigation.loadUrl(params);
Location listener
In SWT, you register a LocationListener
to monitor when the location loaded in
the browser changes. In JxBrowser, you do this by subscribing to
the NavigationFinished
event:
browser.addLocationListener(new LocationAdapter() {
@Override
public void changed(LocationEvent event) {
var url = event.location;
var isMainFrame = event.top;
}
});
navigation.on(NavigationFinished.class, event -> {
var url = event.url();
var frame = event.frame();
var hasCommitted = event.hasCommitted();
var isSameDocument = event.isSameDocument();
var isErrorPage = event.isErrorPage();
if (isErrorPage) {
var error = event.error();
}
});
There are nine granular navigation events in JxBrowser. Check the complete list.
In SWT, the LocationListener
is also used to prevent unwanted navigation.
In JxBrowser, you can achieve this by registering StartNavigationCallback
:
browser.addLocationListener(new LocationAdapter() {
@Override
public void changing(LocationEvent event) {
var url = event.location;
if (...) {
event.doit = true;
} else {
event.doit = false;
}
}
});
navigation.set(StartNavigationCallback.class, params -> {
var url = params.url();
var isRedirect = params.isRedirect();
var isMainFrame = params.isMainFrame();
if (...) {
return StartNavigationCallback.Response.start();
} else {
return StartNavigationCallback.Response.ignore();
}
});
Progress listener
In SWT, you get events about the page loading progress, and, in particular, about the loading completion.
In JxBrowser, you can’t check the loading progress, but you can detect when the page is fully loaded, and you can use it:
browser.addProgressListener(new ProgressAdapter() {
@Override
public void completed(ProgressEvent event) {
// A location has been completely loaded.
}
});
// Check if the HTML document has been fully loaded.
browser.navigation().on(FrameDocumentLoadFinished.class, event -> {
var frame = event.frame();
var isMainFrame = frame.isMain();
frame.document().ifPresent(document -> {
var element = document.documentElement();
});
});
JxBrowser doesn’t provide an API equivalent to
the ProgressLister.changed(ProgressEvent)
method.
Calling JavaScript from Java
In SWT, you execute the JavaScript code in the current document by calling
the execute()
and evaluate()
methods. If possible, the latter automatically
converts the return value to the Java primitive type and String
. Both are
synchronous:
boolean isSuccessful = browser.execute("document.documentElement");
String zipCode = browser.evaluate("getZipCode()");
In JxBrowser, you can execute JavaScript in the context of any frame, and JxBrowser will convert the return value to one of 11 available types:
Element element = frame.executeJavaScript("document.documentElement");
String zipCode = frame.executeJavaScript("getZipCode()");
// There is an asynchronous version too:
frame.executeJavaScript("longOperation()", (result) -> {
// The result of the non-blocking JavaScript call.
});
In SWT, you can turn JavaScript on and off. In JxBrowser, we have drop-in replacements for these methods:
browser.setJavascriptEnabled(false);
var isEnabled = browsser.getJavascriptEnabled();
var settings = browser.settings();
settings.enableJavaScript();
settings.disableJavaScript();
var isEnabled = settings.isJavaScriptEnabled();
Calling Java from JavaScript
In SWT, you need to register BrowserFunction
to call Java code from
JavaScript. This function will be accessible in all web pages until it’s
disposed of. The types of arguments and the return values will be automatically
converted to a corresponding Java primitive type and String
.
// This function will be available in the top frame and two other frames
// as `sayHello()`.
var function = new BrowserFunction(br, "sayHello") {
@Override
public Object function(Object[] args) {
return "Hello from Java!";
}
};
...
function.dispose();
In JxBrowser, you can inject arbitrary Java objects into JavaScript, but only when the frame is ready. You don’t need to close injected objects, as this will happen automatically when the page is reloaded.
// This callback is invoked when the document has been created,
// and before the page executes its own scripts.
browser.set(InjectJsCallback.class, params -> {
var frame = params.frame();
JsObject window = frame.executeJavaScript("window");
window.putProperty("sayHello", (JsFunctionCallback) args -> {
return "Hello from Java!";
});
return InjectJsCallback.Response.proceed();
});
Loading HTML
In both browsers, you can load a simple HTML from memory:
browser.setText("<html>Hello</html>");
frame.loadHtml("<html>Hello</html>");
In JxBrowser, the loadHtml()
method works by loading a data URL from
the given HTML, limiting the page size to ~2 MB.
To exceed this limit and cover other advanced cases, check our guide on loading HTML and local resources.
Fetching page content
In SWT, you can use the getText()
of the browser to read the HTML
of the page. In JxBrowser, you will need to get the
inner or outer HTML of the document:
var html = browser.getText();
frame.document().flatMap(Document::documentElement).ifPresent(element -> {
var innerHtml = element.innerHtml();
var outerHtml = element.outerHtml();
});
Status line and title
In both browsers, you can receive notifications when the status line changes:
browser.addStatusTextListener(event -> {
var newStatus = event.text;
});
browser.on(StatusChanged.class, event -> {
var newStatus = event.statusText();
});
You can track the page title changes similarly:
browser.addTitleListener(event -> {
var newTitle = event.title;
});
browser.on(TitleChanged.class, event -> {
var newTitle = event.title();
});
Cookies
You can read existing cookies in SWT using the getCookie()
method.
In JxBrowser, you can read the cookies using the CookieStore
:
String cookie = Browser.getCookie("auth_token", "https://example.com");
var cookieStore = browser.profile().cookieStore();
for (Cookie cookie : cookieStore.cookies("https://example.com")) {
String domain = cookie.domain();
Timestamp expiration = cookie.expirationTime();
...
}
To create a new cookie, use setCookie()
in SWT and CookieStore.set()
in
JxBrowser:
Browser.setCookie("auth_token=abc123; Path=/;", "https://example.com");
var cookieStore = browser.profile().cookieStore();
var cookie = Cookie.newBuilder("example.com")
.name("auth_token")
.value("abc123")
.path("/")
.build();
cookieStore.set(cookie);
Similarly, you can clean up the cookies:
Browser.clearSessions();
// Delete a specific cookie.
cookieStore.delete(cookie);
// Delete all the cookies.
cookieStore.deleteAll();
Authentication
In SWT, you register an AuthenticationListener
to handle server requests for
authentication automatically. In JxBrowser, you will need to
use AuthenticateCallback
:
browser.addAuthenticationListener(event -> {
var url = event.location;
if (...) {
event.user = "username";
event.password = "password";
event.doit = true;
} else {
event.doit = false;
}
});
var network = browser.profile().network();
network.set(AuthenticateCallback.class, (params, action) -> {
var url = params.url();
var proxy = params.isProxy();
var scheme = params.scheme();
var hostPort = params.hostPort();
if (...) {
action.authenticate("username", "password");
} else {
action.cancel();
}
});
Popups
When a web page wants to open a new pop-up window, SWT sends you an event. Depending on the event, the OS will create the new browser window for you, or let your application create it:
browser.addOpenWindowListener(event -> {
if (event.required) {
// Your application is required to create a window for the pop-up.
event.browser = new Browser(shell, SWT.NONE);
} else {
// Operating system will create the pop-up.
}
});
JxBrowser automatically creates the browser object for the new pop-up. It’s up
to you to show it in the user interface or use it off-screen. By default,
JxBrowser will open a pop-up in a new Shell
:
// First, allow creating a pop-up browser.
browser.set(CreatePopupCallback.class, e -> {
var url = e.targetUrl();
var name = e.targetName();
if (...) {
return CreatePopupCallback.Response.create();
} else {
return CreatePopupCallback.Response.suppress();
}
});
browser.set(OpenPopupCallback.class, e -> {
var popupBrowser = e.popupBrowser();
var bounds = e.initialBounds();
var scaleFactor = e.scaleFactor();
// You can embed the `popupBrowser` into the UI here.
return OpenPopupCallback.Response.proceed();
});
JxBrowser allows you to programmatically handle JavaScript, file, color picker, and other dialogs. Learn how in the guide on dialogs.
Conclusion
Migrating from SWT’s browser to JxBrowser is essentially a matter of translating API calls, as most methods have direct equivalents in JxBrowser.
In this guide, we provided the drop-in replacements from JxBrowser API for every SWT Browser, covering the entire Browser API.
While the real-world migration may be hard, we believe it should not be. This guide is a good starting point to learn how JxBrowser can replace the SWT browser in your application.
Sending…
Sorry, the sending was interrupted
Please try again. If the issue persists, contact us at info@teamdev.com.
Your personal JxBrowser trial key and quick start guide will arrive in your Email Inbox in a few minutes.