📜 ⬆️ ⬇️

JavaFX WebView (HTML / JS) - we use web practices for developing desktop applications

image
JavaFX was chosen as the base UI framework for our application. JavaFX has performed well. In the same article, we wanted to focus on one component of JavaFX - WebView.

When developing our application, the COLT interface, we used the approach that is gaining popularity among developers when some of the UI components are implemented in JavaScript / HTML.

The HTML / JS-based component is a regular Java class, a regular JavaFX component with a layout — HBox or just Pane, which contains an instance of the Webview component.
')

How to create an instance of webkit in JavaFX and upload HTML


WebView webView = new WebView(); WebEngine engine = webView.getEngine(); engine.load(this.getClass().getResource("html/webview.html").toExternalForm()) 


What we got using web technology in our application.

Tons of ready-made solutions


jQuery, D3 covers almost all of our tasks. We need a ready-made solution - we find it through Google in 5 minutes. It's great that the analogues of the interface elements are filled to capacity by the whole Internet. And all in the public domain. You can peep the idea and take its implementation.

Cheap


In Java, the same that we implemented on JS / HTML would be difficult to write.

For example, this component to add paths. As a basis, we took the tag engine and properly “finished” it. It turned out a very clever and pleasant thing. It can edit in the “tag” mode, and by double-clicking it still allows you to simply work with the text. Work with "clipboard".

image

Prior to this, in the previous version of the interface, we used an ugly list-view. Our new fileset is simple, compact, modern. There are ideas how to further extend its functionality.

The second example is the log view.

image

First, we wanted to make a component based on a ListView. We did not receive any special problems with skinning, but still the component turned out to be unsuitable for real use by users. For example, it was impossible to select logs as text, several blocks at once, the implementation of the component threatened to result in a considerable amount of code. The HTML component is light and extensible. It should be noted that JavaFX uses GPU for DOM rendering, so the component turned out to be quite productive. We plan to expand the component by searching for logs, filters, etc. We plan to implement all this with JavaScript / CSS.

Maybe we are just not so good at Java-UI, but it was really difficult for us to write components with complex interactivity to Java. Where you need a ready-made component, an example of which you can “google” - yes, everything is easy and simple. Linking data and “views” through “binding” is again very simple and familiar (our previous experience is Adobe Flex). But when it comes to something that goes beyond the standard case studies described in the documentation - we lost too much time on the “search”.

We have developed the following scheme for ourselves - we are trying to do it through JavaFX components, and if we “run into the wall,” or the implementation becomes too complicated, then we write in HTML. This approach greatly accelerated our development.

Cross Platform


The JavaFX webview engine is a webkit. Works the same on any platform. We practically did not waste time on cross-platform relationships.

Java javascript bridge


A bundle of Java-JavaScript, a bridge between them allows you to make calls to Java classes from HTML, as well as invoke JavaScript code from Java. A simple example of Java code:

 private void clear() { JSObject windowObject = (JSObject)webView.getEngine().executeScript("window"); windowObject.call("test", new ArrayList(1, 2, 3)); } 

