Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

de.perdian.maven.plugins:macosappbundler-maven-plugin

Package Overview
Dependencies
Maintainers
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

de.perdian.maven.plugins:macosappbundler-maven-plugin

Maven plugin to create a macOS application bundle

  • 1.21.1
  • Source
  • Maven
  • Socket score

Version published
Maintainers
2
Source

macOS app bundler Maven plugin

Maven plugin for creating a native macOS bundle containing all dependencies declared by a Maven project.

Maven Central License Build

Requirements

  • Java 9 or newer

Usage

Minimum example

...
    <plugin>
        <groupId>de.perdian.maven.plugins</groupId>
        <artifactId>macosappbundler-maven-plugin</artifactId>
        <version>1.21.0</version>
        <configuration>
            <plist>
                <JVMMainClassName>de.perdian.test.YourApplication</JVMMainClassName>
            </plist>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>bundle</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
...

Extended example

...
    <plugin>
        <groupId>de.perdian.maven.plugins</groupId>
        <artifactId>macosappbundler-maven-plugin</artifactId>
        <version>1.21.0</version>
        <configuration>
            <plist>
                <CFBundleIconFile>src/bundle/test.icns</CFBundleIconFile>
                <CFBundleDisplayName>My supercool application</CFBundleDisplayName>
                <CFBundleDevelopmentRegion>English</CFBundleDevelopmentRegion>
                <CFBundleURLTypes>
                    <string>msa</string>
                </CFBundleURLTypes>
                <JVMMainClassName>de.perdian.test.YourApplication</JVMMainClassName>
                <JVMVersion>11+</JVMVersion>
                <JVMOptions>
                    <string>-Dfoo=bar</string>
                    <string>-Dx=y</string>
                </JVMOptions>
                <JVMArguments>
                    <string>-example</string>
                    <string>${someProperty}</string>
                </JVMArguments>
            </plist>
            <dmg>
                <generate>true</generate>
                <additionalResources>
                    <additionalResource>
                        <directory>src/bundle/macos/distribution</directory>
                    </additionalResource>
                </additionalResources>
            </dmg>
            <codesign>
                <identity>3rd Party Mac Developer Application: MyName (MyNumber)</identity>
            </codesign>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>bundle</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
...

Example with Java Module Path

...
    <plugin>
        <groupId>de.perdian.maven.plugins</groupId>
        <artifactId>macosappbundler-maven-plugin</artifactId>
        <version>1.21.0</version>
        <configuration>
            <plist>
                <CFBundleIconFile>src/bundle/test.icns</CFBundleIconFile>
                <CFBundleDisplayName>My supercool application</CFBundleDisplayName>
                <CFBundleDevelopmentRegion>English</CFBundleDevelopmentRegion>
                <CFBundleURLTypes>
                    <string>msa</string>
                </CFBundleURLTypes>
                <JVMMainModuleName>de.perdian.somemodule/de.perdian.test.YourApplication</JVMMainModuleName>
                <JVMVersion>11+</JVMVersion>
                <JVMOptions>
                    <string>-Dfoo=bar</string>
                    <string>-Dx=y</string>
                </JVMOptions>
                <JVMArguments>
                    <string>-example</string>
                    <string>${someProperty}</string>
                </JVMArguments>
            </plist>
            <dmg>
                <generate>true</generate>
                <additionalResources>
                    <additionalResource>
                        <directory>src/bundle/macos/distribution</directory>
                    </additionalResource>
                </additionalResources>
            </dmg>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>bundle</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
...

Features

After executing the goal during (e.g. during the package phase as shown in the example above) the macOS application bundle will be located in the PROJECT_NAME.app directory inside the target directory, where PROJECT_NAME equals the bundle name entered within the CFBundleName setting inside the plist configuration, or the name of the Maven project (${project.name}) if the value is not present inside the plist configuration.

The plugin will detect whether the project is a Java module by checking if the plist property JVMMainModuleName is present. If that's the case the launcher will use the modulepath. Otherwise the regular classpath will be used.

Configuration

Property list Configuration

The values within the plist element are directly transferred to the Info.plist file within the application bundle. To keep the usage within the code consistent they use the same keys within the pom.xml configuration as they do within the Info.plist.

The following values can be configured:

