I recently integrated the Java Chromium Embedded Framework (https://github.com/chromiumembedded/java-cef) in a Netbeans (RCP) Application Project (Java: JDK11).
The Browser Window is shown in a Netbeans TopComponent and generally works just fine.
However I have several rather small, but nasty bugs that I noticed which are always following the same pattern: Whatever code I execute that concerns the jcef browser always only works when I execute it a second time and is all but ignored the first time around. However there are no error messages or logs or any thing like that and the code seems to be executed when I go through it with the debugging tool.
Three examples:
true
for browser.canGoBack()
. If it returns true
a button is activated.false
, but it returns true just after the second change of url.(Should obviously happen after the first)false
again - Which it doesn't.false
for canGoBack()
(which should then obviously be true
) and only returns true
after the second URL change again.canGoBack
always shows the return it should have shown from its previous execution, as if lagging behind one time.callback.Continue(ad.getUsername(), ad.getPassword());
is executed, nothing at all is actually send to the server...Code for the third example:
cefClient_.addRequestHandler(new CefRequestHandlerAdapter() {
@Override
public boolean getAuthCredentials(CefBrowser browser, String origin_url, boolean isProxy, String host,
int port, String realm, String scheme, CefAuthCallback callback) {
AuthenticationDialog ad = new AuthenticationDialog();
ad.authenticate(); // Shows Login Dialog
LOGGER.log(Level.INFO, String.format("--->%s:%s", ad.getUsername(), ad.getPassword())); //This confirms that the variables are indeed correct even the first time around
callback.Continue(ad.getUsername(), ad.getPassword());
return true;
}
});
Sadly I don't have any clue anymore what could possibly cause these problems.
If anyone of you has had these same problems or has any idea as to how to fix them or even where to start looking for a fix I would very much appreciate your comments.
Thanks in advance!
I found the answer(s) to the afore mentioned questions. In case someone else will stumble upon similar issues in the future I'm going to shortly summarize what fixed it for me.
Apparently most of the problems I faced arose from threading problems. It seems like when you execute a command on the jcef browser while it's thread is still working on something, your command will not be executed, but there also won't be any error messages or other unwanted behaviour.
Example for the second problem:
When the go(url)
command was executed the browser had not finished loading the initial home page completely yet. That's why the command was ignored.
To fix this I added a simple String variable that will save the URL that someone wants to load until the browser has finished loading the previous page.
Only then will this url be loaded in the browser and consequently be deleted from the variable.
This could of course also be done with something like a list, but I can't think of a scenario where that would be useful.
Checking whether the browser is done loading should be done in the overridden method onLoadingStateChange
of the CefLoadHandlerAdapter
.
client_.addLoadHandler(new CefLoadHandlerAdapter() {
@Override
public void onLoadingStateChange(CefBrowser browser, boolean isLoading,
boolean canGoBack, boolean canGoForward) {
if (!isLoading) {
browser_ready = true;
if (goOnReady != null) {
goURL(goOnReady);
}
}
}
});
A similar issue was present with the first example from the original question.
Activating the "Back" button within the afore mentioned onLoadingStateChange
via the canGoBack
variable did the trick for me in the end.
Now the third example (the login dialog showing twice) turned out to be a problem that was also present in the official detailed example code from the jcef github page. This problem seems like it might be a threading problem again, but I'm not sure this time. As a workaround I implemented the following solution:
getAuthCredentials
method (see original question) and save the given username and password in these class variables.browser.reload();
callback.Continue(username, password);
thus only showing one login dialog to the user.This process is also very quick so the user want be able to notice the reload.