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
Browser
This guide describes how to create, use, and close Browser
.
Please consider reading the Architecture guide to better understand how the JxBrowser architecture is designed, what main components it provides, and how it works.
Creating Browser
To create a new Browser
instance please use the Profile.newBrowser()
method. For example:
Browser browser = profile.newBrowser();
val browser = profile.newBrowser()
If you use Engine.newBrowser()
then the browser is created under the default profile.
Browser browser = engine.newBrowser();
val browser = engine.newBrowser()
This method performs the following actions:
- Creates a new
Browser
instance. - Loads the
about:blank
web page in it and waits until the web page is loaded completely.
Closing Browser
The Browser
instance is running in a separate native process that allocates memory and system resources to be released. So, when a Browser
instance is no longer needed, it should be closed through the Browser.close()
method to release all the allocated memory and system resources. For example:
Browser browser = engine.newBrowser();
...
browser.close();
val browser = engine.newBrowser()
...
browser.close()
An attempt to use an already closed Browser
instance will lead to the IllegalStateException
.
The Browser
instance is closed automatically in the following cases:
- When its
Engine
is closed or unexpectedly crashed. - When
Browser
is a pop-up that is closed from JavaScript usingwindow.close()
.
To get notifications when the Browser
instance is closed, please use the BrowserClosed
event. For example:
browser.on(BrowserClosed.class, event -> {});
browser.on(BrowserClosed::class.java) { event -> }
To check whether Browser
is closed please use the isClosed()
method:
boolean closed = browser.isClosed();
val closed = browser.isClosed
Browser Size
By default Browser
size is empty. If you want to work with DOM or Find Text on a web page please configure the size.
To update the size of the Browser
please use resize(int width, int height)
. For example:
browser.resize(800, 600);
browser.resize(800, 600)
This method notifies Chromium that the size of the Browser
has been changed. Chromium will update the DOM layout of the loaded web page and repaint its content asynchronously. So, it might take some time for the web page to be repainted after the method returns.
User Agent
You can override the default User Agent string and configure Browser
to use a custom string. For example:
browser.userAgent("<user-agent>");
browser.userAgent("<user-agent>")
To get the current user agent string please use:
String userAgent = browser.userAgent();
val userAgent = browser.userAgent()
Remote Debugging URL
To get the remote debugging URL for a web page loaded in a particular Browser
instance, use the following approach:
browser.devTools().remoteDebuggingUrl().ifPresent(url -> {});
browser.devTools().remoteDebuggingUrl().ifPresent { url -> }
This approach returns a valid URL only if the Engine
was configured with the Remote Debugging Port.
Mouse and Keyboard Events
JxBrowser provides functionality that allows you to intercept the mouse and keyboard events before they will be sent to the web page using the following callbacks:
EnterMouseCallback
ExitMouseCallback
MoveMouseCallback
MoveMouseWheelCallback
PressKeyCallback
PressMouseCallback
ReleaseKeyCallback
ReleaseMouseCallback
TypeKeyCallback
The following example demonstrates how to suppress mouse wheel:
browser.set(MoveMouseWheelCallback.class, params -> Response.suppress());
browser.set(MoveMouseWheelCallback::class.java, MoveMouseWheelCallback { Response.suppress() })
You can use these callbacks to get notifications about the mouse and keyboard events in order to implement hotkeys in your application. Or you can suppress the default shortcuts such as Ctrl+C
on Windows and Linux. For example:
browser.set(PressKeyCallback.class, params -> {
KeyPressed event = params.event();
boolean keyCodeC = event.keyCode() == KeyCode.KEY_CODE_C;
boolean controlDown = event.keyModifiers().isControlDown();
if (controlDown && keyCodeC) {
return PressKeyCallback.Response.suppress();
}
return PressKeyCallback.Response.proceed();
});
browser.set(PressKeyCallback::class.java, PressKeyCallback { params ->
val event = params.event()
val keyCodeC = event.keyCode() == KeyCode.KEY_CODE_C
val controlDown = event.keyModifiers().isControlDown
if (controlDown && keyCodeC) {
PressKeyCallback.Response.suppress()
} else {
PressKeyCallback.Response.proceed()
}
})
Dispatch Keyboard Events
You can simulate typing into the focused DOM element of Browser
.
import static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly;
import static com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED;
import com.google.common.collect.ImmutableMap;
import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.navigation.event.FrameLoadFinished;
import com.teamdev.jxbrowser.ui.KeyCode;
import com.teamdev.jxbrowser.ui.event.KeyPressed;
import com.teamdev.jxbrowser.ui.event.KeyReleased;
import com.teamdev.jxbrowser.ui.event.KeyTyped;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
/**
* This example demonstrates how to dispatch the {@code KeyEvent} to the currently focused element
* on the loaded web page.
*/
public final class DispatchKeyEvents {
private static final String HTML = "<input id=\"input\" autofocus>";
private static final Map<Character, KeyCode> charToKeyCode;
public static void main(String[] args) {
Engine engine = Engine.newInstance(HARDWARE_ACCELERATED);
Browser browser = engine.newBrowser();
SwingUtilities.invokeLater(() -> {
BrowserView view = BrowserView.newInstance(browser);
JFrame frame = new JFrame("Dispatch key event");
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
engine.close();
}
});
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.add(view);
frame.setSize(800, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
loadHtmlAndWait(browser, HTML);
dispatchKey(browser, 'h');
dispatchKey(browser, 'i');
}
static {
charToKeyCode = ImmutableMap.<Character, KeyCode>builder()
.put('h', KeyCode.KEY_CODE_H)
.put('i', KeyCode.KEY_CODE_I)
.build();
}
private static void loadHtmlAndWait(Browser browser, String html) {
CountDownLatch latch = new CountDownLatch(1);
browser.mainFrame().ifPresent(mainFrame -> {
mainFrame.loadHtml(html);
});
browser.navigation().on(FrameLoadFinished.class, event -> latch.countDown());
awaitUninterruptibly(latch);
}
private static void dispatchKey(Browser browser, char character) {
dispatchKeyEvent(browser, character, charToKeyCode.get(character));
}
private static void dispatchKeyEvent(Browser browser, char character, KeyCode keyCode) {
KeyPressed keyPressed = KeyPressed.newBuilder(keyCode)
.keyChar(character)
.build();
KeyTyped keyTyped = KeyTyped.newBuilder(keyCode)
.keyChar(character)
.build();
KeyReleased keyReleased = KeyReleased.newBuilder(keyCode)
.build();
browser.dispatch(keyPressed);
browser.dispatch(keyTyped);
browser.dispatch(keyReleased);
}
}
import com.google.common.util.concurrent.Uninterruptibles
import com.teamdev.jxbrowser.browser.Browser
import com.teamdev.jxbrowser.engine.Engine
import com.teamdev.jxbrowser.engine.RenderingMode
import com.teamdev.jxbrowser.frame.Frame
import com.teamdev.jxbrowser.navigation.event.FrameLoadFinished
import com.teamdev.jxbrowser.ui.KeyCode
import com.teamdev.jxbrowser.ui.event.KeyPressed
import com.teamdev.jxbrowser.ui.event.KeyReleased
import com.teamdev.jxbrowser.ui.event.KeyTyped
import com.teamdev.jxbrowser.view.swing.BrowserView
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import java.util.concurrent.CountDownLatch
import javax.swing.JFrame
import javax.swing.SwingUtilities
import javax.swing.WindowConstants
private const val HTML = "<input id=\"input\" autofocus>"
private val charToKeyCode: Map<Char, KeyCode> = mapOf(
'h' to KeyCode.KEY_CODE_H,
'i' to KeyCode.KEY_CODE_I
)
/**
* This example demonstrates how to dispatch the `KeyEvent` to the currently focused element
* on the loaded web page.
*/
fun main() {
val engine = Engine.newInstance(RenderingMode.HARDWARE_ACCELERATED)
val browser = engine.newBrowser()
SwingUtilities.invokeLater {
val view = BrowserView.newInstance(browser)
val frame = JFrame("Dispatch key event")
frame.addWindowListener(object : WindowAdapter() {
override fun windowClosing(e: WindowEvent) {
engine.close()
}
})
frame.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
frame.add(view)
frame.setSize(800, 500)
frame.setLocationRelativeTo(null)
frame.isVisible = true
}
loadHtmlAndWait(browser, HTML)
dispatchKey(browser, 'h')
dispatchKey(browser, 'i')
}
private fun loadHtmlAndWait(browser: Browser, html: String) {
val latch = CountDownLatch(1)
browser.mainFrame().ifPresent { mainFrame: Frame -> mainFrame.loadHtml(html) }
browser.navigation().on(FrameLoadFinished::class.java) { latch.countDown() }
Uninterruptibles.awaitUninterruptibly(latch)
}
private fun dispatchKey(browser: Browser, character: Char) {
dispatchKeyEvent(browser, character, charToKeyCode[character])
}
private fun dispatchKeyEvent(browser: Browser, character: Char, keyCode: KeyCode?) {
val keyPressed = KeyPressed.newBuilder(keyCode)
.keyChar(character)
.build()
val keyTyped = KeyTyped.newBuilder(keyCode)
.keyChar(character)
.build()
val keyReleased = KeyReleased.newBuilder(keyCode)
.build()
browser.dispatch(keyPressed)
browser.dispatch(keyTyped)
browser.dispatch(keyReleased)
}
Screen Sharing
Some web pages may want to start a screen sharing session. Chromium has the built-in functionality that allows sharing a screen, an application window, or a web page. In 7.20 the library API was extended with functionality that allows programmatically handling such requests or just display the standard Chromium dialog where the user can select the capture source.
To display the standard dialog use the following approach:
browser.set(StartCaptureSessionCallback.class, (params, tell) ->
tell.showSelectSourceDialog());
browser.set(StartCaptureSessionCallback::class.java,
StartCaptureSessionCallback { params, tell -> tell.showSelectSourceDialog() }
)
If you don’t want to display the dialog and would like to programmatically handle the requests, you can always programmatically select the capture source and start session:
browser.set(StartCaptureSessionCallback.class, (params, tell) -> {
CaptureSources sources = params.sources();
CaptureSource screen = sources.screens().get(0);
// Tell the browser instance to start a new capture session
// with the given capture source (the first entire screen).
tell.selectSource(screen, AudioCaptureMode.CAPTURE);
});
browser.set(StartCaptureSessionCallback::class.java,
StartCaptureSessionCallback { params, tell ->
val sources = params.sources()
val screen = sources.screens().first()
// Tell the browser instance to start a new capture session
// with the given capture source (the first entire screen).
tell.selectSource(screen, AudioCaptureMode.CAPTURE)
}
)
To programmatically stop the session, use the CaptureSessionStarted
event. This event is triggered when a new capture session has been started. You can get a reference to the capture session and stop it anytime. The following example demonstrates how to stop the started capture session in 5 seconds:
browser.on(CaptureSessionStarted.class, event -> {
CaptureSession captureSession = event.capture();
new java.util.Timer().schedule(new TimerTask() {
@Override public void run() {
// Stop the capture session in 5 seconds.
captureSession.stop();
}
}, 5000);
});
browser.on(CaptureSessionStarted::class.java) { event ->
val captureSession = event.capture()
java.util.Timer().schedule(5000) {
// Stop the capture session in 5 seconds.
captureSession.stop()
}
}
Desktop Notifications
Secure (HTTPS) web pages may display desktop notifications to the end user via the Notifications API. The API is designed to be compatible with existing notification systems, across different platforms.
Notifications will not work if the web page is not secure (HTTPS).
To display the desktop notification you must grant the corresponding permissions:
engine.permissions().set(RequestPermissionCallback.class, (params, tell) -> {
if (params.permissionType() == PermissionType.NOTIFICATIONS) {
tell.grant();
} else {
tell.deny();
}
});
engine.permissions().set(RequestPermissionCallback::class.java,
RequestPermissionCallback { params, tell ->
if (params.permissionType() == PermissionType.NOTIFICATIONS) {
tell.grant()
} else {
tell.deny()
}
}
)
Some platforms require additional configuration to enable desktop notifications. On macOS, when JxBrowser is launched for the first time, the end user will be prompted to allow Chromium to show notifications.
Alternatively, the end user can enable/disable notifications for Chromium in macOS System Preferences -> Notification Centre:
DevTools
You can show/hide the DevTools window programmatically without configuring Remote Debugging Port:
browser.devTools().show();
browser.devTools().show()
DevTools will be displayed in a separate window: