Code signing + notarization using jpackage utility isn't working on macOS

I'll go ahead and answer my own question because I ended up figuring out how to sign my application and get it successfully notarized from the Apple notarization service (my product is http://cardr.x10.bz).

  1. Use jpackage's app-image option to generate an unsigned app bundle.

  2. Use an automated bash script to codesign all dylib and executable files inside of the app bundle, using codesign -vvv --options runtime --deep --force --sign "Developer ID Application: ********" <filename>.

  3. This is a multi-step procedure, so I'll just split it up into A/B/C.

3A) Find all jar files within the MyApp.app/Contents/mods/ that contain embedded .dylib files, and extract those files to a specific folder (or write a small program to do this for you). For me, my app relied on JavaFX, so many of the JavaFX libraries contained .dylib files within the jar files. However, if you're just using the default Java libraries, you should be able to skip to step 4, since the default Java libraries don't contain .dylib files. The reason we need to do this step is becuase Apple's notarization service checks these embedded .dylib files for codesigning as well.

3B) Use an automated bash script to codesign all dylib files that you just extracted, using codesign -vvv --options runtime --deep --force --sign "Developer ID Application: ********" <filename>.

3C) Add each of signed .dylib files back into their respective jar files to replace the original unsigned embedded .dylib files. Here's a command that may come in handy: jar uf <path to jar file> <path to dylib file>. Keep note that the second path specified, the path to the dylib file, should also be the dylib's relative location within the archive. Take a look here for more details - https://docs.oracle.com/javase/tutorial/deployment/jar/update.html.

  1. Now that you've signed each of the executable files and dylib files within the .app, it's time to sign the .app itself. Run codesign -vvv --force --sign "Developer ID Application: ********" MyApp.app.

  2. Now that you have signed the .app, you need to run jpackage on the app bundle to create either a DMG or a PKG out of it. Feel free to use the jpackage mac signing features, which will sign the outer DMG/PKG. Take note that the property --mac-signing-key-user-name "My Developer Account Name (*******)" should NOT include the "Developer ID Application/Installer" part of the certificate.

  3. Finally, you have created a signed PKG/DMG ready for notarization. Use xcrun altool --notarize-app --username <apple-id> --password <app-specific-password> <MyApp.dmg or MyApp.pkg>. Wait for notarization to complete and make sure it is approved.

  4. If notarization succeeded (it should), you can staple your app's ticket to the PKG installer using xcrun stapler staple MyApp.pkg.

Hope this helps!


For a working end-to-end script for my app (Unattach), see the darwin section of package.sh.


FYI - Delved into this problem in JDK 14.0.1 and wanted to share the knowledge as another interim solution until jpackage works correctly.

In the JDK 14 source path: src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal

the file MacAppBundler.java contains these lines (81 & 82): "Developer ID Application: " + SIGNING_KEY_USER.fetchFrom(params),

where SIGNING_KEY_USER picks up the value of the --mac-signing-key-user-name parameter from the command line.

With these lines using jpackage to sign the DMG always failed. (The 'Developer ID Application: ' did not match the name of my certificate.)

CHANGED these lines to drop the "Developer ID Application: " and the following '+' sign. On invoking jpackage used the full name of the certificate as the parameter value:

--mac-signing-key-user-name "3rd Party Mac Developer Application: John Smith (ABCDEFGHIJ)"

and jpackage will now (apparently) build and sign the DMG. Have not actually attempted to submit this to the Apple Store, so this may still be incomplete.

Interestingly, the MacAppStoreBundler.java source does contain the correct "3rd Party Mac Developer Application: " and "3rd Party Mac Developer Installer: " prefix strings so suspect that jpackager is actually invoking the wrong methods -- but have not yet sorted that out. Possibly jpackage needs to have some additional parameters to specify exactly what should be done (but you would think that '--type dmg' would invoke the correct logic).

Basic (clumsy) steps to reproduce:

  • Download source from https://hg.openjdk.java.net/jdk (picked jdk14, commit 6c954123ee8d).
  • Download and unpack the .zip (or .gz or .bz2) into a working directory
  • Use any text editor to follow the path from 'src' and change MacAppBundler.java as noted above.
  • Open terminal window, and cd into the 'src' directory
  • run 'make all' to compile the entire JDK 14
  • run src/build/macosx-x86_64-server-release/images/jdk/bin/jpackage ...parameters...