Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bundle Java program for Mac users with maven from GNU/Linux

Tags:

java

macos

maven

I am trying to bundle a java program for Mac users. I first found this article that explains how to do it with Ant, and then, I found this that seems perfect for Maven.

So I added to my pom:

<plugin>
    <groupId>sh.tak.appbundler</groupId>
    <artifactId>appbundle-maven-plugin</artifactId>
    <version>1.1.0</version>
    <configuration>
        <mainClass>xxx</mainClass>
        <iconFile>xxx</iconFile>
        <jrePath>???</jrePath>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>bundle</goal>
            </goals>
        </execution>
    </executions>
</plugin>

(I also found this article that explains some details about Mac bundles and why to use appbundler)

The only issue is that on every example I found, I see <jrePath>xxx.jdk</jrePath>. But I am running this under Ubuntu, so I only have the GNU/Linux jdk. Where can I find the Mac jdk ? On the oracle website, I can only find the dmg file. I extracted the dmg and got an hfs. I mounted the hfs and got a pkg. I extracted the pkg, and have now more file I don't know what to do with...

like image 259
Sharcoux Avatar asked Aug 28 '16 17:08

Sharcoux


1 Answers

Here are step by step what I did to do it with a test project on Ubuntu 16.04.1 LTS.

In your case steps 1 to 3 will be done on your GNU/Linux env and the last one on Mac OS X.

1. Download the JRE

As you only need the JRE, the easiest thing to do is:

  1. To go to the download area,
  2. Click on JRE DOWNLOAD,
  3. Choose the tar.gz version of the JRE for Mac OS X which is currently jre-8u112-macosx-x64.tar.gz.
  4. Untar the content of the archive in the folder of your choice that we will call ${jre-folder} (for example /foo/bar/jre1.8.0_112.jre).

2. Create my test project

My typical maven project structure:

TestProject
└── src
|   └── main
|       └── java
|           └── my
|               └── pkg
|                   └── MyClass.java
└── pom.xml

My class my.pkg.MyClass which actually does an arbitrary task. Here, it simply dumps the system properties into a temporary file, just to be able to easily check that it has been called:

package my.pkg;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class MyClass {
    public static void main(String[] args) throws IOException {
        Path path = Files.createTempFile("MyClass", "txt");
        try (BufferedWriter writer = Files.newBufferedWriter(path)) {
            System.getProperties()
                .entrySet()
                .stream()
                .forEach(
                    entry -> {
                        try {
                            writer.write(entry.getKey() + "=" + entry.getValue() + "\n");
                        } catch (IOException e) {
                            throw new IllegalStateException(e);
                        }
                    }
                );
        }
    }
}

My pom file:

<?xml version="1.0" encoding="UTF-8"?>
<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>

    <groupId>TestProject</groupId>
    <artifactId>TestProject</artifactId>
    <version>0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>sh.tak.appbundler</groupId>
                <artifactId>appbundle-maven-plugin</artifactId>
                <version>1.1.0</version>
                <configuration>
                    <mainClass>my.pkg.MyClass</mainClass>
                    <!--
                       For example
                    <jrePath>/foo/bar/jre1.8.0_112.jre</jrePath>
                    -->
                    <jrePath>${jre-folder}</jrePath>
                    <generateDiskImageFile>true</generateDiskImageFile>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>bundle</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

3. Build my test project

Simply launch the command mvn package appbundle:bundle from the root of the directory TestProject.

This will build the dmg file in the target folder with the JRE for Mac OS X included, in this particular case it will be called TestProject-0.1-SNAPSHOT.dmg.

4. Test my test project

On the target Mac OS X:

  1. Double click on the dmg file, it will automatically mount the image,
  2. Then you will be able to double click on TestProject.app, you will see an icon appear and quickly disappear as the test program is rather short
  3. You can check that it worked properly by launching cat $TMPDIR/MyClass* from a terminal, you will then see the content of the temporary file that has been created by the test application.

5. Add resources to the dmg file

To add resources to the generated dmg file, you can use additionalResources with a fileSet.

<plugin>
    <groupId>sh.tak.appbundler</groupId>
    <artifactId>appbundle-maven-plugin</artifactId>
    <version>1.1.0</version>
    <configuration>
        ...
        <additionalResources>
            <fileSet>
                <directory>/path/to/my/resources/folder</directory>
                <includes>
                    <include>*.pdf</include>
                </includes>
            </fileSet>
        </additionalResources>
    </configuration>
    ...
</plugin>

This example will add all the pdf files from /path/to/my/resources/folder into the generated dmg file.

6. Add resources to the app file

To add resources to the generated app file, you can use additionalResources with a fileSet.

<plugin>
    <groupId>sh.tak.appbundler</groupId>
    <artifactId>appbundle-maven-plugin</artifactId>
    <version>1.1.0</version>
    <configuration>
        ...
        <additionalBundledClasspathResources>
            <fileSet>
                <directory>/path/to/my/resources/folder</directory>
                <includes>
                    <include>*.pdf</include>
                </includes>
            </fileSet>
        </additionalBundledClasspathResources>
    </configuration>
    ...
</plugin>

This example will add all the pdf files from /path/to/my/resources/folder to the generated app file into /Contents/Java/lib, they will be automatically included to the classpath of your application such that you will be able to access them easily.

like image 68
Nicolas Filotto Avatar answered Oct 20 '22 00:10

Nicolas Filotto