Particle is a Java alternative to Electron. It is based on SWTs Browser and uses a native browser engine (WebKit on Linux & macOS, Edge on Windows).
Warning
This project is in active development, and caution is advised when considering it for production uses. You can use it, but you should expect APIs to change often, things to move around and/or break, and all that jazz. Binary compatibility is not guaranteed across releases, and APIs are still in flux and subject to change.
I really like HTML & CSS for UI, but I very much dislike Electron. This led me down a rabbit whole, where I accidentally
stumbled upon the SWT Browser widget. This widget uses the system browser engine and allows bidirectional calls
(BrowserFunction
s to call Java from JavaScript, and browser.execute
to execute JavaScript from Java). This project
aims to make usage of this widget easier.
- Java 17
- The correct SWT library in your classpath (OS and CPU architecture)
- Right now testing is a huge question mark as SWT makes no effort to be testable outside the Eclipse world, e.g. there is SWTBot for UI testing, but no Maven artifacts are provided.
- Easier SWT setup with Particle Window
- Expose Java functions to the browser with Particle Function Java
- Execute JavaScript code in the browser using Particle Function JavaScript
This is a convenience project for easier setup of an SWT display, shell and browser by providing the ParticleWindow. The browser widget takes the full size of the shell.
Although it is possible to provide HTML to the browser through browser.setText
, Particle Window expects a URL (either
a web URL or a file URL), since browser.setText
does not properly work with Microsoft Edge. In case of a file URL,
make sure that all JavaScript and CSS is inlined, otherwise you will run into issues with CSP (Content Security Policy).
- Build a single HTML file with inlined JavaScript, CSS and images
- Copy the HTML file into the user home folder, eg
~/.my-application/index.html
- Provide a file URL to the index file
This project provides the annotation BrowserMapping,
which can be used to mark classes and methods to be exposed through the window
object inside the
Browser widget.
The BrowserMappingProcessor processes
objects containing this annotation to the provided browser.
@BrowserMapping(prefix = "incrementer")
public class Incrementer {
private int number = 0;
@BrowserMapping
public int increment() {
number++;
return number;
}
}
This code will expose the increment function through window.incrementer_increment()
inside the browser.
By default, SWTs own BrowserFunction
only supports primitive types. This project provides support for objects by using a Jackson ObjectMapper
to turn those
objects into a String and parsing String into objects. This means that the JavaScript side has to use JSON.parse
and
JSON.stringify
for communication.
This project provides support for executing JavaScript code inside the browser. The code can be provided through
interfaces annotated with @JavaScriptFile
, whose methods are annotated with @JavaScriptCode("js-code")
.
@JavaScriptFile
public interface SomeJavaScript {
@JavaScriptCode(
// language=JavaScript
"""
document.body.style.backgroundColor = "red";
"""
)
void makeBodyRed();
}
- JavaScript cannot return values; behind the scenes,
browser.execute
is used to execute the code, which only returnstrue
on successful execution,false
otherwise
GitHub requires authentication to use a project's package registry. The cleanest version is to set your GitHub user and
an access token in your global Gradle properties file under ~/.gradle/gradle.properties
. This example assumes that
GPR_USER (your GitHub username) and GPR_KEY (an access token) are set in the global properties file.
In case of a pipeline: GITHUB_ACTOR
is a variable used in GitHub actions. Make sure to provide an access token through
a secret in your pipeline.
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/bitfist/particle")
credentials {
username = project.findProperty("GPR_USER") as String? ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("GPR_KEY") as String? ?: System.getenv("GPR_KEY")
}
}
}
name: 'test'
...
env:
GPR_KEY: ${{ secrets.GPR_KEY }}