Introduction
Installation
Guides
- Engine
- Profile
- Browser
- BrowserView
- Navigation
- Content
- DOM
- JavaScript
- Pop-ups
- Dialogs
- Downloads
- Network
- Cache
- Cookies
- Proxy
- Authentication
- Plugins
- Printing
- Passwords
- User Data Profiles
- Credit Cards
- Media
- Zoom
- Spell Checker
- Deployment
- Chromium
Troubleshooting
Migration
The 7.0 version of JxBrowser introduces a major improvement to both internals and the public API of the library. This guide shows how to change your application code written with JxBrowser version 6.x to work with version 7.0.
Overview
Why Migrate?
We recommend you to update your code to the latest version because all the new features, Chromium upgrades, support of the new operating systems and JDKs, bug fixes, security patches, performance, and the memory usage enhancements are applied on top of the latest version.
How Long Does It Take?
From our experience, upgrade to the new major version takes from a couple of hours to a few days depending on the number of the features you use in your application. As usual, we strongly recommend to test your software after the upgrade in all the environments it supports.
Getting Help
Please check out the FAQ section at the end of this guide. Maybe the answer to your question is already there.
In case you did not find the answer in this guide and you need assistance with migration, please contact us. We will be happy to help.
Key Changes
API & Architecture
In JxBrowser 7 the architecture of the library has been improved. Now JxBrowser allows you to create two absolutely independent Browser
instances and control their life cycle. Along with this internal architecture change the public API has been improved and extended with the new features as well.
Please see the Mapping section to find out how the main functionality of 6.x maps to 7.0.
System Requirements
Starting with this version JxBrowser no longer supports Oracle JREs 1.6 and 1.7, Apple’s and IBM’s JREs, macOS 10.9, and OSGi. Current System Requirements are available here.
JARs
The structure of the library has changed. Now the library consists of the following JARs:
jxbrowser-7.36.3.jar
— the core classes and interfaces;jxbrowser-swing-7.36.3.jar
— the classes and interfaces for embedding into a Swing app;jxbrowser-javafx-7.36.3.jar
— the classes and interfaces for embedding into a JavaFX app;jxbrowser-win32-7.36.3.jar
— the Chromium 32-bit binaries for Windows;jxbrowser-win64-7.36.3.jar
— the Chromium 64-bit binaries for Windows;jxbrowser-linux64-7.36.3.jar
— the Chromium 64-bit binaries for Linux;jxbrowser-mac-7.36.3.jar
— the Chromium binaries for macOS.
Basic Concepts
The way to create and dispose the objects has changed in the new API.
To create a service object use the <ServiceObject>.newInstance()
static method. For example:
Engine engine = Engine.newInstance(options);
val engine = Engine.newInstance(options)
To create an immutable data object use the Object.newBuilder()
static method. For example:
EngineOptions engineOptions = EngineOptions.newBuilder(...)
.setLanguage(Language.ENGLISH_US)
.build();
val options = EngineOptions.newBuilder(...)
.language(Language.ENGLISH_US)
.build()
Every object that should be disposed manually implements the com.teamdev.jxbrowser.Closable
interface, e.g. com.teamdev.jxbrowser.Browser
. To dispose the object call the com.teamdev.jxbrowser.Closable.close()
method. For example:
browser.close();
browser.close()
Please note that some service objects depend on the other service objects. When you dispose a service object, all the service objects depending on it will be disposed automatically, so you do not need to close them manually. Please see the Architecture guide for more details about the key objects and their interaction principles.
If a method can return null
, its return value is wrapped into the java.util.Optional
. For example:
browser.mainFrame().ifPresent(frame -> {});
browser.mainFrame().ifPresent { frame -> }
Events
The way to register an event listener has changed.
v6.x
We use a classic Observer pattern that consists of the addXxxListener(XxxListener listener)
and removeXxxListener(XxxListener listener)
methods that allow you to register and unregister an event listener. For example:
TitleListener titleListener = new TitleListener() {
@Override
public void onTitleChange(TitleEvent event) {}
};
browser.addTitleListener(titleListener);
val titleListener = object: TitleListener {
override fun onTitleChanged(event: TitleEvent) {}
}
browser.addTitleListener(titleListener)
The event listener should be unregistered using an appropriate method when you do not want to receive the event notifications:
browser.removeTitleListener(titleListener);
browser.removeTitleListener(titleListener)
v7.0
A service object that allows registering event observers implements the com.teamdev.jxbrowser.event.Observable
interface. To register an event observer use the on(Class<E> eventClass, Observer<E> observer)
method. This method returns Subscription
. Use this instance to unsubscribe from receiving the required events. For example:
Subscription subscription = browser.on(TitleChanged.class, event -> {});
...
subscription.unsubscribe();
val subscription = browser.on(TitleChanged::class.java) { event -> }
...
subscription.unsubscribe()
Callbacks
The logic of registering event handlers (callbacks) has changed as well.
v6.x
To register an event handler use the setXxxHandler(XxxHandler handler)
method to set and remove an event handler. For example:
browser.setDialogHandler(new DialogHandler() {
...
@Override
public CloseStatus onConfirmation(DialogParams params) {
return CloseStatus.OK;
}
...
});
browser.setDialogHandler(null);
browser.setDialogHandler(object: DialogHandler {
...
override fun onConfirmation(params: DialogParams): CloseStatus = CloseStatus.OK
...
})
v7.0
Event handlers are now named Callbacks. Each object that allows registering callbacks implements the com.teamdev.jxbrowser.callback.Advisable
interface. To register and unregister a callback the set(Class<C> callbackClass, C callback)
and remove(Class<C> callbackClass)
methods should be used. For example:
browser.set(ConfirmCallback.class, (params, tell) -> tell.ok());
browser.remove(ConfirmCallback.class);
browser.set(ConfirmCallback::class.java, ConfirmCallback { params, tell -> tell.ok() })
browser.remove(ConfirmCallback::class.java)
Please do not forget to return the result through the given tell
parameter, otherwise the engine will wait blocked until termination.
Thread Safety
The library is not thread-safe, so please do not work with the library from different threads at the same time.
Licensing
In JxBrowser 7 the license format and the way how the library checks the license has been improved.
v6.x
In the previous version the license represents a JAR file (e.g. license.jar
) with the teamdev.licenses
text file inside. This text file contains the plain text of the license. To setup the license you must include this JAR file in your Java app classpath.
The Project license is tied to a fully qualified class name (e.g. com.company.product.MyClass
). It can be any class of your application. The only requirement is that this class must be included in the classpath of your Java app where you use JxBrowser.
v7.0
Now, the library requires a license key that represents a string with combination of letters and digits. You can add the license to your project via the jxbrowser.license.key
System Property or through the API.
The Project license is tied to a package name now. The package name is expected to be in the com.company.product.module
format. It should be a top-level package for the classes where you create an Engine
instance.
For example, if the Project license is tied to the com.company.product
package name, then you can create Engine
instances only in the classes located in the com.company.product.*
packages.
The Engine
was introduced in JxBrowser 7. We recommend that you check out the guide that describes the new architecture, how to create an Engine
and manage multiple Browser
s lifecycle.
You can work with the created Engine
instance and make calls to the library’s API from the classes located in other packages without any restrictions.
Dropped Functionality
Starting with this version JxBrowser no longer supports Oracle JREs 1.6 and 1.7, Apple’s and IBM’s JREs, macOS 10.9, and OSGi.
In the new version the following functionality has been temporarily dropped. We are going to provide alternatives in the next updates:
- Taking screenshots of the loaded web page. Restored in 7.1.
- Suppressing mouse and keyboard events. Restored in 7.1.
- Displaying the
BeforeUnload
dialog when closingBrowser
. The possibility to display the dialog when closingBrowser
was restored in 7.6. Read more. - Transparent background in the off-screen rendering mode. Restored in 7.2.
- IME, Accessibility, and “Pinch to zoom” on macOS in the hardware accelerated (heavyweight) rendering mode.
WebStorage
API. Restored in 7.1.- The
SWT_AWT
andFXCanvas
bridges that allow embedding Swing/JavaFXBrowserView
into SWT UI. Instead, please use SWTBrowserView
introduced in 7.7.
Mapping
In this section we will show how the main functionality of 6.x maps to 7.0.
Engine
Creating Engine
6.x
The Engine
is not a part of the public API. It is created internally when the first Browser
instance is created in the application. Only one Engine
can be created and used in the application.
7.0
The Engine
is a part of the public API now. You can create and use multiple Engine
instances in the application. To create an Engine
instance with the required options use the following code:
Engine engine = Engine.newInstance(
EngineOptions.newBuilder(RenderingMode.OFF_SCREEN)
// The language used on the default error pages and GUI.
.language(Language.ENGLISH_US)
// The absolute path to the directory where the data
// such as cache, cookies, history, GPU cache, local
// storage, visited links, web data, spell checking
// dictionary files, etc. is stored.
.userDataDir(Paths.get("/Users/Me/JxBrowser/UserData"))
.build());
val engine = Engine.newInstance(
EngineOptions.newBuilder(RenderingMode.OFF_SCREEN)
// The language used on the default error pages and GUI.
.language(Language.ENGLISH_US)
// The absolute path to the directory where the data
// such as cache, cookies, history, GPU cache, local
// storage, visited links, web data, spell checking
// dictionary files, etc. is stored.
.userDataDir(Path("/Users/Me/JxBrowser/UserData"))
.build()
)
The Engine
runs a separate native process where the Chromium with the provided options is created and initialized. The native process communicates with the Java process via the Inter-Process Communication (IPC) bridge. If the native process is unexpectedly terminated because of a crash, the Java process will continue running.
You can use the following notification to find out when the Engine
is unexpectedly terminated, so that you can re-create the Engine and restore the Browser
instances:
engine.on(EngineCrashed.class, event -> {
// Clear all the allocated resources and re-create the Engine.
});
engine.on(EngineCrashed::class.java) { event ->
// Clear all the allocated resources and re-create the Engine.
}
Closing Engine
6.x
The Engine
is closed automatically when the last Browser
instance is closed in the application.
7.0
The Engine
should be closed manually via the close()
method when it is no longer required:
engine.close();
engine.close()
When you close the Engine
, all its Browser
instances are closed automatically. Any attempt to use an already closed Engine
will lead to an exception.
To find out when the Engine
is closed use the following notification:
engine.on(EngineClosed.class, event -> {});
engine.on(EngineClosed::class.java) { event -> }
Browser
Creating Browser
6.x
Browser browser = new Browser();
val browser = Browser()
7.0
Browser browser = engine.newBrowser();
val browser = engine.newBrowser()
Creating Browser with Options
6.x
BrowserContextParams browserContextParams =
new BrowserContextParams("Users/Me/JxBrowser/Data");
browserContextParams.setStorageType(StorageType.MEMORY);
BrowserContext browserContext = new BrowserContext(browserContextParams);
Browser browser = new Browser(BrowserType.HEAVYWEIGHT, browserContext);
val browserContextParams = BrowserContextParams("Users/Me/JxBrowser/Data")
browserContextParams.setStorageType(StorageType.MEMORY)
val browserContext = BrowserContext(browserContextParams)
val browser = Browser(BrowserType.HEAVYWEIGHT, browserContext)
7.0
The BrowserContext
functionality has been moved to Engine
. So, the same code should be replaced with:
Engine engine = Engine.newInstance(EngineOptions.newBuilder(HARDWARE_ACCELERATED)
.userDataDir(Paths.get("/Users/Me/JxBrowser/UserData"))
.enableIncognito()
.build());
Browser browser = engine.newBrowser();
val engine = Engine.newInstance(EngineOptions.newBuilder(HARDWARE_ACCELERATED)
.userDataDir(Path("/Users/Me/JxBrowser/UserData"))
.enableIncognito()
.build()
)
val browser = engine.newBrowser()
Closing Browser
6.x
browser.dispose();
browser.dispose()
7.0
browser.close();
browser.close()
Responsive/Unresponsive
6.x
browser.addRenderListener(new RenderAdapter() {
@Override
public void onRenderUnresponsive(RenderEvent event) {}
@Override
public void onRenderResponsive(RenderEvent event) {}
});
browser.addRenderListener(object: RenderAdapter {
override fun onRenderUnresponsive(event: RenderEvent) {}
override fun onRenderResponsive(event: RenderEvent) {}
})
7.0
browser.on(BrowserBecameResponsive.class, event -> {});
browser.on(BrowserBecameUnresponsive.class, event -> {});
browser.on(BrowserBecameResponsive::class.java) { event -> }
browser.on(BrowserBecameUnresponsive::class.java) { event -> }
BrowserView
Creating Swing BrowserView
6.x
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
...
BrowserView view = new BrowserView(browser);
import com.teamdev.jxbrowser.chromium.swing.BrowserView
...
val view = BrowserView(browser)
7.0
import com.teamdev.jxbrowser.view.swing.BrowserView;
...
BrowserView view = BrowserView.newInstance(browser);
import com.teamdev.jxbrowser.view.swing.BrowserView
...
val view = BrowserView.newInstance(browser)
Creating JavaFX BrowserView
6.x
import com.teamdev.jxbrowser.chromium.javafx.BrowserView;
...
BrowserView view = new BrowserView(browser);
import com.teamdev.jxbrowser.chromium.javafx.BrowserView
...
val view = BrowserView(browser)
7.0
import com.teamdev.jxbrowser.view.javafx.BrowserView;
...
BrowserView view = BrowserView.newInstance(browser);
import com.teamdev.jxbrowser.view.javafx.BrowserView
...
val view = BrowserView.newInstance(browser)
Frame
Working with Frame
6.x
A web page may consist of the main frame that may contain multiple sub-frames. To perform an operation with a frame you need to pass the frame’s identifier to the corresponding method. For example:
// Get HTML of the main frame.
browser.getHTML();
// Get HTML of the all frames.
for (Long frameId : browser.getFramesIds()) {
String html = browser.getHTML(frameId);
}
// Get HTML of the main frame.
browser.html
// Get HTML of the all frames.
for (frameId in browser.framesIds) {
val html = browser.getHTML(frameId)
}
7.0
The Frame
is a part of the public API now. You can work with the frame through the Frame
instance. For example:
// Get HTML of the main frame if it exists.
browser.mainFrame().ifPresent(Frame::getHtml);
// Get HTML of all the frames.
browser.frames().forEach(frame -> {
String html = frame.html();
});
// Get HTML of the main frame if it exists.
browser.mainFrame().ifPresent(Frame::getHtml)
// Get HTML of all the frames.
browser.frames().forEach { frame ->
val html = frame.html()
}
Navigation
Loading URL
6.x
browser.loadURL("https://www.google.com");
browser.loadURL("https://www.google.com")
7.0
browser.navigation().loadUrl("https://www.google.com");
browser.navigation().loadUrl("https://www.google.com")
Loading HTML
6.x
browser.loadHTML("<html><body></body></html>");
browser.loadHTML("<html><body></body></html>")
7.0
browser.mainFrame().ifPresent(frame ->
frame.loadHtml("<html><body></body></html>"));
browser.mainFrame().ifPresent { frame ->
frame.loadHtml("<html><body></body></html>") }
Filtering URLs
6.x
browser.setLoadHandler(new DefaultLoadHandler() {
@Override
public boolean onLoad(LoadParams params) {
if (params.getURL().startsWith("mailto:")) {
return true; // Cancel loading
}
return false; // Continue loading
}
});
browser.setLoadHandler(object: DefaultLoadHandler {
override fun onLoad(params: LoadParams): Boolean {
return if (params.getURL().startsWith("mailto:")) {
true // Cancel loading
} else false // Continue loading
}
})
7.0
navigation.set(StartNavigationCallback.class, params -> {
if (params.url().startsWith("mailto:")) {
return Response.ignore();
}
return Response.start();
});
navigation.set(StartNavigationCallback::class.java,
StartNavigationCallback { params ->
if (params.url().startsWith("mailto:")) Response.ignore() else Response.start()
}
)
Navigation Events
Start Loading
6.x
browser.addLoadListener(new LoadAdapter() {
@Override
public void onStartLoadingFrame(StartLoadingEvent event) {
String url = event.getValidatedURL();
}
});
browser.addLoadListener(object: LoadAdapter {
override fun onStartLoadingFrame(event: StartLoadingEvent) {
val url = event.validatedURL
}
})
7.0
browser.navigation().on(NavigationStarted.class, event -> {
String url = event.url();
});
browser.navigation().on(NavigationStarted::class.java) { event ->
val url = event.url()
}
Finish Loading
6.x
browser.addLoadListener(new LoadAdapter() {
@Override
public void onFinishLoadingFrame(FinishLoadingEvent event) {
String html = browser.getHTML(event.getFrameId());
}
});
browser.addLoadListener(object: LoadAdapter {
override fun onFinishLoadingFrame(event: FinishLoadingEvent) {
val html = browser.getHTML(event.frameId)
}
})
7.0
browser.navigation().on(FrameLoadFinished.class, event -> {
String html = event.frame().html();
});
browser.navigation().on(FrameLoadFinished::class.java) { event ->
val html = event.frame().html()
}
Fail Loading
6.x
browser.addLoadListener(new LoadAdapter() {
@Override
public void onFailLoadingFrame(FailLoadingEvent event) {
NetError errorCode = event.getErrorCode();
}
});
browser.addLoadListener(object: LoadAdapter {
override fun onFailLoadingFrame(event: FailLoadingEvent) {
val errorCode = event.errorCode
}
})
7.0
browser.navigation().on(FrameLoadFailed.class, event -> {
NetError error = event.error();
});
browser.navigation().on(FrameLoadFailed::class.java) { event ->
val error = event.error()
}
or
browser.navigation().on(NavigationFinished.class, event -> {
NetError errorCode = event.error();
});
browser.navigation().on(NavigationFinished::class.java) { event ->
val errorCode = event.error()
}
Network
Configuring User-Agent
6.x
BrowserPreferences.setUserAgent("My User-Agent");
BrowserPreferences.setUserAgent("My User-Agent")
7.0
Engine engine = Engine.newInstance(EngineOptions.newBuilder(...)
.userAgent("My User-Agent")
.build());
val engine = Engine.newInstance(EngineOptions.newBuilder(...)
.userAgent("My User-Agent")
.build())
Configuring Accept-Language
6.x
browserContext.setAcceptLanguage("fr, en-gb;q=0.8, en;q=0.7");
browserContext.setAcceptLanguage("fr, en-gb;q=0.8, en;q=0.7")
7.0
engine.network().acceptLanguage("fr, en-gb;q=0.8, en;q=0.7");
engine.network().acceptLanguage("fr, en-gb;q=0.8, en;q=0.7")
Configuring Proxy
6.x
ProxyService proxyService = browserContext.getProxyService();
proxyService.setProxyConfig(new CustomProxyConfig("http-proxy-server:80"));
val proxyService = browserContext.proxyService
proxyService.setProxyConfig(CustomProxyConfig("http-proxy-server:80"))
7.0
engine.proxy().config(CustomProxyConfig.newInstance("http-proxy-server:80"));
engine.proxy().config(CustomProxyConfig.newInstance("http-proxy-server:80"))
Redirecting URL Request
6.x
browserContext.getNetworkService().setNetworkDelegate(new NetworkDelegate() {
@Override
public void onBeforeURLRequest(BeforeURLRequestParams params) {
params.setURL("https://www.google.com");
}
});
browserContext.networkService.setNetworkDelegate(object: NetworkDelegate {
override fun onBeforeURLRequest(params: BeforeURLRequestParams) {
params.setURL("https://www.google.com")
}
})
7.0
engine.network().set(BeforeUrlRequestCallback.class, (params) ->
Response.redirect("https://www.google.com"));
engine.network().set(BeforeUrlRequestCallback::class.java,
BeforeUrlRequestCallback { params ->
Response.redirect("https://www.google.com")
}
)
Overriding HTTP Headers
6.x
browserContext.getNetworkService().setNetworkDelegate(new NetworkDelegate() {
...
@Override
public void onBeforeSendHeaders(BeforeSendHeadersParams params) {
HttpHeadersEx headers = params.getHeadersEx();
headers.setHeader("User-Agent", "MyUserAgent");
headers.setHeader("Content-Type", "text/html");
}
});
browserContext.networkService.setNetworkDelegate(object: NetworkDelegate {
override fun onBeforeSendHeaders(params: BeforeSendHeadersParams) {
val headers = params.headersEx
headers.setHeader("User-Agent", "MyUserAgent")
headers.setHeader("Content-Type", "text/html")
}
})
7.0
engine.network().set(BeforeSendHeadersCallback.class, (params) ->
Response.override(Arrays.asList(
HttpHeader.of("User-Agent", "MyUserAgent"),
HttpHeader.of("Content-Type", "text/html"))));
engine.network().set(BeforeSendHeadersCallback::class.java,
BeforeSendHeadersCallback { params ->
Response.override(listOf(
HttpHeader.of("User-Agent", "MyUserAgent"),
HttpHeader.of("Content-Type", "text/html")))
}
)
Intercepting URL Requests
6.x
BrowserContext browserContext = browser.getContext();
ProtocolService protocolService = browserContext.getProtocolService();
protocolService.setProtocolHandler("https", new ProtocolHandler() {
@Override
public URLResponse onRequest(URLRequest request) {
URLResponse response = new URLResponse();
String html = "<html><body><p>Hello there!</p></body></html>";
response.setData(html.getBytes());
response.getHeaders().setHeader("Content-Type", "text/html");
return response;
}
});
val browserContext = browser.context
val protocolService = browserContext.protocolService
protocolService.setProtocolHandler("https", object: ProtocolHandler {
override fun onRequest(request: URLRequest): URLResponse {
val response = URLResponse()
val html = "<html><body><p>Hello there!</p></body></html>"
response.setData(html.toByteArray())
response.headers.setHeader("Content-Type", "text/html")
return response
}
});
7.0
Network network = engine.network();
network.set(InterceptRequestCallback.class, params -> {
UrlRequest urlRequest = params.urlRequest();
if (urlRequest.url().startsWith("https")) {
Options options = UrlRequestJob.Options
.newBuilder(urlRequest.id(), HttpStatus.OK)
.addHttpHeader(HttpHeader.of("Content-Type", "text/html"))
.build();
UrlRequestJob urlRequestJob = network.newUrlRequestJob(options);
String html = "<html><body><p>Hello there!</p></body></html>";
urlRequestJob.write(html.getBytes(UTF_8));
urlRequestJob.complete();
return Response.intercept(urlRequestJob);
}
return Response.proceed();
});
val network = engine.network()
network.set(InterceptRequestCallback::class.java, InterceptRequestCallback { params ->
val urlRequest = params.urlRequest()
if (urlRequest.url().startsWith("https")) {
val options = UrlRequestJob.Options
.newBuilder(urlRequest.id(), HttpStatus.OK)
.addHttpHeader(HttpHeader.of("Content-Type", "text/html"))
.build()
val urlRequestJob = network.newUrlRequestJob(options)
val html = "<html><body><p>Hello there!</p></body></html>"
urlRequestJob.write(html.toByteArray(UTF_8))
urlRequestJob.complete()
Response.intercept(urlRequestJob)
} else {
Response.proceed()
}
})
Authentication
Proxy, Basic, Digest, NTLM
6.x
NetworkService networkService = browserContext.getNetworkService();
networkService.setNetworkDelegate(new NetworkDelegate() {
...
@Override
public boolean onAuthRequired(AuthRequiredParams params) {
if (params.isProxy()) {
params.setUsername("user");
params.setPassword("password");
return false;
}
return true; // Cancel authentication request
}
});
val networkService = browser.networkService
networkService.setNetworkDelegate(object: NetworkDelegate {
...
override fun onAuthRequired(params: AuthRequiredParams): Boolean {
return if (params.isProxy()) {
params.setUsername("user")
params.setPassword("password")
false
} else true // Cancel authentication request
}
});
7.0
engine.network().set(AuthenticateCallback.class, (params, tell) -> {
if (params.isProxy()) {
tell.authenticate("user", "password");
} else {
tell.cancel();
}
});
engine.network().set(AuthenticateCallback::class.java,
AuthenticateCallback { params, tell ->
if (params.isProxy) {
tell.authenticate("user", "password")
} else {
tell.cancel()
}
}
)
HTTPS Client Certificate
6.x
browser.setDialogHandler(new DialogHandler() {
...
@Override
public CloseStatus onSelectCertificate(CertificatesDialogParams params) {
List<Certificate> certificates = params.getCertificates();
if (certificates.isEmpty()) {
return CloseStatus.CANCEL;
} else {
params.setSelectedCertificate(certificates.get(certificates.size() - 1));
return CloseStatus.OK;
}
}
});
browser.setDialogHandler(object: DialogHandler {
...
override fun onSelectCertificate(params: CertificatesDialogParams): CloseStatus {
val certificates = params.certificates
return if (certificates.isEmpty()) {
CloseStatus.CANCEL
} else {
params.setSelectedCertificate(certificates[certificates.size - 1])
CloseStatus.OK
}
}
});
7.0
browser.set(SelectClientCertificateCallback.class, (params, tell) -> {
List<Certificate> certificates = params.certificates();
if (certificates.isEmpty()) {
tell.cancel();
} else {
tell.select(certificates.size() - 1);
}
});
browser.set(SelectClientCertificateCallback::class.java,
SelectClientCertificateCallback { params, tell ->
val certificates = params.certificates()
if (certificates.isEmpty()) {
tell.cancel()
} else {
tell.select(certificates.size - 1)
}
}
)
Plugins
Filtering Plugins
6.x
browser.getPluginManager().setPluginFilter(new PluginFilter() {
@Override
public boolean isPluginAllowed(PluginInfo pluginInfo) {
return true;
}
});
browser.pluginManager.setPluginFilter(object: PluginFilter {
override fun isPluginAllowed(pluginInfo: PluginInfo): Boolean {
return true
}
})
7.0
engine.plugins().set(AllowPluginCallback.class, params -> Response.allow());
engine.plugins().set(AllowPluginCallback::class.java,
AllowPluginCallback { Response.allow() })
DOM
Accessing Document
6.x
DOMDocument document = browser.getDocument();
if (document != null) {
String baseURI = document.getBaseURI();
}
val document = browser.document
val baseURI = document?.baseURI
7.0
browser.mainFrame().ifPresent(frame ->
frame.document().ifPresent(document -> {
String baseUri = document.baseUri();
}));
browser.mainFrame().ifPresent { frame ->
frame.document().ifPresent { document ->
val baseUri = document.baseUri()
}
}
DOM Events
Working with Events
6.x
element.addEventListener(DOMEventType.OnClick, new DOMEventListener() {
@Override
public void handleEvent(DOMEvent event) {
DOMEventTarget eventTarget = event.getTarget();
if (eventTarget != null) {
...
}
}
}, false);
element.addEventListener(DOMEventType.OnClick, object: DOMEventListener {
override fun handleEvent(event: DOMEvent) {
val eventTarget = event.target
if (eventTarget != null) {
...
}
}
})
7.0
element.addEventListener(EventType.CLICK, event ->
event.target().ifPresent(eventTarget -> {
...
}), false);
element.addEventListener(EventType.CLICK, { event ->
event.target().ifPresent { eventTarget ->
...
}
}, false)
CSS
Injecting CSS
6.x
browser.setCustomStyleSheet("body { background-color: orange; }");
browser.setCustomStyleSheet("body { background-color: orange; }")
7.0
browser.set(InjectCssCallback.class, params ->
Response.inject("body { background-color: orange; }"));
browser.set(InjectCssCallback::class.java,
InjectCssCallback { Response.inject("body { background-color: orange; }") })
JavaScript
Calling JavaScript from Java
6.x
String string = browser.executeJavaScriptAndReturnValue("'Hello'")
.asString().getValue();
double number = browser.executeJavaScriptAndReturnValue("123")
.asNumber().getValue();
boolean bool = browser.executeJavaScriptAndReturnValue("true")
.asBoolean().getValue();
JSObject window = browser.executeJavaScriptAndReturnValue("window")
.asObject();
val string = browser.executeJavaScriptAndReturnValue("'Hello'")
.asString().value
val number = browser.executeJavaScriptAndReturnValue("123")
.asNumber().value
val bool = browser.executeJavaScriptAndReturnValue("true")
.asBoolean().value
val window = browser.executeJavaScriptAndReturnValue("window")
.asObject()
7.0
The JSValue
class has been removed. The type conversion is done automatically now. You can execute JavaScript both synchronously blocking the current thread execution or asynchronously:
browser.mainFrame().ifPresent(frame -> {
String string = frame.executeJavaScript("'Hello'");
Double number = frame.executeJavaScript("123");
Boolean bool = frame.executeJavaScript("true");
JsObject window = frame.executeJavaScript("window");
frame.executeJavaScript("document", (Consumer<Document>) document -> {
String baseUri = document.baseUri();
});
});
browser.mainFrame().ifPresent { frame: Frame ->
val string = frame.executeJavaScript<String>("'Hello'")
val number = frame.executeJavaScript<Double>("123")
val bool = frame.executeJavaScript<Boolean>("true")
val window = frame.executeJavaScript<JsObject>("window")
frame.executeJavaScript("document", Consumer<Document> { document ->
val baseUri = document.baseUri()
})
}
Calling Java from JavaScript
6.x
In Java code:
public class JavaObject {
public void foo(String text) {}
}
…
JSValue window = browser.executeJavaScriptAndReturnValue("window");
if (window.isObject()) {
window.asObject().setProperty("java", new JavaObject());
}
class JavaObject {
fun foo(text String) {}
}
…
val window = browser.executeJavaScriptAndReturnValue("window")
if (window.isObject()) {
window.asObject().setProperty("java", JavaObject())
}
In JavaScript code:
window.java.foo("Hello");
7.0
For security reasons only public methods annotated with @JsAccessible
can be accessed from JavaScript.
In Java code:
public class JavaObject {
@JsAccessible
public void foo(String text) {}
}
…
JsObject window = frame.executeJavaScript("window");
window.putProperty("java", new JavaObject());
class JavaObject {
@JsAccessible
fun foo(text: String) {}
}
…
val window = frame.executeJavaScript<JsObject>("window")
window?.putProperty("java", JavaObject())
In JavaScript code:
window.java.foo("Hello");
Injecting JavaScript
6.x
browser.addScriptContextListener(new ScriptContextAdapter() {
@Override
public void onScriptContextCreated(ScriptContextEvent event) {
JSValue window = browser.executeJavaScriptAndReturnValue(
event.getJSContext().getFrameId(), "window");
}
});
browser.addScriptContextListener(object: ScriptContextAdapter {
override fun onScriptContextCreated(event: ScriptContextEvent) {
val window = browser.executeJavaScriptAndReturnValue(
event.jsContext.frameId, "window")
}
})
7.0
browser.set(InjectJsCallback.class, params -> {
JsObject window = params.frame().executeJavaScript("window");
return Response.proceed();
});
browser.set(InjectJsCallback::class.java, InjectJsCallback { params ->
val window = params.frame().executeJavaScript<JsObject>("window")
Response.proceed()
})
Console Events
6.x
browser.addConsoleListener(new ConsoleListener() {
@Override
public void onMessage(ConsoleEvent event) {
String message = event.getMessage();
}
});
browser.addConsoleListener(object: ConsoleListener {
override fun onMessage(event: ConsoleEvent) {
val message = event.message
}
})
7.0
browser.on(ConsoleMessageReceived.class, event -> {
String message = event.consoleMessage().message();
});
browser.on(ConsoleMessageReceived::class.java) { event ->
val message = event.consoleMessage().message()
}
Pop-ups
Suppressing Pop-ups
6.x
browser.setPopupHandler(new PopupHandler() {
@Override
public PopupContainer handlePopup(PopupParams params) {
return null;
}
});
browser.setPopupHandler(object: PopupHandler {
override fun handlePopup(params: PopupParams): PopupContainer? {
return null
}
})
7.0
browser.set(CreatePopupCallback.class, (params) -> Response.suppress());
browser.set(CreatePopupCallback::class.java, CreatePopupCallback { Response.suppress() })
Opening Pop-ups
6.x
browser.setPopupHandler(new PopupHandler() {
@Override
public PopupContainer handlePopup(PopupParams params) {
return new PopupContainer() {
@Override
public void insertBrowser(Browser popupBrowser, Rectangle initialBounds) {}
};
}
});
browser.setPopupHandler(object: PopupHandler {
override fun handlePopup(params: PopupParams): PopupContainer {
return object: PopupContainer {
override fun insertBrowser(popupBrowser: Browser, initialBounds: Rectangle) {}
}
}
})
7.0
browser.set(CreatePopupCallback.class, (params) -> Response.create());
browser.set(OpenPopupCallback.class, (params) -> {
Browser popup = params.popupBrowser();
return OpenPopupCallback.Response.proceed();
});
browser.set(CreatePopupCallback::class.java, CreatePopupCallback { Response.create() })
browser.set(OpenPopupCallback::class.java, OpenPopupCallback { params ->
val popup = params.popupBrowser()
OpenPopupCallback.Response.proceed()
})
Dialogs
JavaScript Dialogs
6.x
browser.setDialogHandler(new DialogHandler() {
@Override
public void onAlert(DialogParams params) {
}
@Override
public CloseStatus onConfirmation(DialogParams params) {
return CloseStatus.CANCEL;
}
@Override
public CloseStatus onPrompt(PromptDialogParams params) {
params.setPromptText("Text");
return CloseStatus.OK;
}
...
});
browser.setDialogHandler(object: DialogHandler {
override fun onAlert(params: DialogParams) {}
override fun onConfirmation(params: DialogParams): CloseStatus =
CloseStatus.CANCEL
override fun onPrompt(params: PromptDialogParams): CloseStatus {
params.setPromptText("Text")
return CloseStatus.OK
}
})
7.0
browser.set(AlertCallback.class, (params, tell) -> tell.ok());
browser.set(ConfirmCallback.class, (params, tell) -> tell.cancel());
browser.set(PromptCallback.class, (params, tell) -> tell.ok("Text"));
browser.set(AlertCallback::class.java, AlertCallback { params, tell -> tell.ok() })
browser.set(ConfirmCallback::class.java, ConfirmCallback { params, tell -> tell.cancel() })
browser.set(PromptCallback::class.java, PromptCallback { params, tell -> tell.ok("Text") })
File Dialogs
6.x
browser.setDialogHandler(new DialogHandler() {
@Override
public CloseStatus onFileChooser(FileChooserParams params) {
FileChooserMode mode = params.getMode();
if (mode == FileChooserMode.Open) {
params.setSelectedFiles(new File(params.getDefaultFileName()));
}
if (mode == FileChooserMode.OpenMultiple) {
params.setSelectedFiles(new File("file1.txt"), new File("file2.txt"));
}
return CloseStatus.OK;
}
...
});
browser.setDialogHandler(object: DialogHandler {
override fun onFileChooser(params: FileChooserParams): CloseStatus {
val mode = params.mode
if (mode == FileChooserMode.Open) {
params.setSelectedFiles(File(params.defaultFileName))
}
if (mode == FileChooserMode.OpenMultiple) {
params.setSelectedFiles(File("file1.txt"), File("file2.txt"))
}
return CloseStatus.OK
}
})
7.0
browser.set(OpenFileCallback.class, (params, tell) ->
tell.open(Paths.get(params.defaultFileName())));
browser.set(OpenFilesCallback.class, (params, callback) ->
callback.open(Paths.get("file1.txt"), Paths.get("file2.txt")));
browser.set(OpenFileCallback::class.java,
OpenFileCallback { params, tell ->
tell.open(Path(params.defaultFileName()))
}
)
browser.set(OpenFilesCallback::class.java,
OpenFilesCallback { _, callback ->
callback.open(Path("file1.txt"), Path("file2.txt"))
}
)
Color Dialogs
6.x
browser.setDialogHandler(new DialogHandler() {
@Override
public CloseStatus onColorChooser(ColorChooserParams params) {
params.setColor(params.getColor());
return CloseStatus.OK;
}
...
});
browser.setDialogHandler(object: DialogHandler {
override fun onColorChooser(params: ColorChooserParams): CloseStatus {
params.setColor(params.сolor)
return CloseStatus.OK
}
})
7.0
browser.set(SelectColorCallback.class, (params, tell) ->
tell.select(params.defaultColor()));
browser.set(SelectColorCallback::class.java,
SelectColorCallback { params, tell ->
tell.select(params.defaultColor())
}
)
SSL Certificate Dialogs
6.x
browser.setDialogHandler(new DialogHandler() {
@Override
public CloseStatus onSelectCertificate(CertificatesDialogParams params) {
X509Certificate x509Certificate = ...;
PrivateKey privateKey = ...;
params.setSelectedCertificate(new Certificate(x509Certificate, privateKey));
return CloseStatus.OK;
}
...
});
browser.setDialogHandler(object: DialogHandler {
override fun onSelectCertificate(params: CertificatesDialogParams): CloseStatus {
val x509Certificate: X509Certificate = ...
val privateKey: PrivateKey = ...
params.setSelectedCertificate(Certificate(x509Certificate, privateKey))
return CloseStatus.OK
}
...
})
7.0
private static final Path CLIENT_CERT_FILE = Paths.get("<cert-file>.p12");
private static final String CLIENT_CERT_PASSWORD = "<cert-password>";
...
browser.set(SelectClientCertificateCallback.class, (params, tell) ->
tell.select(ClientCertificate.of(CLIENT_CERT_FILE,
CLIENT_CERT_PASSWORD, KeyStoreType.PKCS12)));
private val certFile = Path("<cert-file>.p12")
private val certPassword = "<cert-password>"
...
browser.set(SelectClientCertificateCallback::class.java,
SelectClientCertificateCallback { params, tell ->
tell.select(ClientCertificate.of(certFile,
certPassword, KeyStoreType.PKCS12))
}
)
Context Menu
Handling Context Menu
6.x
browser.setContextMenuHandler(new ContextMenuHandler() {
@Override
public void showContextMenu(ContextMenuParams params) {
}
});
browser.setContextMenuHandler(object: ContextMenuHandler {
override fun showContextMenu(params: ContextMenuParams) {
}
})
7.0
browser.set(ShowContextMenuCallback.class, (params, tell) -> {
tell.close();
});
browser.set(ShowContextMenuCallback::class.java,
ShowContextMenuCallback { params, tell -> tell.close() }
)
Read more about how to handle context menu.
Printing
Configuring Printing
6.x
browser.setPrintHandler(new PrintHandler() {
@Override
public PrintStatus onPrint(PrintJob printJob) {
PrintSettings printSettings = printJob.getPrintSettings();
printSettings.setPrinterName("Microsoft XPS Document Writer");
printSettings.setLandscape(true);
printSettings.setPrintBackgrounds(true);
...
return PrintStatus.CONTINUE;
}
});
browser.setPrintHandler(object: PrintHandler {
override fun onPrint(printJob: PrintJob): PrintStatus {
val printSettings = printJob.printSettings
printSettings.setPrinterName("Microsoft XPS Document Writer")
printSettings.setLandscape(true)
printSettings.setPrintBackgrounds(true)
...
return PrintStatus.CONTINUE
}
})
7.0
Functionality that allows configuring printing has been removed. Instead it got possible to display a standard Print Preview dialog where you can provide the required settings:
browser.set(PrintCallback.class, (params, tell) -> tell.showPrintPreview());
browser.set(PrintCallback::class.java,
PrintCallback { params, tell -> tell.showPrintPreview() }
)
Suppressing Printing
6.x
browser.setPrintHandler(new PrintHandler() {
@Override
public PrintStatus onPrint(PrintJob printJob) {
return PrintStatus.CANCEL;
}
});
browser.setPrintHandler(object: PrintHandler {
override fun onPrint(printJob: PrintJob): PrintStatus =
PrintStatus.CANCEL
})
7.0
browser.set(PrintCallback.class, (params, tell) -> tell.cancel());
browser.set(PrintCallback::class.java,
PrintCallback { params, tell -> tell.cancel() }
)
Cache
Clearing HTTP Cache
6.x
browser.getCacheStorage().clearCache(new Callback() {
@Override
public void invoke() {
// HTTP Disk Cache has been cleared.
}
});
browser.cacheStorage.clearCache(object: Callback {
override fun invoke() {
// HTTP Disk Cache has been cleared.
}
})
7.0
engine.httpCache().clearDiskCache(() -> {
// HTTP Disk Cache has been cleared.
});
engine.httpCache().clearDiskCache {
// HTTP Disk Cache has been cleared.
}
Cookies
Accessing Cookies
6.x
List<Cookie> cookies = browser.getCookieStorage().getAllCookies();
val cookies = browser.cookieStorage.allCookies
7.0
List<Cookie> cookies = engine.cookieStore().cookies();
val cookies = engine.cookieStore().cookies()
Render Process
Started/Terminated
6.x
browser.addRenderListener(new RenderAdapter() {
@Override
public void onRenderCreated(RenderEvent event) {}
@Override
public void onRenderGone(RenderEvent event) {
TerminationStatus status = event.getTerminationStatus();
}
});
browser.addRenderListener(object: RenderAdapter {
override fun onRenderCreated(event: RenderEvent) {}
override fun onRenderGone(event: RenderEvent) {
val status: TerminationStatus = event.terminationStatus
}
})
7.0
browser.on(RenderProcessStarted.class, event -> {});
browser.on(RenderProcessTerminated.class, event -> {
TerminationStatus status = event.status();
});
browser.on(RenderProcessStarted::class.java) { event -> }
browser.on(RenderProcessTerminated::class.java) { event ->
val status = event.status()
}
Chromium
Switches
The library does not support all the possible Chromium switches. It allows configuring Chromium with the switches, but we do not guarantee that the passed switches will work correctly or work at all. We recommend to check this functionality before using.
6.x
BrowserPreferences.setChromiumSwitches(
"--<switch_name>",
"--<switch_name>=<switch_value>"
);
BrowserPreferences.setChromiumSwitches(
"--<switch_name>",
"--<switch_name>=<switch_value>"
)
7.0
Engine engine = Engine.newInstance(EngineOptions.newBuilder(...)
.addSwitch("--<switch_name>")
.addSwitch("--<switch_name>=<switch_value>")
.build());
val engine = Engine.newInstance(EngineOptions.newBuilder(...)
.addSwitch("--<switch_name>")
.addSwitch("--<switch_name>=<switch_value>")
.build())
API Keys
6.x
BrowserPreferences.setChromiumVariable(
"GOOGLE_API_KEY", "My API Key");
BrowserPreferences.setChromiumVariable(
"GOOGLE_DEFAULT_CLIENT_ID", "My Client ID");
BrowserPreferences.setChromiumVariable(
"GOOGLE_DEFAULT_CLIENT_SECRET", "My Client Secret");
BrowserPreferences.setChromiumVariable(
"GOOGLE_API_KEY", "My API Key")
BrowserPreferences.setChromiumVariable(
"GOOGLE_DEFAULT_CLIENT_ID", "My Client ID")
BrowserPreferences.setChromiumVariable(
"GOOGLE_DEFAULT_CLIENT_SECRET", "My Client Secret")
7.0
Engine engine = Engine.newInstance(EngineOptions.newBuilder(...)
.googleApiKey("My API Key")
.googleDefaultClientId("My Client ID")
.googleDefaultClientSecret("My Client Secret")
.build());
val engine = Engine.newInstance(EngineOptions.newBuilder(...)
.googleApiKey("My API Key")
.googleDefaultClientId("My Client ID")
.googleDefaultClientSecret("My Client Secret")
.build())
Logging
In the new version the logging API has been simplified. Please read more about how to configure logging in the Troubleshooting guide.
FAQ
How long will JxBrowser 6 be supported?
JxBrowser 6 will be supported until the end of 2019.
Can I upgrade to JxBrowser 7 for free?
If you already own a commercial license for JxBrowser 6 with an active Subscription, then you can receive a commercial license key for JxBrowser 7 for free. Please feel free to contact our Sales Team if you have any questions regarding this.
I have a case not covered by this guide. What should I do?
We recommend that you check out our Guides. JxBrowser 6 and 7 are almost identical by functionality. So, if this migration guide does not describe an alternative to the JxBrowser 6 functionality you use, then you can find description of the similar functionality in our guides which documents are grouped by feature areas.
If you do not see description of the required functionality in the guides, then please let us know.