KeyTypeRequired?DefaultDescription
CFBundleDevelopmentRegionStringNoEnglishThe default language and region for the bundle, as a language ID.
CFBundleDisplayNameStringNo${project.name}The published name of your application.
CFBundleExecutableStringNoJavaLauncherThe name of the executable within the application bundle. No regular user will ever see this but you may want to change it for debugging purposes when analyzing your application.
CFBundleIconFileFileNoThe icns file that should be used as main icon for the application. The location must be entered relatively to the root of the project in which the plugin is used.
CFBundleIdentifierStringNo${groupId}.${artifactId}The macOS bundle identifier of your application.
CFBundleNameStringNo${project.name}The internal name of your application.
CFBundlePackageTypeStringNoAPPLA four-letter code specifying the bundle type. For apps, the code is APPL, for frameworks, it' FMWK, and for bundles, it's BNDL (Details)
CFBundleShortVersionStringStringNo${version}The version of your application.
CFBundleDocumentTypesArray of CFBundleDocumentTypesNoAdditional information for document types (see details for an extended example).
CFBundleURLTypesArray of StringsNoA list of URL schemes (http, ftp, etc.) supported by the application.
JVMArgumentsArray of StringsNoAdditional arguments to be passed to the Java runtime.
JVMLogLevelStringNoINFOThe amount of details the launcher will print to the console if called directly from the command line. Possible values: TRACE, DEBUG, INFO, WARN, ERROR.
JVMMainClassNameStringYes (if the application is a classic classpath based application)The main class whose main method should be invoked when starting your application.
JVMMainModuleNameStringYes (if the application is a module based application)The main module that should be invoked when starting your application.
JVMOptionsArray of StringsNoAdditional parameters (-D parameters) to be passed to the Java runtime.
JVMRuntimePathStringNoThe exact location of the Java runtime.
JVMVersionStringNoThe Java version your application needs to work. Can either be an explicit version String like 11.0.1, a major version like 11 (signalizing that any Java 11 runtime is sufficient) or a value like 11+ (signalizing that any Java 11 or higher runtime is sufficient).
LSUIElementBooleanNoDeclares if the application is an agent app that runs in the background and doesn't appear in the Dock (Details).
NSAppleMusicUsageDescriptionStringNoA message that tells the user why the app is requesting access to the user’s media library.
NSAppSleepDisabledBooleanNoDeclares if the app is allowed to nap or not.
NSCameraUsageDescriptionStringNoA message that tells the user why the app is requesting access to the device's camera (Details).
NSHighResolutionCapableBooleanNotrueDeclares if the application supports rendering in HiDPI (Retina) (Details).
NSHumanReadableCopyrightStringNoA human-readable copyright notice for the bundle (Details).
NSMicrophoneUsageDescriptionStringNoA message that tells the user why the application is requesting access to the device's microphone (Details).
NSSupportsAutomatic GraphicsSwitchingBooleanNotrueDeclares whether an OpenGL app may utilize the integrated GPU (Details).

CFBundleDocumentTypes configuration example

    <configuration>
        <plist>
            ...
            <CFBundleDocumentTypes>
                <CFBundleDocumentTypes>
                    <CFBundleTypeName>MyDocumentType</CFBundleTypeName>
                    <CFBundleTypeRole>Editor</CFBundleTypeRole>
                    <CFBundleTypeExtensions>
                        <string>foo</string>
                        <string>foobar</string>
                    </CFBundleTypeExtensions>
                </CFBundleDocumentTypes>
                <CFBundleDocumentTypes>
                    <CFBundleTypeName>AnotherDocumentType</CFBundleTypeName>
                    <CFBundleTypeRole>Editor</CFBundleTypeRole>
                    <CFBundleTypeExtensions>
                        <string>x</string>
                        <string>y</string>
                    </CFBundleTypeExtensions>
                </CFBundleDocumentTypes>
            </CFBundleDocumentTypes>
            ...
        </plist>
    </configuration>

Yes, the CFBundleDocumentTypes has to be entered twice: First as the parent for additional configurations and then for each configuration you want to define.

DMG configuration

The following other properties can be added to the dmg element configuring the generation of the DMG file at the end of the build:

