Native Installers with DukeScript

This Tutorial was contributed by Ruslan López Carro, a Software Development professional at UNICOM, and a very active and valued member of the DukeScript community. Here’s a link to his original blog post:

For this tutorial we’ll create a Java powered native desktop app with HTML GUI using netbeans and my Windows 10 computer in less than 30 minutes using the Dukescript sample code.

We’ll create the native app with Dukescript in record time. Dukescript is a client side technology based in Java and mainly on JavaFx to provide a backend with Java and a frontend with HTML5.

You should have Inno and Wix Toolset to create the app and the installer directly from maven pom file.

To install Inno Setup:

  1. Download ispack-5.5.3.exe from the Inno Setup Downloads page.
  2. Double-click the file to launch the installer.
  3. Accept the Inno Setup license agreement and click Next.
  4. Follow the instructions in the install wizard for installing Inno Setup.

To install WiX:

  1. Download wix37.exe from the WiX Toolset – Download page.
  2. Double-click the file to launch the installer.
  3. Follow the instructions in the install wizard for installing WiX.

You need to install the “Dukescript project wizzard” plugin and then

Add Inno Setup and/or WiX to the system Path variable:

  1. On Windows 7, select Start > Computer > System Properties > Advanced system settings.
  2. Select the Advanced tab and click the Environment Variables button.
  3. In the System Variables pane, double-click the Path variable.
  4. In the Edit System Variable dialog box, add a semicolon followed by a new path to the Variable value field (for example, C:\Program Files (x86)\Inno Setup 5 or C:\Program Files (x86)\WiX Toolset v3.6\bin).
  5. Click OK to close all the open dialog boxes.

Dukescript App Native Packaging

Create a new dukescript application from new project wizzard and use the sample hello world project with knockout:

new dukescript project

Name it nativeds:

new dukescript project

No platforms selected, so only javafx version will be available. It will generate three projects, the general project, the javafx project and the javascript libraries project.

dukescript project in NetBeans

Add a plugin to maven’s pom file generated at http://javafx-maven-plugin.github.io/

maven plugin tag:

<plugin>
    <groupId>com.zenjava</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <version>8.1.4</version>
    <configuration>
        <mainClass>org.javapro.nativeds.Main</mainClass>
        <verbose>true</verbose>
        <vendor>javapro.org</vendor>
        <nativeReleaseVersion>0.1</nativeReleaseVersion>
        <additionalAppResources>${project.basedir}/src/main/webapp</additionalAppResources>
    </configuration>
    <executions>
        <execution>
            <!-- required before build-native -->
            <id>create-jfxjar</id>
            <phase>package</phase>
            <goals>
                <goal>build-jar</goal>
            </goals>
        </execution>
        <execution>
            <id>create-native</id>
            <phase>package</phase>
            <goals>
                <goal>build-native</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The final result will look like this:

The final native app

