Tools for packging, code-signing and notarization of Java applications for Apple macOS, Windows and Linux.
- .NET Framework 3.5
- https://wixtoolset.org/docs/wix3/
- Wrapper for Jlink
- Wrapper for JPackage
- Wrapper for xcrun notarytool
- Wrapper for codesign
Integrate packaging, codesigning and notarizing with your Maven build.
Add the following configurations to your pom.yml
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-mods</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
<includeGroupIds>${modularGroupIds}</includeGroupIds>
<outputDirectory>${project.build.directory}/mods</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-libs</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
<excludeGroupIds>${modularGroupIds}</excludeGroupIds>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
This will configure your build to copy and separate all dependencies to the following two paths:
{project.build.directory}/libs
and {project.build.directory}/mods
.
Specify filtering using the {modularGroupIds}
property:
<modularGroupIds>org.openjfx</modularGroupIds>
In this example, JavaFX mods will go to mods
, all other dependencies will go to libs
.
<profile>
<id>macosx-aarch64</id>
<properties>
<javafx.platform>mac-aarch64</javafx.platform>
</properties>
<build>
<finalName>${project.artifactId}-${javafx.platform}</finalName>
<plugins>
<plugin>
<groupId>io.github.tools1000.codesignjava</groupId>
<artifactId>codesignjava-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>package-and-codesign</goal>
</goals>
</execution>
</executions>
<configuration>
<jreModuleNames>java.desktop, java.base,java.logging, java.xml, java.scripting, java.compiler,
java.instrument, jdk.unsupported, javafx.base, javafx.graphics,
javafx.controls,javafx.fxml, java.sql, java.naming
</jreModuleNames>
<jreModules>${project.build.directory}/mods</jreModules>
<applicationModulesPath>${project.build.directory}/libs</applicationModulesPath>
<appVersion>1.0.0</appVersion>
<moduleName>Name</moduleName>
<packageIdentifier>com.name</packageIdentifier>
<moduleStarter>module-name/LauncherClass</moduleStarter>
<developerId>${MAC_DEVELOPER_ID}</developerId>
<apiKey>${MAC_API_KEY_ID}</apiKey>
<apiIssuer>${MAC_API_ISSUER_ID}</apiIssuer>
</configuration>
</plugin>
</plugins>
</build>
</profile>
-
Valid values for
javafx.platform
arelinux
,linux-aarch64
,mac
,mac-aarch64
,win
,win-x86
. For more details, see here. -
Currently, you need to specify required modules explicitly with
jreModuleNames
. See Issue 14. -
You need to specify modules that should be bundled together with the JRE via
jreModules
. A typical use case would be JavaFX mods. -
Modules and libraries that should be bundled with your app are specified with
applicationModulesPath
. -
for developerId, apiKey and apiIssuer, please see [Secrets] (#Secrets) section.
-
Register as a developer at developer.apple.com.
-
Go to developer.apple.com/account/resources/certificates/list and create a new Certificate:
-
Go to appstoreconnect.apple.com/access/api and create a developer API key.
You will need the "Issuer ID" and the "KEY ID" later for the notarization.
Important: Download the API key, that is only possible once right after creation of the key! You will need it later.
create folder
.private_keys
in home and move*.p8
file there:mkdir -p ~/private_keys; cp *.p8 ~/.private_keys
-
Go to developer.apple.com/account/resources/certificates/list and register a new identifier for the app.
-
Go to appstoreconnect.apple.com/apps and register a new App with the created identifier.
On developer.apple.com/forums/thread/128166 they write:
Do not use the --deep argument. This feature is helpful in some specific circumstances but it will cause problems when signing a complex program.
See here developer.apple.com/forums/thread/129980 for more info.
-
Download your certificate.
-
Convert to base64 string and copy it to your clipboard:
base64 -i Developer\ ID\ Application\ John\ Doer\ \(12345ABCDE\).p12 | pbcopy
-
Create a repository variable and paste the base64 string:
-
Create another variable and paste your password:
xcrun altool --notarize-app --primary-bundle-id "com.drkodi" --apiKey "ABCDE12345" --apiIssuer "3a8a0000-5288-41dd-8527-b0000000028a" -t osx -f DrKodi.app.zip --output-format json
Note: trying to upload an .app file will fail. Instead, zip it first and upload the zip file.
xcrun altool --notarization-info 'cb00ab00-b46b-424a-b0dd-d4f7f9111147' --primary-bundle-id "com.drkodi" --apiKey "ABCDE12345" --apiIssuer "3a8a0000-5288-41dd-8527-b0000000028a" --output-format json
Go to https://github.com///settings/secrets/actions and create repository/ organisation secrets.
MAC_DEVELOPER_ID
this should hold the name of your Apple developer certificate. For example,Developer ID Application: John Doe (12345ABCDE)
. Note that there are different certificates for different purposes. See https://developer.apple.com/account/resources/certificates/add for more details.MAC_DEVELOPER_CERTIFICATE
this is the actual certificate. You need to export your certificate from your keychain into a base64 string that can be passed on via a GitHub secret. See https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development and https://help.apple.com/xcode/mac/current/#/dev154b28f09 for more details.- During certificate export, you will need to provide a password. Store it in another organisation/ repository variable. Call it
MAC_DEVELOPER_CERTIFICATE_PASSWORD
for example.
Go to https://appstoreconnect.apple.com/access/api and create a new key as described above. Like before, we need the key name/ id, and the key itself. A password is not required here.
MAC_API_KEY_ID
the name of the API key. Identical toKEY ID
on the App Store Connect page.MAC_API_KEY
the key itself. Again, it is supposed to be a base64 string. Transform and copy to clipboard with the following command:base64 -i .private_keys/AuthKey_12345ABCDE.p8 | pbcopy
.MAC_API_ISSUER_ID
the keyIssuer ID
. Identical to Issuer ID on the App Store Connect page.
KEYCHAIN_PASSWORD
: A new keychain will be created on the runner, so the password for the new keychain can be any new random string. In this example, the secret is namedKEYCHAIN_PASSWORD
. From the docs (https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development).