This guide describes how to create, use, and dispose Browser
.
Creating Browser
Each Browser
instance must be initialized with BrowserContext
. The BrowserContext
instance holds the context needed for a browsing session and provides path to the directory where Chromium stores cookies, cache data files, etc.
The following code creates a new Browser
instance initialized with default context:
Browser browser = new Browser();
The code above equals to:
Browser browser = new Browser(BrowserContext.defaultContext());
The BrowserContext.defaultContext()
method returns the default BrowserContext
that is configured to store Chromium data files such as cookies, cache, etc. in user’s temp directory on macOS and Linux and AppData\Local\JxBrowser
on Windows. You can get path to the directory where data files are stored using the BrowserPreferences.getDefaultDataDir()
method.
Two Browser instances with the same BrowserContext
instances will use the same user data directory. As result they will share cookies and cache files. For example:
BrowserContext context = new BrowserContext(
new BrowserContextParams("C:\\my-data1"));
Browser browser1 = new Browser(context);
Browser browser2 = new Browser(context);
To create the independent Browser
instances that don’t share cookies and cache data, you must initialize each Browser
instance with a different BrowserContext
instance configured to use a different data directory. For example:
BrowserContext context1 = new BrowserContext(
new BrowserContextParams("C:\\my-data1"));
Browser browser1 = new Browser(context1);
BrowserContext context2 = new BrowserContext(
new BrowserContextParams("C:\\my-data2"));
Browser browser2 = new Browser(context2);
To get BrowserContext
of the Browser instance you can use the browser.getContext()
method.
User Data
By default, JxBrowser stores user data in a folder with the path that usually looks like %LocalAppData%\JxBrowser\browsercore-<version>\data
on Windows. On Linux and macOS user’s temp directory is used.
To change the default behavior and customize the path to the user data directory use the following approach:
BrowserContext context = new BrowserContext(
new BrowserContextParams("Users/Me/JxBrowser/Data"));
Browser browser = new Browser(context);
In case of using a custom user data directory, it is completely possible to upgrade JxBrowser from an older version to a newer one, however, in case of a downgrade, the user data folder may appear incompatible. Such functionality is not supported, so you should avoid such situations when you downgrade JxBrowser and tell it to use the user data directory created by a newer version.
Important to Know
Using several BrowserContext
instances configured to use same data directory in a single or multiple Java application instances is forbidden. In this case Browser constructor will throw the BrowserException exception to prevent unexpected behavior or errors such as native crash in the Chromium engine.
If it’s possible to launch more than one instance of your Java application at the same time on the same machine, then please don’t create Browser
instance in your application using default constructor. In this case both Browser
instances running in different Java applications at the same time will be configured to use the same Chromium data directory which is forbidden. The BrowserException
exception will be thrown when the second Java application instance will try to create a new Browser
instance.
To solve this issue please make sure that only one instance of your Java application can be used at the same time. If you would like to let end users to run multiple instances of your Java application at the same time, then please make sure that each instance of your Java application configures JxBrowser library to use unique Chromium data directory.
Multiple instances of Java application
// App instance #1
Browser browser = new Browser(); // OK
// App instance #2
Browser browser = new Browser(); // <= BrowserException
// App instance #1
BrowserContext context = new BrowserContext(
new BrowserContextParams("C:\\data"));
Browser browser = new Browser(context); // OK
// App instance #2
BrowserContext context = new BrowserContext(
new BrowserContextParams("C:\\data"));
Browser browser = new Browser(context); // <= BrowserException
// App instance #1
BrowserContext context = new BrowserContext(
new BrowserContextParams("C:\\data1"));
Browser browser = new Browser(context); // OK
// App instance #2
BrowserContext context = new BrowserContext(
new BrowserContextParams("C:\\data2"));
Browser browser = new Browser(context); // OK
A single Java application instance
Browser browserOne = new Browser(); // OK
String dataDir = BrowserContext.defaultContext().getDataDir();
BrowserContext context = new BrowserContext(
new BrowserContextParams(dataDir));
Browser browserTwo = new Browser(context); // <= BrowserException
BrowserContext context1 = new BrowserContext(
new BrowserContextParams("C:\\shared-data"));
Browser browser1 = new Browser(context1); // OK
BrowserContext context2 = new BrowserContext(
new BrowserContextParams("C:\\shared-data"));
Browser browser2 = new Browser(context2); // <= BrowserException
BrowserContext context1 = new BrowserContext(
new BrowserContextParams("C:\\my-data1"));
Browser browser1 = new Browser(context1); // OK
BrowserContext context2 = new BrowserContext(
new BrowserContextParams("C:\\my-data2"));
Browser browser2 = new Browser(context2); // OK
Browser browser1 = new Browser(); // OK
Browser browser2 = new Browser(); // OK
Browser browser3 = new Browser(BrowserContext.defaultContext()); // OK
Limitations
At the moment there is a limit on how many BrowserContext
instances can be held by one Chromium process. Holding more than that limit can lead to unexpected crashes in Chromium process. The limit is around 50 instances of BrowserContext per process and varies depending on the operating system.
On Linux and MacOS Chromium does not release its file descriptors. That behavior leads to the file descriptors leak and after some point, it becomes impossible to create new BrowserContext instances because of hitting the hard limit of the file descriptors.
On Windows, new BrowserContext
instances are acquiring thread-local storages from Chromium pool of thread-local storages and never releases them, which may lead to Chromium process crashes when trying to create new BrowserContext
.
To avoid issues with multiple BrowserContext
instances, the following approaches can be used:
- Multiple
Browser
instances can use the sameBrowserContext
. If you do not need to create theBrowser
instances that don’t share cookies, caches and other user data, you can use a singleBrowserContext
instance. For example:
BrowserContext browserContext = new BrowserContext(new BrowserContextParams(
new File("user_data_dir").getAbsolutePath()));
Browser browserOne = new Browser(browserContext);
Browser browserTwo = new Browser(browserContext);
- In case you need to use multiple
Browser
instances that don’t share cookies and other user data and you have to create multipleBrowserContext
instances, we recommend that you dispose allBrowser
instances periodically to destroy all createdBrowserContext
instances, and terminate Chromium native process to release file descriptors and other resources. After that, you can continue creating the newBrowserContext
andBrowser
instances.
Creating Incognito Browser
By default, each Browser
instance stores all user data such as history, cookies, cache on disk. Since 6.8 you can configure Browser
instance to store all user data in memory (Chromium’s “Incognito” mode), so that all user data will be cleared once your Java application is terminated.
The following example demonstrates how to configure Browser
instance to work in “Incognito” mode and store all user data in memory:
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.BrowserContext;
import com.teamdev.jxbrowser.chromium.BrowserContextParams;
import com.teamdev.jxbrowser.chromium.StorageType;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import javax.swing.*;
import java.awt.*;
/**
* This sample demonstrates how to configure Browser instance
* to use in-memory data storage.
*/
public class IncognitoModeSample {
public static void main(String[] args) {
// No user data will be stored to the "user-data-dir" folder.
// This directory will be used for internal purposes
// on macOS and Linux platforms.
BrowserContextParams params = new BrowserContextParams("user-data-dir");
params.setStorageType(StorageType.MEMORY);
BrowserContext browserContext = new BrowserContext(params);
Browser browser = new Browser(browserContext);
BrowserView view = new BrowserView(browser);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(view, BorderLayout.CENTER);
frame.setSize(700, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
browser.loadURL("http://google.com");
}
}
Disposing Browser
When you don’t need to use a Browser
instance you must dispose it using the Browser.dispose()
method.
For example:
browser.dispose();
Accessing disposed instance
Once you dispose a Browser
instance, you cannot use it anymore. If you try to access already disposed Browser
instance the IllegalStateException
exception will be thrown. For example:
browser.dispose();
browser.getDocument(); // IllegalStateException will be thrown
To check if the Browser
instance is disposed or not, you can use the Browser.isDisposed()
method.
Dispose Events
Each Browser
instance can be also disposed from JavaScript via the window.close()
function. In this case you might be interested in receiving notification when a Browser
instance is disposed. To get such notifications, you can use DisposeListener
. For example:
browser.addDisposeListener(new DisposeListener<Browser>() {
@Override
public void onDisposed(DisposeEvent<Browser> event) {
// B<span class="fr-marker" data-id="0" data-type="false" style="display: none; line-height: 0;"></span><span class="fr-marker" data-id="0" data-type="true" style="display: none; line-height: 0;"></span>rowser is disposed
}
});
When you dispose a Browser
instance manually via the Browser.dispose()
method, the Dispose
event will also be fired.
Restoring Browser
You can restore a Browser
instance after an unexpected crash in Chromium render process using the following approach:
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.events.RenderAdapter;
import com.teamdev.jxbrowser.chromium.events.RenderEvent;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import javax.swing.*;
import java.awt.*;
/**
* This sample demonstrates how to restore Browser instance after its
* native process unexpectedly terminated. In general to restore a Browse instance you just need to load the same or another URL.
*/
public class RestoreBrowserSample {
public static void main(String[] args) {
Browser browser = new Browser();
BrowserView browserView = new BrowserView(browser);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(browserView, BorderLayout.CENTER);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
browser.addRenderListener(new RenderAdapter() {
@Override
public void onRenderGone(RenderEvent event) {
Browser browser = event.getBrowser();
// Restore Browser instance by loading the same URL
browser.loadURL(browser.getURL());
}
});
browser.loadURL("http://www.google.com");
System.out.println("Run 'Task Manager' app and kill the 'jxbrowser-chromium.exe' " +
"process with the '--type=renderer' command line argument.");
}
}
Preferences
JxBrowser provides functionality that allows you to enable or disable various features, such as images, JavaScript, videos, etc., for each Browser
instance. Use BrowserPreferences
class to work with Browser
features/preferences. To modify some features/preferences you must obtain BrowserPreferences
instance using the Browser.getPreferences()
method, modify preferences, and save them using the Browser.setPreferences()
method.
The following sample demonstrates how to disable loading images and JavaScript execution on www.google.com
web page:
Browser browser = new Browser();
// Gets the current Browser's preferences
BrowserPreferences preferences = browser.getPreferences();
preferences.setImagesEnabled(false);
preferences.setJavaScriptEnabled(false);
// Updates Browser's preferences
browser.setPreferences(preferences);
// Images and JavaScript will be disabled
browser.loadURL("http://www.google.com/");
Forwarding Mouse Events
You can programmatically forward mouse events to the currently loaded web page. The mouse events will be send to the loaded web page as if they were sent due to user actions.
The following example demonstrates how to use this functionality:
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyModifiers;
import com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyModifiersBuilder;
import com.teamdev.jxbrowser.chromium.BrowserMouseEvent.BrowserMouseEventBuilder;
import com.teamdev.jxbrowser.chromium.BrowserMouseEvent.MouseButtonType;
import com.teamdev.jxbrowser.chromium.Callback;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import static com.teamdev.jxbrowser.chromium.BrowserMouseEvent.MouseButtonType.*;
import static com.teamdev.jxbrowser.chromium.BrowserMouseEvent.MouseEventType.*;
import static com.teamdev.jxbrowser.chromium.BrowserMouseEvent.MouseScrollType.WHEEL_BLOCK_SCROLL;
/**
* This sample demonstrates how to create and forward mouse events
* containing scroll parameters, modifiers, and button options to Chromium engine.
*/
public class ForwardMouseEventsSample {
public static void main(String[] args) {
final Browser browser = new Browser();
BrowserView view = new BrowserView(browser);
JButton scrollDown = new JButton("Scroll Down");
scrollDown.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
forwardMouseScrollEvent(browser, -1, 11, 62);
}
});
JButton scrollUp = new JButton("Scroll Up");
scrollUp.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
forwardMouseScrollEvent(browser, 1, 11, 62);
}
});
JButton clickMe = new JButton("Click");
clickMe.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
forwardMouseClickEvent(browser, PRIMARY, 11, 12, 629, 373);
}
});
JPanel actionPane = new JPanel();
actionPane.add(scrollDown);
actionPane.add(scrollUp);
actionPane.add(clickMe);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(actionPane, BorderLayout.SOUTH);
frame.add(view, BorderLayout.CENTER);
frame.setSize(600, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Browser.invokeAndWaitFinishLoadingMainFrame(browser, new Callback<Browser>() {
@Override
public void invoke(Browser value) {
browser.loadHTML("<div>" +
"<button onclick=\"alert('Mouse has been clicked.');\">Click Me</button></div>" +
"<textarea autofocus rows='10' cols='30'>" +
"Line 1 \n Line 2 \n Line 3 \n Line 4 \n Line 5 \n " +
"Line 6 \n Line 7 \n Line 8 \n Line 9 \n Line 10 \n " +
"Line 11 \n Line 11 \n Line 12 \n Line 13 \n Line 14 \n " +
"Line 15 \n Line 16 \n Line 17 \n Line 18 \n </textarea>");
}
});
}
private static void forwardMousePressEvent(Browser browser,
MouseButtonType buttonType,
int x,
int y,
int globalX,
int globalY) {
BrowserMouseEventBuilder builder = new BrowserMouseEventBuilder();
builder.setEventType(MOUSE_PRESSED)
.setButtonType(buttonType)
.setX(x)
.setY(y)
.setGlobalX(globalX)
.setGlobalY(globalY)
.setClickCount(1)
.setModifiers(new KeyModifiersBuilder().mouseButton().build());
browser.forwardMouseEvent(builder.build());
}
private static void forwardMouseReleaseEvent(Browser browser,
MouseButtonType buttonType,
int x,
int y,
int globalX,
int globalY) {
BrowserMouseEventBuilder builder = new BrowserMouseEventBuilder();
builder.setEventType(MOUSE_RELEASED)
.setButtonType(buttonType)
.setX(x)
.setY(y)
.setGlobalX(globalX)
.setGlobalY(globalY)
.setClickCount(1)
.setModifiers(KeyModifiers.NO_MODIFIERS);
browser.forwardMouseEvent(builder.build());
}
private static void forwardMouseClickEvent(Browser browser,
MouseButtonType buttonType,
int x,
int y,
int globalX,
int globalY) {
forwardMousePressEvent(browser, buttonType, x, y, globalX, globalY);
forwardMouseReleaseEvent(browser, buttonType, x, y, globalX, globalY);
}
private static void forwardMouseScrollEvent(Browser browser,
int unitsToScroll,
int x,
int y) {
BrowserMouseEventBuilder builder = new BrowserMouseEventBuilder();
builder.setEventType(MOUSE_WHEEL)
.setX(x)
.setY(y)
.setGlobalX(0)
.setGlobalY(0)
.setScrollBarPixelsPerLine(25)
.setScrollType(WHEEL_BLOCK_SCROLL)
.setUnitsToScroll(unitsToScroll);
browser.forwardMouseEvent(builder.build());
}
}
Forwarding Keyboard Events
JxBrowser API provides functionality that allows forwarding keyboard events to the currently focused element on the currently loaded web page.
This functionality is useful when you need to programmatically send keyboard events to a web page. For example, if you develop a Web-base Kiosk Java application that should run on a terminal/PC with a touch screen monitor and no physical keyboard, you might want to display your own screen keyboard. The end user will use this screen keyboard to type on the loaded web page. In this case the screen keyboard can programmatically forward the appropriate key events to the currently loaded web page using this functionality.
The following example demonstrates how to programmatically send keyboard events to type text and press Enter in the currently focused textarea on the loaded web page:
import com.teamdev.jxbrowser.chromium.*;
import com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyCode;
import com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyModifiers;
import com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyModifiersBuilder;
import com.teamdev.jxbrowser.chromium.events.FinishLoadingEvent;
import com.teamdev.jxbrowser.chromium.events.LoadAdapter;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import javax.swing.*;
import java.awt.*;
import static com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyCode.*;
import static com.teamdev.jxbrowser.chromium.BrowserKeyEvent.KeyEventType.*;
/**
* This sample demonstrates how to create and forward keyboard events
* containing characters, modifiers, and control keys to Chromium engine.
*/
public class ForwardKeyEventsSample {
public static void main(String[] args) {
Browser browser = new Browser();
BrowserView view = new BrowserView(browser);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(view, BorderLayout.CENTER);
frame.setSize(700, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
browser.addLoadListener(new LoadAdapter() {
@Override
public void onFinishLoadingFrame(FinishLoadingEvent event) {
if (event.isMainFrame()) {
Browser browser = event.getBrowser();
// Sending 'Hello' to the currently focused textarea
forwardKeyEvent(browser, VK_H, 'H');
forwardKeyEvent(browser, VK_E, 'e');
forwardKeyEvent(browser, VK_L, 'l');
forwardKeyEvent(browser, VK_L, 'l');
forwardKeyEvent(browser, VK_O, 'o');
// Sending 'Enter' to insert a line break
forwardKeyEvent(browser, VK_RETURN);
// Selecting text in the textarea using Ctrl+A shortcut
forwardKeyEvent(browser, VK_A,
new KeyModifiersBuilder().ctrlDown().build());
}
}
});
browser.loadHTML("<textarea autofocus rows='10' cols='30'></textarea>");
}
private static void forwardKeyEvent(Browser browser, KeyCode code, char character) {
browser.forwardKeyEvent(new BrowserKeyEvent(PRESSED, code, character));
browser.forwardKeyEvent(new BrowserKeyEvent(TYPED, code, character));
browser.forwardKeyEvent(new BrowserKeyEvent(RELEASED, code, character));
}
private static void forwardKeyEvent(Browser browser, KeyCode code) {
browser.forwardKeyEvent(new BrowserKeyEvent(PRESSED, code));
browser.forwardKeyEvent(new BrowserKeyEvent(TYPED, code));
browser.forwardKeyEvent(new BrowserKeyEvent(RELEASED, code));
}
private static void forwardKeyEvent(Browser browser, KeyCode code, KeyModifiers modifiers) {
browser.forwardKeyEvent(new BrowserKeyEvent(PRESSED, code, modifiers));
browser.forwardKeyEvent(new BrowserKeyEvent(TYPED, code, modifiers));
browser.forwardKeyEvent(new BrowserKeyEvent(RELEASED, code, modifiers));
}
}
Editor Commands
JxBrowser provides functionality that allows you to execute commands such as “Cut”, “Copy”, “Paste”, “Undo”, “Redo”, “Insert Text”, etc. on the loaded web page. JxBrowser supports two types of commands: simple commands (e.g. “Copy”, “Cut”, “Paste”) and parametrized commands (“InsertText”, “FindString”, etc.).
Most of commands can be executed only in a WYSIWYG editor (e.g. “FontSize”, “ForegroundColor”, “Bold”, etc.), HTML text filed or text area (“InsertText”, “Cut”, “Delete”, etc.).
To execute command you need to use the Browser.executeCommand(EditorCommand command)
method to execute simple commands or the Browser.executeCommand(EditorCommand command, String value)
method to execute parameterised command.
browser.executeCommand(EditorCommand.SELECT_ALL);
browser.executeCommand(EditorCommand.COPY);
browser.executeCommand(EditorCommand.CUT);
browser.executeCommand(EditorCommand.PASTE);
browser.executeCommand(EditorCommand.INSERT_TEXT, "Text");
Render Process Events
Each Browser
instance is running in a separate native process where the web page is rendered. Sometimes this process can exit unexpectedly because of the crash in plugin. To receive notifications about unexpected render process termination you can use RenderListener
. When you receive notification about render process termination you can display a “sad” icon like Google Chrome does, for example, to inform the user that this particular Browser
component has crashed.
browser.addRenderListener(new RenderAdapter() {
@Override
public void onRenderCreated(RenderEvent event) {
System.out.println("Render process is created.");
}
@Override
public void onRenderGone(RenderEvent event) {
System.out.println("Render process is gone:");
TerminationStatus terminationStatus =
event.getTerminationStatus();
System.out.println("Termination Status: " + terminationStatus);
}
});
If you refresh or load the same or another URL, the render process and Browser
instance will be restored. Example:
browser.addRenderListener(new RenderAdapter() {
@Override
public void onRenderGone(RenderEvent event) {
Browser browser = event.getBrowser();
// Restore Browser instance by loading the same URL
browser.loadURL(browser.getURL());
}
});
User Agent
The user-agent string can be modified only once, before you create any Browser
instances. You can provide your own user-agent string using the BrowserPreferences.setUserAgent(String userAgent)
method or via the jxbrowser.chromium.user-agent
Java System Property:
BrowserPreferences.setUserAgent("My User Agent String");