How to prepare your JME project for MacAppStore (Netbeans / SDK)

Hello,

I didn’t see here in the forum steps to submit your game or app that used JME to the MacAppStore. I managed to sumbit mine and pass the preliminary tests. So I want to share with you what I have done as documentation. Some parts can be implemented into a plugin but in my case this is enough.

NOTE: This is for Netbeans / SDK, but you can use it on other IDE’s with a few changes in the method

Feel free to add suggestions or changes:

To do this you need:

  • Your Java project ready to release
  • An Apple developer signature for apps
  • xCode installed.

Before you begin:

Before you pack your main project into an app you need to ensure two things. The first one is that the main frame / display has your project’s title and not “JMonkeyEngine…”. The second and more complex one is that the menu bar on top must have a “Window” menu with a list of opened windows or frames of your app (usually one). as shown here.

Apple’s guideline

To Add this window menu to the menu bar you have two options:

  1. Use Java’s awt.Frame libraries to contain your application, you can have the menu pretty straightforward but just add the lines at the very begining of the main method: (using Frame with JME may be buggy in OSx as of now but later it will be solved)

    System.setProperty(“apple.laf.useScreenMenuBar”, “true”);
    ///The next one is Optional
    System.setProperty(“com.apple.mrj.application.apple.menu.about.name”, “Your.app.name.here”);

  2. “Hack” your way to the menu bar so that you can use the standard JME Display by using code similar to this example

     try {
         Class<?> clazz = Class.forName("com.apple.eawt.Application");
         Method method = clazz.getMethod("getApplication");
     
         Object obj = method.invoke(null);
     
         method = clazz.getMethod("setDefaultMenuBar", JMenuBar.class);
     
         method.invoke(obj, CreateMenuBar()); //Your custom MenuBar
     
         method = clazz.getMethod("enableSuddenTermination");
     
         method.invoke(obj);
     
     } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
         ...
     }
    

Ensure that the the menu closes with your app so add the proper handles ;).

Now that you have the Window menu and the title, you are ready to pack your application in a app using either Netbeans or the SDK (including the JRE for users that do not have Java installed)

Minor changes to the app’s plist File

Once you have your app bundled, you will notice that inside there is an Info.plist file under the Contents folder. You need to edit it a little in order to bundle.

  • Ensure that under CFBundleIdentifier it has the package name you submitted to the App Store’s submission form.
  • Ensure that it contains the key LSArchitecturePriority like this

<key>LSArchitecturePriority</key>
<array>
    <string>x86_64</string>
</array>
  • Ensure that the application category is in there as well

    LSApplicationCategoryType
    public.app-category.[your app category]

  • If you submitted before, make sure that the version under CFBundleShortVersionString is higher than the latest you have submitted successsfully

Note: You can add a i386 architecture if you like. But 64 bit is more connon now

If you Bundled the JRE

We need to remove from the bundled app the files that Apple does not like. The files are: libjfxmedia_avf.dylib, libjfxmedia_qtkit.dylib, libjfxmedia.dylib and libjfxwebkit.dylib. You can either use a command or explore the app to find and delete them. they don’t do anything most of the time and removing them is harmless.

The bundled JRE also contains an Info.plist file. We need to make a slight change inside since the bundle identifier of the jre is already in the app store and a repeated ID is not allowed (even though you haven’t submitted anything). To do that look for the key named CFBundleIdentifier and change the string value right bellow it to something like your.package.name.jre

Signing the app

Before we package the app we need an entitlements file to add sandboxing to your application. This is very easy to make. Just create a file [appname].entitlements and add the following lines:

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
     <dict>
         <key>com.apple.security.app-sandbox</key>   
         <true/>
     </dict>
 </plist>

Now we need to sign it the app with this entitlements file and using the signature we obtained from Apple. But it’s not as straightforward as it sounds. This is what needs to be signed:

  • ALL jar files. your application, all JME jars you are using + additionals, all jars inside the bundled jre.
  • ALL *.dylib files you can find.
  • The executable file [your app name] located in Contents/MacOS/
  • ALL Info.plist files (no entitlement needed)
  • the app package. This is the last to be signed.
  • A file named jspawnhelper that is contained in the JRE

There isn’t really an effective, recursive command using Mac’s terminal. You have to run the same command to each file… something like

codesign -f -s "3rd Party Mac Developer Application: <Your name or company name>"  
             --entitlements [appname].entitlements  [appname].app/Contents/<path to every file>

This is tedious to do it one by one and you may miss a file or two. You can write a shell script to do this for you, but since I suck at shell scripts I decided to make a Java console app that will do the job for me. I will put the code in another post.

Making the package

Now that you got everything signed. we need to make an pkg installer. thankfully you only need to run one command in terminal:

productbuild --component [path to your app].app /Applications [your package name].pkg --sign "3rd Party Mac Developer Installer: [Your name or company name]" --product [path to internal app plistFile].plist

Congratulations! You have the package ready to sumbit to the app store :smiley:

Edit: Sorry, I forgot a few details! Added now. :stuck_out_tongue:

9 Likes