Category Archives: Java

Maven2iOS

Video: Building a Codename One Project for iOS

This is the third video in my series about our new online tool, Codename One initializr, which allows you to generate a Maven starter project for a native mobile app in one click. The first video showed how to generate the starter project, and run it in the Codename One simulator. The second video showed how to build and deploy the project on an Android device. In this video I show how to build and deploy the project on an iOS device.

TLDW (Too Long Didn’t Watch):

This video starts out with my Codename One project already opened in IntelliJ. See this post for steps on how to generate this project.

In the video I demonstrate two different approaches for building the iOS app.

  1. Locally (0:55-2:45) – Requires a Mac with Xcode Installed.
  2. Using Build Server (6:45-8:35) – Can be built on Windows, Linux, or Mac. With no special requirements beyond Maven and the JDK. You just need a free Codename One account.

NOTE: I also show how to generate your iOS certificates and provisioning profiles using the Certificate Wizard (2:45-6:45), as this is required to build apps for iOS.

Building Locally

The local build option generates an Xcode project, which we then open and build using Xcode.

To trigger this build, select “Local Builds” > “Xcode iOS Project”:

Screen Shot 2021-04-06 at 5.51.41 AM

Then press the “Run” button.

It takes the ParparVM compiler a minute or two to do its thing, but when it’s done, it opens the generated Xcode project in Xcode.

Screen Shot 2021-04-06 at 5.55.03 AM

Once opened, I press the “Run” button on the Xcode toolbar and wait while it compiles the project. When it is done, it opens the iOS simulator with my app running in it.

Screen Shot 2021-04-06 at 5.58.05 AM

Building with the Build Server

One of the nice things about Codename One is that it provides a build server with all of the native build tools installed and up-to-date. This simplifies the process of building native apps greatly. You can build your project for iOS, Android, Mac Desktop, Windows Desktop, Windows UWP, and Javascript without requiring any special build tools installed beyond the JDK. Building for any of these targets is as simple as pressing a button, or running a Maven goal.

Generating Certificates

Building for iOS requires that you have an Apple developer account. Additionally, Apple requires you to generate certificates and provisioning profiles for your apps. This is by far the most painful part of app development. To help ease the pain, Codename One provides a certificate wizard to help generate these. Before I can submit my first iOS build, I need to walk through the certificate wizard to generate these certificates. The certificate wizard process starts at approx 2:45 in the video, and runs until 6:45.

To access the certificate wizard, I need to open Codename One Settings. I do this by selecting “Tools” > “Codename One Settings” from IntelliJ’s configuration menu, then pressing the “Run” button.

Screen Shot 2021-04-06 at 6.11.27 AM

This will open The Control Center (aka Codename One Settings, aka Codename One Preferences):

Screen Shot 2021-04-06 at 6.12.53 AM

Once there, I select “Device Settings” > “iOS” > “Certificate Wizard” from the navigation menu on the left.

Screen Shot 2021-04-06 at 6.13.55 AM

This displays the login form for the certificate wizard:

Screen Shot 2021-04-06 at 6.15.40 AM

IMPORTANT: You need to use your Apple Developer account to login to this form. NOT your Codename One account.

In the video I spliced out some of the waiting time. The login can take a little while, so be patient. Once logged in, it shows me a list of my registered development devices, and I can select which ones I want to be able to deploy this app to for testing and debugging.

Screen Shot 2021-04-06 at 6.17.06 AM

The above screenshot has all of the rows greyed out. When you log in, you’ll see device names and UDIDs listed on this form.

Generally I select all of them. If this is your first time building an iOS app, then you may not have any devices listed yet, and you’ll need to click on the “Manage Devices” button and follow the instructions there.

Next, it asks me to confirm that I want to regenerate my certificates, as it has detected that I already have certificates generated in my Apple account. In my case, I say “yes”, I’d like to regenerate them, but in most cases, you would select “no”, to just use your existing certificates.

TIP: If your certificates were generated by the certificate wizard, then a copy of them has been stored inside the $HOME/.codenameone/iosCerts directory, and the wizard will use them automatically. If they weren’t generated by the certificate wizard, and you choose not to regenerate them, then you may need to specify the location of your certificates in the iOS Settings section.

Screen Shot 2021-04-06 at 6.25.52 AM

Next, it asks whether we want to generate push certificates. In this case, since this is just a basic Hello World app, we don’t need push, so I leave these options OFF.

Screen Shot 2021-04-06 at 6.27.38 AM

After clicking next, it will churn for a bit, and if all goes well, it will show us the message that our certificates were generated and installed successfully.

Just to be sure that my settings are saved. I click on the hamburger menu in the upper right, and select “Save”.

Screen Shot 2021-04-06 at 6.29.40 AM

Sending the Build

Now that the certificates are generated, we can send the build. Back in IntelliJ, I select “Build Server” > “iOS Debug Build”

Screen Shot 2021-04-06 at 6.32.38 AM

NOTE: If this is your first time building with the build server, you may be prompted for your Codename One username and password.

I then follow the progress of the build on the Codename One website.

When it’s finished, I get a set of links to do things like download the .ipa, or install the app on device.