Full client project’s POM

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.javapro</groupId>
        <artifactId>nativeds-pom</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>org.javapro</groupId>
    <artifactId>nativeds</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>bundle</packaging>

    <name>nativeds General Client Code</name>

    <properties>
        <netbeans.compile.on.save>all</netbeans.compile.on.save>
        <project.mainclass>org.javapro.nativeds.Main</project.mainclass>
        <exec.java.bin>${java.home}/bin/java</exec.java.bin>
        <exec.debug.arg>-Ddebug=false</exec.debug.arg>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.4.0</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Export-Package>org.javapro.nativeds</Export-Package>
                        <Bundle-SymbolicName>org.javapro.nativeds</Bundle-SymbolicName>
                    </instructions>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version>
                <configuration>
                    <junitArtifactName>com.dukescript.api:junit-osgi</junitArtifactName>
                    <systemPropertyVariables>
                        <fxpresenter.headless>true</fxpresenter.headless>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>${project.mainclass}</mainClass>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <useUniqueVersions>false</useUniqueVersions>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.2.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <executable>${exec.java.bin}</executable>
                    <classpathScope>test</classpathScope>
                    <arguments>
                        <argument>-classpath</argument>
                        <classpath/>
                        <argument>-javaagent:${project.build.directory}/springloaded.jar</argument>
                        <argument>-noverify</argument>
                        <argument>-Dbrowser.rootdir=${basedir}/src/main/webapp/</argument>
                        <argument>-Dnetbeans.inspect.port=${netbeans.inspect.port}</argument>
                        <argument>${exec.debug.arg}</argument>
                        <argument>${project.mainclass}</argument>
                    </arguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>org.springframework</groupId>
                                    <artifactId>springloaded</artifactId>
                                    <version>1.2.3.RELEASE</version>
                                    <type>jar</type>
                                    <overWrite>false</overWrite>
                                    <destFileName>springloaded.jar</destFileName>
                                </artifactItem>
                            </artifactItems>
                            <outputDirectory>${project.build.directory}</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>web-pages</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <descriptors>
                                <descriptor>src/main/assembly/webpages.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.netbeans.html</groupId>
            <artifactId>net.java.html</artifactId>
            <version>${net.java.html.version}</version>
        </dependency>
        <dependency>
            <groupId>org.netbeans.html</groupId>
            <artifactId>net.java.html.json</artifactId>
            <version>${net.java.html.version}</version>
        </dependency>
        <dependency>
            <groupId>org.netbeans.html</groupId>
            <artifactId>net.java.html.boot</artifactId>
            <version>${net.java.html.version}</version>
        </dependency>
        <dependency>
            <groupId>org.netbeans.html</groupId>
            <artifactId>net.java.html.sound</artifactId>
            <version>${net.java.html.version}</version>
        </dependency>
        <dependency>
            <groupId>org.netbeans.html</groupId>
            <artifactId>ko4j</artifactId>
            <version>${net.java.html.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.javapro</groupId>
            <artifactId>nativeds-js</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.netbeans.html</groupId>
            <artifactId>net.java.html.boot.fx</artifactId>
            <version>${net.java.html.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.dukescript.api</groupId>
            <artifactId>junit-osgi</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.dukescript.api</groupId>
            <artifactId>junit-browser-runner</artifactId>
            <version>${junit.browser.version}</version>
            <scope>test</scope>
            <type>jar</type>
        </dependency>

        <!-- Nashorn presenter for BrowserRunner
        <dependency>
          <groupId>org.netbeans.html</groupId>
          <artifactId>net.java.html.boot.script</artifactId>
          <version>${net.java.html.version}</version>
          <scope>test</scope>
          <type>jar</type>
        </dependency>
        -->
    </dependencies>
    <profiles>
        <profile>
            <id>desktop</id>
            <dependencies>
                <dependency>
                    <groupId>org.netbeans.html</groupId>
                    <artifactId>net.java.html.boot.fx</artifactId>
                    <version>${net.java.html.version}</version>
                    <scope>runtime</scope>
                </dependency>
            </dependencies>
            <build>
                <plugins>
                    <plugin>
                        <artifactId>maven-assembly-plugin</artifactId>
                        <version>2.4</version>
                        <executions>
                            <execution>
                                <id>distro-assembly</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>single</goal>
                                </goals>
                                <configuration>
                                    <descriptors>
                                        <descriptor>src/main/assembly/javafx.xml</descriptor>
                                    </descriptors>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>com.zenjava</groupId>
                        <artifactId>javafx-maven-plugin</artifactId>
                        <version>8.1.4</version>
                        <configuration>
                            <mainClass>org.javapro.nativeds.Main</mainClass>
                            <verbose>true</verbose>
                            <vendor>javapro.org</vendor>
                            <nativeReleaseVersion>0.1</nativeReleaseVersion>
                            <additionalAppResources>${project.basedir}/src/main/webapp</additionalAppResources>
                        </configuration>
                        <executions>
                            <execution>
                                <!-- required before build-native -->
                                <id>create-jfxjar</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>build-jar</goal>
                                </goals>
                            </execution>
                            <execution>
                                <id>create-native</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>build-native</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Congratulations! If you reached this far it means that now you can create a native app with Dukescript technology.

Thanks to Ruslan for this great tutorial!