And this JavaScript code that accepts data and calls the methods of the ArrayList java -

 function test(list){ console.log("list.size() - " + list.size();//3 console.log("list.get(0) - " + list;//1 } 

An example of course is not quite real, synthetics, but it is clear that the methods are invoked, and the data is accepted.

When downloading html, you can add a link to the application directly to the Window object.

 JSObject windowObject = (JSObject) webView.engine.executeScript("window"); windowObject.setMember("app", this); 

And call Java methods from JavaScript code -

 app.addData($("my-input").val()); 

A more correct (more secure) approach is to create a special object in a Java environment that restricts access and allows only “allowed” methods to be called from an application in JavaScript.

 windowObject.setMember("app", new JSBridge(){ public myMethod(){ MyApp.this.myMethod(); } }); 

Another example of a bundle through the JS "alert". We needed to catch the “load” html - full initialization of the application. All other methods were not so reliable. What we did.

As usual in JavaScript via jquery:

 $(function(){ alert("command:ready"); }); 

In Java, we added an “onAlert” handler for webview.engine and now we know for sure that HTML is loaded and initialized.

 engine.onAlert = new EventHandler<WebEvent<String>>() { @Override void handle(WebEvent<String> event) { if("command:ready".equals(event.getData())){ //TODO: initialize } } } 

Reuse code


The code that we wrote for our application for computers we plan to reuse for mobile development. On the mobile application (objective-c / java) we will also create a component based on Webview, most of the functionality will be ready.

What difficulties have we encountered when working with HTML / JS in JavaFX?


The first. Document upload life cycle. You can call methods in JS only after the page is fully loaded; the documentation suggests a path to track the page state change event in Java. This approach was quite buggy. As mentioned earlier - a bunch of “load” events on the html side and interception of “alert” on the Java side, solved this problem.

The second problem that drank our blood is glitches with calls to multiple JavaScript functions at the same time in different components from a webview. Moreover, such a bug has emerged quite recently and is very similar to the optimization that was added to the webkit engine in JavaFX. In any case, you can get an error about infinite recursion in JavaScript literally from scratch. This problem is solved quite easily - we wrap the JavaScript call from Java using Platform.runLater ().

The third problem. Debag and logging.
At the first stage of work, when prototyping is in progress and you work only with HTML / JS, you can test it just in the browser. At the stage of integration with Java, your code simply stops working without the right environment. And you are more and more often starting to build a Java application in order to test the functionality in JavaScript. A build Java application and its launch is a long second of waiting. What techniques in the work we used to avoid such a long load and not lose time?

Simple and obvious let - add a "reload" page by key combination. Corrected HTML / CSS / JS - clicked F5 - the content of WebView was overloaded:

 $(document).keydown(function (e) { if(e.keyCode == 116 /*F5*/){ location.reload(); } }); 

But in addition to a quick "refresh" we need to view the logs.
A fairly simple solution was to add FireBug Lite -

 <script type='text/JavaScript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> 


And of course, as soon as our application “breathed” and earned livecoding for HTML / JS, we began to use COLT to develop COLT. At the moment, the functionality of our application covers most cases - we no longer need FireBug Lite. Log, live update, remote testing, livecoding. Livkoding in our opinion can replace debag, but users are asking, and we will also fix the “real debug with breakpoints”.

How to connect? Just add the following code to the html document

 var url = "http://<address>:<port>/webview.html"; if (location.href != url) { location.href = url } 

Where url is the address where COLT launches the transformed page. It's easy to learn. Create a project COLT, specify a link to our page - "Main Document" and start the session - click "green lightning".

image

The page will open in the browser. Let us copy to the page and paste into our JS code. Browser window is closing. Now run the JavaFX application. We try to change the content of the page, JavaScript and livecoding will work directly in the JavaFX application.

In the new version, in the settings, in the “Advanced” block, we added a special text field with this snippet. Without starting the project, you can copy this code directly from the COLT settings.

image

Logs will appear in the COLT window. So that the next time Colt didn’t open the browser, he launched your application, you can choose not to launch the browser, but to launch from the console. In our project, we simply copied the text from the output of our run-configuration IDEA and added this call to the COLT console luncher.

image

image

Now, when you click on the "green eyebrow", a Java application window will be launched.

In general, the approach to redirecting HTML inside to a live page is universal. He, for example, works great on PhoneGap. The application runs on a mobile device (the main thing is that the device is on the same local network) and updates are delivered without the need for a restart. You need to remember the order of actions - and you can apply wherever there is a WebView.

It has become a good practice to add a function to the code change event.

 //@code-update function live(){ console.log("live update"); } 

The @ code-update annotation intercepts our AST transformations and adds a listener to the code update event.

A typical case of working with such a handler is to call functions in code (that is, what we usually write to the FireBug console). You can change the value or call a function when the application is already running. Added code, saved - code executed.
Plus it is convenient to “treysit”, output data, the value of which you need to know in “runtime”, without stopping the code - you can simply output them to the console.

Groovy


Just a little beyond the scope of the article, the conclusion that we made during the implementation of our project and which we would like to share is that it is better to write UI in a language more concise than Java. We used Groovy for this and are very pleased. The amount of code was reduced ten times, and work with XML and the file system was also simplified by an order of magnitude. AST transformations to create Bindable properties, our transformations allowed us to mix services into controllers, generate Bindable wrappers for simple data. And so on. What is called must have. About using Groovy for JavaFX, we are writing a separate article .

Plans


The approach that we used in the development of our desktop application, we began to apply for mobile development. We use PhoneGap + COLT and the case is almost the same as JavaFX + HTML + COLT.

We chose PhoneGap, and not another platform, since we had already accumulated a lot of things ready in the desktop project and it seemed to us inexpedient to rewrite it to another platform. If our application requires you to abandon PhoneGap, we will rewrite part of the application to “nativ”, but we will not lose all the functionality that is written in HTML / JS. They will just run differently.

Project site codeorchestra.com

Source: https://habr.com/ru/post/198776/


All Articles