Screen Shot 2021-04-06 at 6.34.32 AM

Get Started

Getting started with your own native app is really easy. Just go to the Codename One initializr, enter your app details, and press “Download”.

For more information about Codename One, see the Codename One website.

domenico-loia-1000x667

Deploying Apps on Multiple Form-Factors

Photo by Domenico Loia on Unsplash

The other day I stumbled across this post whose title seemed to suggest that Flutter is not a cross-platform framework.

Screen Shot 2021-04-06 at 10.08.33 AM

The thrust of his article is that, even though Flutter allows you to build your app for 6 platforms, that doesn’t mean that you should:

Yes, you can deploy your app on 6 platforms, but honestly, I am not planning to do so. Basically, because YOU SHOULD use different design patterns depending on the platform. I can’t imagine deploying my apps on a different platform.

At first glance, he appears to be arguing for writing separate apps for each platform (e.g. Android, iOS, Mac, Windows, etc…). This idea that you need to write a separate app for each platform using the platform’s native UI toolkit is widespread in the developer community. “Native Widget Maximalists”, as I call them, believe that using cross-platform UI libraries will result in a sub-par, “non-native” experience, and will, therefore, be rejected by the user. Generally, adherents to this philosophy are fine with sharing “business logic”, but the user interface must use the native UI widgets. Much of this dogma is based on dated observations of clunky, cross-platform, desktop apps of the mid to late nineties – many of them developed by novices using early incarnations of Swing.

Since that time, cross-platform toolkits have matured, and platforms have converged on some common UI design patterns. This is especially the case on mobile, where many popular native apps look nearly identical on Android and iOS. Mobile developers have realized that it is more important to create a nice, consistent design than it is to try to “look native”. Yes, there are differences between iOS and Android, but the differences are the exception – not the rule. In my opinion it is overkill to maintain two separate codebases for the 2% of the UI where they diverge. Better to provide abstractions that allow that 2% delta to be satisfied in platform-specific ways.

If you read further into the article, you’ll see that the author actually isn’t a “native widget maximalist”. I.e. He isn’t arguing that you should build separate apps for iOS and Android using their native SDKs. He isn’t even arguing that you need to write separate apps for iOS and Android.

Usually what works on mobile won’t work on desktop and the other way around.

What he’s saying is that you shouldn’t deploy the same app on desktop as you do on mobile, because the form factor is too different. If this is his thesis, then I agree with him… with some caveats.

Strategies for targeting multiple form factors

Disclaimer: I work for Codename One.

Two of the best cross-platform development tools for mobile development are Codename One and Flutter. They approach the problem of cross-platform development in very similar ways. Both provide 100% code reuse across platforms. Both provide a rich set of UI components and API abstractions for the underlying device capabilities, and both can be deployed to iOS and Android (and other platforms), as native apps. Codename One apps are developed in Java and/or Kotlin. Flutter, in Dart.

Both Codename One and Flutter also allow you to deploy your app as a desktop app. However, if you don’t tweak your UI for the larger screen-size, and desktop usage patterns, the result probably won’t be very good. Even using mobile apps on tablet feels forced if you haven’t customized the UI for the larger screen-size. There are four strategies I use when building a multi-form-factor app (i.e. an app that runs on mobile and desktop):

1. Responsive UI

Screen Shot 2021-04-06 at 10.26.54 AM

This is where the app logic is essentially the same across both form-factors, but the layout manager, and styles are “form-factor”-aware. E.g. On tablet/desktop they use different styles, and the layout managers position elements differently. (E.g. Instead of a hamburger button that reveals a side-menu sliding out over top of the form, the side menu is always visible).

2. Component-level abstraction

Screen Shot 2021-04-06 at 10.47.10 AM

This is where most of the app’s control flow is the same, but certain parts of each form are abstracted to allow for different implementations on desktop, tablet and mobile. This may involve using a different widget for editing some field, displaying some extra sections on desktop that aren’t visible on mobile. This is very similar to Responsive UI, and there is certainly overlap. The distinction is that with Responsive UI, you are keeping all of the same UI elements – you’re just rendering them differently. With component-level abstraction, the UI form may actually include different UI components with different logic on desktop than it does on mobile.

3. Alternate views

Screen Shot 2021-04-06 at 10.57.34 AM

This is where the app’s control flow is the same, but you create entirely different views on mobile than on tablet. If you are very careful with the design of your views, you may be able to reuse your controller classes, as long as the views share common APIs, and fire compatible events. Keeping them in sync can be challenging, so quite often you would also write separate controllers as well.

4. Separate control-flow

Screen Shot 2021-04-06 at 10.58.55 AM

This is where you are basically implementing two separate apps. You can reuse business logic, but the UI layer is written separately for tablet/desktop and mobile.

5. Separate apps

Screen Shot 2021-04-06 at 11.01.43 AM

If you are already implementing your app with separate control flow, then creating separate apps is just one small additional step. Generally you would still share all of your business logic between the apps. You would just provide alternate entry points for the different apps. With Codename One, this can be achieved either by moving all of the code into a shared library (cn1lib), or by simply providing an alternate configuration file (codenameone_settings.properties) that specifies a different main class. Most build targets use Proguard, or equivalent, to strip out unused code, so the app size isn’t impacted by the code-sharing.