KeyTypeRequired?DefaultDescription
generateBooleanNofalseWhether or not to create a DMG archive.
additionalResourcesList<Fileset>NoList of additional files to be copied into the archive.
createApplicationsSymlinkBooleanNotrueWhether or not to include a link to the Applications folder inside the archive.
useGenIsoImageBooleanNofalseWhether or not to use genisoimage to create the archive. Default is hdiutil.
autoFallbackBooleanNofalseIf true, try the other archive generation method when the first one fails. (e.g. run hdiutil when genisoimage fails and vice-versa)
appendVersionBooleanNotrueIf true, append the version to the .dmg name
dmgFileNameStringNonullIf not null and not empty, the supplied string will be used as the file name (.dmg will be appended).

APP configuration

The following other properties can be added to the app element configuring additional files to be included in the app bundle:

KeyTypeRequired?DefaultDescription
additionalResourcesList<Fileset>NoAdditional files to be copied into the app bundle.
...
    <configuration>
        <app>
            <additionalResources>
                <resource>
                    <directory>${project.basedir}/src/main/resources</directory>
                    <outputDirectory>Contents/Resources</outputDirectory>
                    <includes>
                        <include>**</include>
                    </includes>
                </resource>
            </additionalResources>
        </app>
    </configuration>
...

Code signing

The plugin can automatically sign the created application bundle if a codesign identiy is given:

...
    <configuration>
        <codesign>
            <identity>3rd Party Mac Developer Application: MyName (MyNumber)</identity>
        </codesign>
    </configuration>
...

The following other properties can be added to the codesign element configuring additional options for signing:

KeyTypeRequired?DefaultDescription
enableBooleanNotrueWhether or not to sign the created application bundle.
identityStringYesThe identity of the signer. Required if the codesign element is present.
preserveMetadataList<String>Noentitlements

To sign the application using a local dummy identity (which will only work on the machine where the signing was performed) you can use:

...
    <configuration>
        <codesign>
            <identity>-</identity>
        </codesign>
    </configuration>
...

JDK inclusion

Usually the application bundle built by the plugin will depend upon a Java runtime being available on the machine where the application is executed. To be completely self-sustaining, the plugin supports including the runtime into the target application. That runtime will then be used to launch the application, so there are no dependencies to a JDK being installed locally.

...
    <configuration>
        <jdk>
            <include>true</include>
            <location>/where/your/jdk/is/installed</location>
        </jdk>
    </configuration>
...

The following parameters can be set below the jdk configuration element:

KeyTypeRequired?DefaultDescription
includeBooleanNofalseWhether or not to include the JDK in the generated application bundle.
locationStringNoThe location of the JDK to be included. If no location is provided then the currently used JDK (which is the JDK that is used by the Maven binary) will be added to the application.

Dependencies exclusion

By default all declared dependencies (both direct dependencies as well as transient dependencies) are included in the generated application bundle.

If you only want to include the direct application JAR file without any dependencies (e.g. because you've already included the dependencies into the application JAR itself) then you can set the includeDependencies flag of the app configuration to false:

...
    <configuration>
        <app>
            <includeDependencies>false</includeDependencies>
        </app>
    </configuration>
...

Native binary selection

By default the launcher contains a universal binary that allows running the application on both the classic x86_64 as well as the new arm64 architecture.

In case any problems occur with the universal binary (or if you want to support only a specific architecture) you can select which binary should be bundled with your application via the nativeBinary setting:

 ...
    <configuration>
        <nativeBinary>X86_64</nativeBinary>
    </configuration>
 ...

The available values are:

  • UNIVERSAL (the default if no explicit value is given)
  • X86_64
  • ARM_64

Development

Changes are documented in the CHANGELOG.md file.

The project consists of two main parts: The regular Maven plugin (written in Java) and the native macOS launcher (written in Objective C).

Building the native part is fully integrated into the Maven lifecycle, so all you need to do to build the plugin is:

$ git clone https://github.com/perdian/macosappbundler-maven-plugin.git
$ mvn clean install

I am aware that my understanding of Objective C is very basic - I'm not an Objective C developer by heart and going back to using pointers and (somewhat) manual memory management feels pretty strange. So a lot of what's in the code is highly cargo culted from tutorials and answers on Stackoverflow, but hey: It works!

Authors

Donate

See also the list of contributors who participated in this project.

License

This project is licensed under the Apache 2.0 License - see the LICENSE file for details.

Acknowledgments

I originally used and have been highly influenced by the appbundle-maven-plugin from federkasten. Unfortunately the plugin stopped working with Java versions 10 and above (and didn't provide support for Java 9+ module projects).

FAQs

Package last updated on 05 Oct 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc