Customizing the Resources directory of an .app bundle with Javapackager

1.1k views Asked by At

On macOS, I am using Javapackager to make an Application.app bundle (called a disk image) from my Application.jar Java archive:

javapackager \
  -deploy \
  -native image \
  -srcfiles Application.jar \
  -outdir dist \
  -outfile Application \
  -appclass Application

The resulting Application.app bundle is a directory with the following layout:

Application.app
|--Contents
   |--Info.plist
   |--PkgInfo
   |--Java
   |  |--Application.jar
   |--MacOS
   |  |--Application
   |--Resources

However I have some <language>.lproj directories (which hold InfoPlist.strings files for localizing some strings of the Info.plist file, cf. Apple's Developer website) on my file system that need to be copied in the Resources directory of the Application.app layout, like this:

Application.app
|--Contents
   |--Info.plist
   |--PkgInfo
   |--Java
   |  |--Application.jar
   |--MacOS
   |  |--Application
   |--Resources
      |--en.lproj
         |--InfoPlist.strings
      |--fr.lproj
         |--InfoPlist.strings

How can I tell Javapackager to do that? (I do not want to copy the <language>.lproj directories myself in the Application.app bundle after its creation, as it would break its signature.)

2

There are 2 answers

0
madduci On

If you use (or can use) maven, you can do it with the assembly plugin.

First of all, you can use the exec plugin to perform the jlink/javapackage steps and on completion (in the package phase), copy your missing information to the destination folder.

Maven automatizes it for you and you don't have to perform manually those steps.

For instance:

<project>
  [...]
  <build>
    [...]
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <executions>
          <execution>
          <goals>
            <goal>exec</goal>
          </goals>
         </execution>
       </executions>
       <configuration>
         <executable>jlink</executable>
         <!-- optional -->
         <workingDirectory>/tmp</workingDirectory>
         <arguments>
           <argument>--compress=2</argument>
           <argument>--strip-debug</argument>
           ...
         </arguments>
        [...]

      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <descriptors>
            <descriptor>src/assembly/copy-resources.xml</descriptor>
          </descriptors>
        </configuration>
      </plugin>
</project>
0
jbilander On

As a workaround:

  1. put your custom Info.plist file in package/macosx/ (create if non existent) for javapackager to pick it up during execution, then run your javapackager as you normally would.

  2. manually copy the *.lproj/InfoPlist.strings structure over to the Application.app/Contents/Resources folder.

  3. sign both files, replace with your values. Hint: You can find out your values from the javapackager console output. Something like:

    codesign -s "Developer ID Application: Your Company Inc (A1234ABCDE)" --prefix com.domain. ./Application.app/Contents/Resources/en.lproj/InfoPlist.strings

    do the same for fr.lproj

  4. To verify it looks okay:

    codesign --verify --strict --verbose=2 ./Application.app/Contents/Resources/en.lproj/InfoPlist.strings

    Should output:

    ./Application.app/Contents/Resources/en.lproj/InfoPlist.strings: valid on disk ./Application.app/Contents/Resources/en.lproj/InfoPlist.strings: satisfies its Designated Requirement

    do the same for fr.lproj

  5. Then replace existing signature with command below. This regenerates a new updated CodeResources file under Contents/_CodeSignature/

    codesign -s "Developer ID Application: Your Company Inc (A1234ABCDE)" --prefix com.domain. --force --deep ./Application.app

    Should output:

    ./Application.app: replacing existing signature

    And the updated CodeResources file should have entries for en.lproj and fr.lprojlike:

    <key>Resources/en.lproj/InfoPlist.strings</key>
    <dict>
        <key>hash</key>
        <data>
        CUsP4OMChUrxMRr6uFtSA7pFejs=
        </data>
        <key>optional</key>
        <true/>
    </dict>
    
  6. Verify that your app conforms to Gatekeeper policies when you distribute with Developer ID, to mimic what Gatekeeper does.

    codesign --verify --deep --strict --verbose=2 ./Application.app

  7. Automate the steps above in a script!