Best choice?

It appears that the author of the article is arguing for option #5 – Separate apps. His preference, he says, is informed by his experience working on large enterprise systems where there would be different teams working on the apps for different platforms, and keeping it all in the same app would lead to toes being stepped on. Option #4 (Separate flow control) should adequately address his concern as well, since each form-factor would have its own package, likely, and developers wouldn’t need to tread on anyone else’s garden.

My preference is to use the lowest number on that scale that I can get away with, and progress up the ladder as required. IntelliJ makes refactoring from one strategy to another mostly painless, and the less fragmentation there is in the code-base, the easier it will be to maintain – generally. Obviously adding team members, or splitting the project into multiple teams changes that maintenance calculation.

Still prefer a cross-platform development tool

Suppose your team decides to implement separate apps for each form-factor (Mobile, Tablet, and Desktop). Let’s even go a step further and suppose that you decide to implement separate apps for each platform (Android Mobile, Android Tablet, iPhone, iPad, Mac, Windows, Linux). Then is there still any benefit using a cross-platform toolkit like Codename One or Flutter? Since you’re doing separate apps, wouldn’t it be just as well to just use the native APIs?

Unless you have an unlimited supply of time, developers, and money, then the answer is “no”. You would be much worse off by choosing to use separate native SDKs for each platform. Even if you manage to write some shared modules that you were able to share between the projects, the complexity involved in maintaining separate codebases is staggering. Everything is 7x more difficult. Every bug is fixed 7 times, and testing gets ridiculously complex. In addition, keeping up with the latest on all of these platforms and APIs takes dedication. You would likely need to bring in separate teams for each platform – and very little of the work can be shared between the teams.

Using a technology like Flutter – even if you are building 7 separate apps, would be far easier. Sharing code between projects is much easier, and every developer can work on every project without facing barriers to entry imposed by the idiosyncrasies of each native API.

Summary

Just because you can deploy your app to 8 different platforms, doesn’t mean that you should. Deploying to multiple platforms within the same form factor (e.g. phones) is a solid approach with a proven track record – with countless popular apps on the iOS and Android app stores currently developed with cross-platform tools like Codename One and Flutter. However, deploying to multiple form-factors (e.g. phone and desktop) is more difficult, as what works on one form-factor, may not work well on another. You may be better served by creating separate projects for each form factor, and sharing business logic between them. This doesn’t mean that you should drop your cross-platform development tool (e.g. Flutter/Codename One). Using such a tool is still a benefit as it reduces the combined project complexity, and makes it easier to share code and developers between the projects.

Maven2Android

Codename One Project -> Build Android App

In my last post I showed off the new Codename One initializr online tool, generating a Maven project, and opened it in IntelliJ.

In this video I demonstrate how to build an Android app with this project.

TLDW (Too Long Didn’t Watch):

Here’s the gist of the video. There are two different build options for Android:

  1. Build Server > Android
  2. Local Builds > Android Gradle Project

In this video, I start with option 2, “Android Gradle Project”. This option does NOT require a Codename One account, and performs all of the build on your local machine. It does require that you have Android Studio installed.

I select “Local Builds” > “Android Gradle Project” from the Configuration menu of IntelliJ, and then press “Run”.

Screen Shot 2021-03-30 at 9.25.41 AM

This generates an Android Studio project, and automatically opens it in Android studio.

Screen Shot 2021-03-30 at 9.27.42 AM

I then press “Run” in the Android Studio, and wait while it builds and installs the app on my Android Emulator.

Screen Shot 2021-03-30 at 9.29.25 AM

In the second part of this video, I use the “Build Server” > “Android” build option, which is much simpler, and doesn’t require you to install Android Studio. All you need is IntelliJ (Actually you don’t even need IntelliJ, as you could just build the project using Maven), and it will use the Codename One build server to generate the Android app.

After selecting “Build Server” > “Android” from the configuration menu, I press “Run” to start the build.

Screen Shot 2021-03-30 at 9.30.39 AM

It then redirects me to the Codename One dashboard where I can monitor the build progress and, download the app when it’s done.

Screen Shot 2021-03-30 at 9.31.37 AM

More Background

When we decided to migrate to Maven, we also made the choice to add official local build targets so that developers are no longer reliant on the build server to build their Android and iOS apps. Building locally has always been an option, but it was difficult, and we didn’t provide support for it. By adding an official local build option, we are hoping that developers who balked at Codename One because they didn’t want to be reliant on us for their builds will give us another look.

If you haven’t heard of Codename One yet, I encourage you to check us out. In my biased opinion, we are the best game in town, if you’re looking to build native mobile apps in Java or Kotlin.

It only takes a minute to create and build your first project using Codename One initializr.

JAXB Hell on JDK 9+

JAXB has been removed from JavaSE starting in JDK 9, so we’ve had to make some changes to some of our code to work around this. We have some custom ANT tasks that use JAXB to process some XML. The task it used inside an ANT script using the <taskdef> tag as follows:

<taskdef name="myCustomTask" 
    classname="com.example.tasks.MyCustomTask" 
    classpath="MyCustomTask.jar"/>

Then laster the task us run using syntax like:

<myCustomTask />

If you try to run these ANT tasks on JDK 9 or higher, you just get a big ClassNotFound error when it tries to load the JAXB classes. So the obvious solution is to bundle the JAXB classes into our jar. This, however, only solves part of the problem. This will, indeed, allow the task to load, but when we try to run the task, it says

javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.

Which is strange because we have the API (jaxb-api.jar) and implementation (jaxb-impl.jar, jaxb-core.jar, activation.jar) embedded inside our MyCustomTask.jar file, which should be available on the classpath.

After banging my head against this problem for a few hours, I discovered that the problem is the way which JAXB looks for the implementation. It uses the threads classloader for searching for an implementation, rather than the classloader for our task. When running inside an ANT task, this will be the root classpath for Ant, and not the classpath for my custom ant task.

For example, we have some code like:

JAXBContext componentContext = JAXBContext.newInstance(ComponentEntry.class);

This will fail to find the JAXB implementation (unless we included the JAXB jars in Ant’s classpath – which is not portable in our case, because ANT will usually be run inside an IDE like Netbeans).

I ultimately worked around this problem by wrapping all of my JAXB code inside my own spawned thread. E.g.

private String processFileWithJAXB(final File xmlFile, final boolean full) throws JAXBException {
        final JAXBException[] error = new JAXBException[1];
        final String[] result = new String[1];

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    result[0] = processFileWithJAXBInternal(xmlFile, full);
                } catch (JAXBException ex) {
                    error[0] = ex;
                }
            }

        });
        ClassLoader cl = getClass().getClassLoader();
        t.setContextClassLoader(getClass().getClassLoader());
        t.start();

        try {
            t.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(MyClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (error[0] != null) {
            throw new JAXBException(error[0]);
        }
        return result[0];
    }

In this example, all of my JAXB stuff is inside the processFileWithJAXBInternal() method. The processFileWithJAXB method creates a thread, sets its context classloader to the current classes class loader, and runs it. And magically, it can find my bundled JAXB implementation.

Posting in my blog to help my memory as I’m bound to run into this issue again.

PSA: Prefer to use AdoptOpenJDK’s jdk-11 builds for embedding in Mac Apps

If you are planning to distribute a Java app on Mac, you should avoid using the JDK builds from jdk.java.net as they won’t necessarily work on Mac OS older than 10.13. This is because the libjvm.dylib is build with MACOSX_MIN_VERSION set to 10.13. This doesn’t necessarily cause a problem until you try to run a signed app on Yosemite or older (10.10). Your app just won’t open. Checking the logs you’ll receive an error like:

​Error: dl failure on line 542
Error: failed /Applications/MyApplication.app/Contents/Java/jre//lib/server/libjvm.dylib, because dlopen(/Applications/MyApplication.app/Contents/Java/jre//lib/server/libjvm.dylib, 10): no suitable image found.  Did find:
    /Applications/MyApplication.app/Contents/Java/jre//lib/server/libjvm.dylib: code signature invalid for '/Applications/MyApplication.app/Contents/Java/jre//lib/server/libjvm.dylib'

Now, you might be fine if you’re building the app on 10.10 or older, but not sure. This particular issue is a combination of:

  1. libjvm.dylib set with a min version of 10.13.
  2. codesign on 10.11 and higher automatically signs libs targeting 10.11 and higher with a different signature than is can be understood by gatekeeper pre 10.11.
  3. Gatekeeper barfing when it hits this signature.

So, If you’re building (signing) your app on the latest Mac OS and you want to be able to distribute it to older versions of OS X, you need to make sure that all of your libraries are built with the MACOSX_MIN_VERSION set to 10.10 or lower.

You can verify this using otool. Inside the standard openjdk build on jdk.net, you can go into the Contents/Home/lib directory, and run:

$ otool -l  */libjvm.dylib | grep VERSION -A 5 | grep version
  version 10.13
  version 0.0

(Note: libjvm.dylib is the only problematic one. All the other dylibs are built with 10.8 min version).

However, if you download the build from AdoptOpenJDK, and do the same thing, you’ll find

$ otool -l  */libjvm.dylib | grep VERSION -A 5 | grep version
  version 10.8
  version 0.0

Just another reason to use AdoptOpenJDK for your Java distro.

Use NPM to Distribute Your Command-Line Java Apps

jDeploy flow

From time to time, I need to develop and distribute a command-line application to my customers, and I prefer to write these apps in Java. But I’ve been frustrated by the Java eco-system’s lack of good distribution options for this type of app. I look at tools like Cordova and Ionic that provide a neat “single-line” installation instructions and wonder why I can’t achieve the same thing with Java.

My general solution up until now has been to zip up the executable Jar with its dependencies, and post it for my users to download. The installation instructions then become something like:

  1. Download myapp.zip
  2. Extract it
  3. Then run the app using something like “java -jar /path/to/myapp/myapp.jar”

Sometimes I go as far as writing shell script launch scripts that people can add to their PATH, but this adds an additional installation step…. we were already at 3 possible places for users to get stuck.

Compare this to the installation instructions for Cordova:

  1. Open a command prompt and type “npm install -g cordova”. No need to download anything manually. Just one command
  2. Once installed, you can just run “cordova”, you don’t need to know where it was installed. A symlink is automatically installed in your environment PATH.

That is the type of user experience I want for my command-line apps. Java offers some great package management options for distributing libraries (e.g. Maven and Gradle), but these don’t offer a simple way to distribute applications. Wouldn’t it be nice if we had a way to distribute command-line apps the same way?

NPM to the Rescue

The examples I provided above (Cordova and Ionic) both use NPM as their distribution mechanism. That is what allows them to provide such a smooth process. If you’re not familiar with NPM, it is the package manager that is bundled with NodeJS. Unlike Maven, which is constrained to use in the Java ecosystem (you can only distribute .war, .jar, and pom files), NPM allows you to distribute all manner of files, so why not use it to distribute Java apps. Sounds crazy, I know. But let’s look at some of the features of NPM that make it ideal for distributing Java applications:

  1. WORA – NPM is cross platform, and is automatically installed when users install NodeJS on their system. NodeJS provides a simple double-clickable installer for Mac, Windows, and Linux, so your application can easily be installed on all major platforms.
  2. Pain-free Publishing – Publishing an app to NPM is as simple as npm publish. If you don’t yet have an account on NPM, it’s as simple as npm login. Literally could take you under a minute to get set up and rolling.
  3. Adds to PATH – NPM will automatically add symlinks for your application to the environment path when installed globally. On windows it automatically generates a .cmd script to launch the app. That is the magic that allows apps like Cordova to provide single-line installation instructions.

In addition to all this, NPM provides automatic versioning and updates so that it is easy for you to push updates out to your users. This is a big deal.

But How Do I Deploy my Java App using NPM

You say: This is all fine and well, but how do I leverage NPM to deliver my Java application. NPM is designed to distribute apps written in Javascript, not Java.

I respond: Let me introduce you to jDeploy

jDeploy is a tool that allows you to publish your Java applications on NPM so that users can install it directly using a simple command like

npm install -g your-app

It will take an executable Jar file and bundle it in a node module with all of its dependencies, and publish it to NPM. The resulting app doesn’t even require that the users have Java installed, as it will automatically install a JRE if it detects that Java isn’t installed.

Example

Installing jDeploy

$ npm install -g jdeploy

Publishing an App to NPM

Suppose you have an app in an executable jar file, “myapp.jar”. Place this in a directory on its own, and open a command prompt in this directory, and type:

jdeploy init

This will generate a package.json file for your app that is ready and configured to publish on NPM. You may want to edit this package.json slightly to suit your purposes. The default will look something like:

{
  "bin": {"myapp": "jdeploy-bundle/jdeploy.js"},
  "preferGlobal": true,
  "version": "1.0.1",
  "jdeploy": {"jar": "myapp.jar"},
  "dependencies": {"shelljs": "^0.7.5"},
  "license": "ISC",
  "name": "myapp",
  "files": ["jdeploy-bundle"] 
}

The “myapp” key in the “bin” property is the command name for your app. This is the name of the command that users will run on the command-line to use your app. Change this to something else if you want the command to be different.

The “name” property should be globally unique. This is the identifier that will be used to install your app from NPM. E.g. npm install -g myapp. You may need to change this if the name is already taken by someone else.

Once you’re happy with the settings, you can test out the app locally to make sure it runs.

$ jdeploy install

This should install your command locally so you can try it out:

$ myapp

And your app should run.

Once you’re satisfied that your app works the way you like, you can run

$ jdeploy publish

Installing Your App

Now that your app is published, people can immediately install your app from anywhere in the world, on any computer that runs NPM with a single command:

$ npm install -g myapp

NOTE: On Mac/Linux you will need to use sudo to install the app. Windows should work as long as you are using an administrator account.

Screencast

Introduction to jDeploy Screencast

Async to Better U/X

I come to you today with three simple tips that will guarantee to improve your Codename One apps’ usability:

  1. Don’t block the EDT
  2. If you must block the EDT, do it when the user won’t notice
  3. Prefer asynchronous coding patterns (e.g. using callbacks) to synchronous coding patterns (e.g. *AndWait(), and *AndBlock() methods).

The first one is GUI 101. All of the UI is drawn on the EDT (Event dispatch thread). If you are performing a slow operation on the EDT, the user will probably notice a lag or a jerk in the UI because drawing can’t take place while your slow operation is occupying the thread.

Here’s a quick example. I have a form that allows the user to swipe through 12 images, which are loaded from the classpath (getResourceAsStream()). My first attempt at this is to load all of the images into Labels inside the Form’s constructor as follows:

public class MyForm extends Form {
    private Tabs tabs;

    public MyForm() {
        super("Welcome to My App");

        tabs = new Tabs();

        tabs.hideTabs();

        setScrollable(false);
        Container buttonsContentWrapper = new Container(new BorderLayout());
        try {
            for (int i=1; i< =12; i++) {
                int w = calculateTheWidth();
                int h = calculateTheHeight();
                Button l = new Button(
                        Image.createImage(
                                Display.getInstance().getResourceAsStream(null, "/Instructions"+fi+".png")
                        ).scaledSmallerRatio(w, h)
                );

                l.setUIID("Label");
                if (i>1) {
                    l.setUIID("InstructionImage");
                }
                l.addActionListener(e->{
                    buttonsContentWrapper.setVisible(!buttonsContentWrapper.isVisible());
                    revalidate();
                });
                Container tabWrapper = FlowLayout.encloseCenter(l);
                tabWrapper.getAllStyles().setPaddingTop(Display.getInstance().convertToPixels(2));
                if (i==12) {
                    tabWrapper.putClientProperty("lastSlide", Boolean.TRUE);
                } else {
                    tabWrapper.putClientProperty("lastSlide", Boolean.FALSE);
                }
                tabs.addTab(i+"", tabWrapper);
            }
        } catch (Exception ex) {
            Log.e(ex);
        }
        Container mainContent = new Container(new BorderLayout());
        mainContent.addComponent(BorderLayout.CENTER, tabs);
        setLayout(new LayeredLayout());
        addComponent(mainContent);

        buttonsContentWrapper.setVisible(false);
        Button skipButton = new Button("Skip");

        skipButton.addActionListener(e->{
            MyApp.getInstance().getMainForm().show();
        });

        Container buttonsContent = FlowLayout.encloseRight(skipButton);
        buttonsContentWrapper.addComponent(BorderLayout.SOUTH, buttonsContent);
        addComponent(buttonsContentWrapper);
    }
}

So what’s the problem with this code? Loading the 12 images inside the constructor of this form takes too long. If I have code like:

MyForm form = new MyForm();
form.show();

There is a lag of 1 or 2 seconds in the new MyForm() line — before the form is even shown. This feels really bad to the user.

We can improve on this by employing the 2nd tip above:

If you must block the EDT (hey we need to load the images sometime right?), then do it when the user won’t notice

Rather than loading all of the images directly inside the MyForm constructor, we can load each one inside its own Display.callSerially() dispatch, as shown below:

public class MyForm extends Form {
    private Tabs tabs;

    public MyForm() {
        //...
        try {
            for (int i=1; i< =12; i++) {
                //...
                final Button l = new Button();
                Display.getInstance().callSerially(()->{
                    try {
                        l.setIcon(
                            Image.createImage(
                                    Display.getInstance().getResourceAsStream(null, "/Instructions"+fi+".png")
                            ).scaledSmallerRatio(fw, fh)
                        );
                        l.getParent().revalidate();
                     } catch (Exception ex){
                        Log.e(ex);
                    }
                });
                //...

            }
        } catch (Exception ex) {
            Log.e(ex);
        }
        //...

    }
}

This will still load the images on the EDT, but it will do them one by one, and in a future event dispatch, so that the code won’t block at all in the constructor. If you run this code, you’ll notice that the 1 to 2 second lag before showing the form is gone. However, the form transition may contain a few “jerks” because it is still interleaving the loading of the images while drawing frames.

So this is an improvement, but still not a good user experience. Luckily we can go back to tip #1, “Don’t block the EDT”, when we realize that we didn’t have to block the EDT at all. We can load the images on a background thread, and then apply them as icons to the labels when they are finished loading, as shown below:

public class MyForm extends Form {
    private Tabs tabs;

    public MyForm() {
        // ...
        try {
            for (int i=1; i< =12; i++) {
                // ...
                final Button l = new Button();
                Display.getInstance().scheduleBackgroundTask(()->{
                    try {
                        Image im = Image.createImage(
                                Display.getInstance().getResourceAsStream(null, "/Instructions"+fi+".png")
                        ).scaledSmallerRatio(fw, fh);
                        if (im != null) {
                            Display.getInstance().callSerially(()->{
                                l.setIcon(im);

                                l.getParent().revalidate();
                            });
                        }
                    } catch (Exception ex){
                        Log.e(ex);
                    }
                });
                //...
            }
        } catch (Exception ex) {
            Log.e(ex);
        }
        //...

    }
}

This has double nesting. The first nest (inside scheduleBackgroundTask()) downloads the icon on a background thread. Then the second nesting using callSerially(), assigns the image as the label’s icon back on the EDT. This was necessary because we can’t access the label from the background thread. That part must occur on the EDT. But that part is non-intensive and very fast to perform.

So the result is a very fluid user experience with no lags and no jerks.

Prefer Async to Sync

I’ll address the preference of Async to Sync separately. The example above is a sort of example of this since the nested calls to scheduleBackgroundTask() and callSerially() are technically “callbacks”. However, with this tip I’m more specifically targeting methods like invokeAndBlock(), addToQueueAndWait(), and other *AndWait() methods. At their core, all of these methods are built upon invokeAndBlock() so I’ll target that one specifically here – and the wisdom gleaned will also apply to all AndWait() methods.

First of all, if you aren’t familiar with invokeAndBlock, it is a marvelous invention that allows you to “block” the EDT without actually blocking the EDT. It will indeed block the current dispatch event, but while it is blocked, it will start processing the rest of the events in the EDT queue. That way your app won’t lock up while your code is blocked. This strategy is used for modal dialogs to great effect. You can effectively show a dialog, and the “next” line of code isn’t executed until the user closes the dialog – but the UI itself doesn’t lock up.

invokeAndBlock() is the infrastructure that allows you to do synchronous network requests on the EDT (e.g. NetworkManager.getInstance().addToQueueAndWait(conn)). Since this pattern is so convenient (it allows you to think serially about your workflow – which is much easier), it is used in all kinds of places where it really shouldn’t be.

So why NOT use invokeAndBlock

Because it will ALMOST always result in a worse user experience. I’ll illustrate that with a scenario that would seem, at first, to be a good case for invokeAndBlock (addToQueueAndWait()).

Here is a form that allows a user to update his bio. Somehow the form needs to be populated with the user’s existing profile data, which is exists on a network server. The question is when and how do we load this data from the server.

A first attempt might populate the data inside the form’s constructor using AddToQueueAndWait() (or some method that encapsulates this). That might look like this:

public class MyForm extends Form {

    public MyForm() {
         ConnectionRequest req = createConnectionRequest();
         NetworkManager.getInstance().addToQueueAndWait(req);
         setupFormComponents();
         populateFormData();
    }
}

The problem with this is similar to our first example loading images from the classpath. Execution will stall inside the constructor for our form while the data is loaded. So the user will have to wait to show the form. A common technique to mitigate this UX blunder is to display an infinite progress indicator so the user knows that something is happening. That’s better, but it still makes the app feel slow.

If we want the user to be able to see the form immediately, then either we need to have loaded the data before-hand, or we need to show the form, and populate it later. We could also use a combination (e.g. show the form with data we loaded before, then update it once we have the new data.

Loading data before hand, exclusively, is not realistic. There must exist a point after which we deem the data is too old and we need to reload it. And we are back at needing to load data when the form loads.

If we want to solve this problem, and still use addToQueueAndWait(), we either need to wrap addToQueueAndWait() inside a callSerially() dispatch so that it doesn’t block inside the constructor – and delay our show() method; or we need to move the call somewhere else, after the form is already shown. Although that isn’t ideal either, because we’d like to have the data as soon as possible – so the longer we delay the “sending” of the network request, the longer the user has to wait for the result.

Now, our handy tool (invokeAndBlock) that was supposed to reduce our app’s complexity, is actually making it more complex. Wrapping it inside callSerially() in the constructor means that we are now combining an async callback with sync blocking code. We might as well, at that point, just use addToQueue(), and use a result listener to process the response without blocking the EDT at all, as shown in the example below:

public class MyForm extends Form {

    public MyForm() {
         ConnectionRequest req = createConnectionRequest();
         req.addResponseListener(e->{
             populateFormDataWithResponse(req);
         });
         NetworkManager.getInstance().addToQueue(req);
         setupFormComponents();
    }
}

This predicament is the reason not to use invokeAndBlock (addtoQueueAndWait()). It isn’t that they are evil, or they can’t be made to work. It is because, if you aim to achieve an optimal user experience, it will get in the way more than it will help.

Does this mean that you should never use invokeAndBlock() or addToQueueAndWait()? No. There are valid cases for both of these. E.g. addToQueueAndWait() can be used from a background thread (off the EDT), in which case it isn’t even using invokeAndBlock. It is just plain-old blocking that background thread, which is perfectly OK because it’s not the EDT. In addition, there may be cases where you DO want to block the flow of the application without locking up the UI. Modal dialogs is the flag-ship use-case for this. I struggle to think of another suitable scenario though.

Entitled OSS Users and the Xamarin RoboVM acquisition

RoboVM has been acquired by Xamarin, it was announced; and it would no longer be open source.

Wow.

It only took five minutes for the forum posts and reddit threads to start up condemning the move as some sort of robbery. The RoboVM was accused of luring unsuspecting users into its community on the promise of open source, only to pull a switcheroo and sell out to big business. Some users were demanding the RoboVM team continue to share their work for free, because … that would only be fair.

RoboVM, on the other hand, explained that they had been open source for a few years and had received little to no contributions from the community, so there wasn’t much incentive to continue with that approach. My personal experience with managing open source projects is consistent with theirs. I released the first version of Xataface in 2005. In that time it has hundreds of thousands of downloads, and is still used in many enterprises as the back-bone of their web information systems (I don’t have an exact count since most apps built with Xataface are internal). In that time, I can count the number of community contributions on my fingers and toes. I’m thankful to all of the users who did contribute. But let’s be real, the case for open sourcing a project because the community will contribute is not compelling.

Shut up and Fork it!

No, really. The source (albeit a couple of months out of date) is still on GitHub and it is licensed under the GPL. That repository represents countless hours of high-quality work by incredibly skilled individuals. That is one hell of a contribution to the open source community. Let them move on; And if you want your open source RoboVM, you can build on this fantastic source base.

Personally, I think it is highly likely that the last open source version of RoboVM will continue to circulate for a long time to come. At least in its core as an AOT java VM, it should be maintainable by people on the outside because most of the heavy lifting is already done there. It is the value-added components like the iOS API bindings, and tool support, that will be difficult for the community to maintain going forward. These things are evolving too fast for volunteers to keep up with.

Dependent Tools

If you are an iOS developer who just uses RoboVM to build iOS apps in Java, then the move to close the source probably won’t affect you – except that your costs may be going up some. I wonder more about the impact that this has on other developer tools that have made RoboVM an integral part of their tool chain. I’m thinking about companies like Gluon that provides JavaFX support for iOS and Android. They use RoboVM for their iOS builds. DukeScript, which allows you to write Java apps with an HTML5 UI and deploy to iOS (and other platforms), also uses RoboVM for its iOS builds. How will they respond.

I had argued as recently as 6 months ago that we (at Codename One) should incorporate RoboVM into our toolchain rather than maintain our own Java VM. But we ultimately decided that there was too much risk in that approach because “what if RoboVM closes down, or goes closed source”. 20/20 hindsight shows that we made the right choice and our new iOS VM is now quite mature, performant, and robust. But most importantly we are not dependent upon other external factors for maintaining it.

What Open Source VMs are Left for iOS?

RoboVM wasn’t the only open source VM for iOS. It was just the most active, and provided the best and most comprehensive bindings to the iOS native APIs. But there are alternative VMs that the open source community may turn to for their supply chain. For example:

  1. Codename One (proper) – (Full disclosure, I work for Codename One)… Codename One is open source and provides a full cross-platform Java solution for write once run anywhere.
  2. Codename One’s VM – Codename One has developed its own Java VM for iOS that works as a cross-compiler from Java to C. This is open source and is a good option for Java tools that need a path to iOS.
  3. Avian – Avian is an AOT Java compiler that can be used to compile java directly to iOS binaries. It is written in C++, and has a very permissive license.
  4. XMLVM. This project has been discontinued. But I mention it for completeness in case people want to revive it.
  5. OpenJDK for iOS. It has been approved for an iOS port of the Open JDK to be developed. This may also present a long-term option, but this is still only in the planning stage.
  6. J2ObjC – A transpiler that converts Java source code into Objective-C source code.
  7. JUniversal – Java source transpiler to C# and C++ that includes a runtime library to help with portability.

iOS Certificate Wizard

I don’t know about you, but I cringe every time I need to deploy apps to iOS. There is always something with the certificates or provisioning profiles that requires tinkering. No more, I say!

This is a sneak peak of a new certificate wizard I developed for Codename One. It reduces the problem of generating certificates and provisioning profile down to a few clicks. Watch for this to be included in the Codename One plugin as soon as next week.

JavaFX WebView HTML5 API Support

javafxscore

I played with the JavaFX web view recently. The idea was to embed an HTML5 application that I had built into a plugin that we could embed inside the a Java-based IDE like NetBeans, Eclipse, or IntelliJ. The application ran fine inside the major browsers so, in theory, it should run fine inside the JavaFX web view, since it is based on WebKit. Of course, I expected a few hiccups along the way — it wouldn’t just work. Unfortunately, rather than hiccups , I hit road blocks.

My initial attempts to load the app resulted in a blank screen with no error messages reported. The first troubleshooting step, of course, was to attach error listeners to the web view. I found the API to a little bit opaque on exactly how best to log errors, but it wasn’t hard to find forum threads like this StackOverflow post that provided tips.

Unfortunately, after installing logging to just about every part of the web view, I still ended up with a blank white screen with no errors.

I was determined to get this working so I installed Firebug Lite, as described in this thread. This gave me the ability to probe the DOM at runtime more easily to see “where things were at”. I poked around for quite a while but didn’t get very far.

My next thought was that I must have been relying on some APIs that weren’t supported in the version of WebKit that shipped with JavaFX. At this point, I wasn’t even sure which Javascript engine was being used. Were they somehow using Nashorn for the Javascript Engine? Or were they using V8 or something else? It turns out that the WebView just uses the default Javascript Engine that shipped with WebKit (Javascript Core). Since the webview was proving so difficult to debug, I decided to download the same version of WebKit that was being used in JavaFX. I retrieved the version from “User Agent” string – it was 537.44.

Unfortunately, the app worked fine in that version of WebKit.

Fast forward 3 or 4 hours after banging my head against FireBug, WebKit and JavaFX, I decided to see exactly which APIs were supported in the WebView to see if something was missing.

I don’t know why I didn’t try this at the beginning. Next time I will do this at the beginning.

This information isn’t published anywhere that I could find so I loaded up html5test.com – one of those web sites that tells you information about your browser. And the result was this.

Check out that link if you want to see exactly which APIs are supported. Some highlights:

  • Score: 318 out 555
  • No file or file system APIs.
  • No IndexedDB or WebSQL.
  • No WebGL
  • No request.getAnimationFrame

I still don’t exactly know what the problem was with my app. It is a pretty complex app that uses a lot of APIs. Likely it was making a callback that never returns… or something like that.

I ultimately opted for a different solution that still met the requirements.

The nice thing about Javascript is that it is so dynamic, so missing APIs can be overcome with polyfills. JavaFX’s ability to talk back and forth between Java and Javascript offers even more flexibility. Perhaps, if I get the time and motivation, I’ll start a project for implementing polyfills for the JavaFX web view to bring in some of these missing APIs.