There are lots of tutorials explaining how to bundle a Java application as amacOS application, but there aren’t really any that explain how to bundle aJava application into an existing Objective-C or Swift Cocoa application.
This article describes one possible means of using Java within suchapplications, and will work for Swift as well as Objective-C.
Background to this Exercise
The Xcode project file in that directory will build a shell.app with th= e launcher stub and an example Info.plist. =20 The next steps for this code is to be adapted into the JDK's proper Make= file-driven build system, and to create an artifact in the standard JDK bun= dle. The Java packaging tools provide built-in support for several formats of self-contained application packages. The basic package is a single folder on your hard drive that includes all application resources and the JRE. The package can be redistributed as is, or you can build an installable package (for example, EXE or DMG format.). This issue discusses the conflict found between getdown's bundled JRE and install4j's bundled JRE on macOS using the DMG Jalview.app bundle method in install4j. We don't want to bundle two JREs! Many Adobe applications depend on the Oracle Java Runtime Environment (JRE) for some features to work. Apple recently changed the way it includes Java in Mac OS, and with Lion, Java is no longer preinstalled. It is now an optional install that you must select.
Since version 4.0, Balthisar Tidy and Balthisar Tidy for Workhave offered HTML document validation with the W3C Nu HTML Checker.Users are given the option to perform document validation with their choiceof the official W3C server, a server of their choice, or the localserver that’s bundled with Balthisar Tidy.
The local server, inconveniently, is a Java application, which makes it quitetricky to use from a C/Objective-C environment. While C interfaces remain thedefault for linking to foreign libraries (ask Ruby, Python, PHP, and everyoneelse), Java’s JNI can be a bit of a pain to implement on macOS. Thisgoes doubly for the Nu HTML Checker, because it’s designed to be a completeapplication used as a web service, and not a library like HTML Tidy.
The fact that it’s a web service, though, means that we can can communicatewith it via HTTP, just like we have to do with the W3C’s server oruser-specified server. This means, all we have to do is run it in a processseparate from Balthisar Tidy.
Adding the JAR
At first glance, this appears easy:
Except this probably won’t work, and won’t even be allowed if you want tooffer your application on the Mac App Store.
You Need a JRE
Like both Objective-C and Swift, Java applications require a runtime, calledthe Java Runtime Environment (JRE). It used to be that you could almost counton this being installed on a macOS system by default, but that’s not been thecase in many, many releases.
Sometimes users install Java (which includes the JRE, naturally) on their ownin order to support other Java applications. If not, macOS will inform theuser to install Java when an attempt to use Java is made, but it’s up to theuser to find and install a compatible Java version.
Counting on the system to prompt to install Java isn’t very friendly, and it’sverboten for Mac App Store applications.
Instead, your only alternative is to host the JRE within your application’sbundle (or in the case of
JSDNuVFramework , the framework bundle, which isfound in the application bundle). The rest of this article will explain how todo that while minimizing the JRE size.
The JRE can Bloat your Application
The entire Java 10 JRE can be over 540 MB! While you can certainly bundle theentire JRE in your application, you’ll probably find that your users willwonder why the download size for your simple date calculator (or whatever) ishalf a gigabyte.
The entire JRE consists of headers, debugging symbols, documentation, andexecutable code that your application – in all likelihood – does’t require.Using Java’s own tools, we can find out the true JRE dependencies and builda custom JRE that’s significantly smaller. In the case of
vnu.jar , the JREhas been trimmed down to just under 45 MB for Balthisar Tidy’s next release.
Prerequisites
If you’re reading this article for information (rather than for fun), youprobably already have a Java JDK installed. These instructions should workfor Java 9 and anything newer than Java 10, but I’ve only tested thesetechniques with Java 10.
Don’t overlook setting your
$JAVA_HOME environment variable. It makes itmuch easier to type long paths in Terminal.app, and it means I won’t haveto type long paths in this article that, when you copy and paste in your ownterminal, fail to work.
On my system, I've set
…in my
.bash_profile file.
Determine JRE Dependencies
To determine which parts of the JRE that
vnu.jar depend on, use the jdeps tool provided by Java. Note that my terminal’s working directory is the rootdirectory of the Nu HTML Checker project; adjust your paths to your ownsituation.
For the most part, it’s okay to ignore the “split package” warnings. Theimportant data is the last line of output:
These are the Java modules that must constitute our custom JRE.
Build the Custom JRE with jlink
Next, we can build the custom JRE, and make it as small as possible in onelong step. Again, my example is working from the repository’s root directory.
The result will be a custom JRE with the minimum number of Java modulesrequired to run the
vnu.jar JAR. Things such as debug symbols and headerswill be omitted, and everything will be packaged into the single folder named“Home”.
Now Construct Our Package
Xcode and macOS will expect your JRE to be installed in your bundle’s standard“PlugIns” folder, and that it follow the standard bundle format itself. Ifyou are planning to code sign your application, then this bundle format isdoubly important.
Create this directory structure manually in Finder or your terminal.In the case of
JSDNuVFramework , our bundle content looks something like this:
Notice that the
Java.runtime/ directory honors the standard bundle format.This is important if you plan to code-sign your application, in thatcodesign simply won’t work if the bundle isn’t a macOS bundle.
When we built the JRE with
jlink , the example should have produced adirectory named “Home”; the Home directory above should be this entiredirectory. Just drag it over in Finder to keep things simple.
However, let’s address the
MacOS directory and its libjli.dylib library.This file is not generated by the JRE, and it’s not part of the JRE. Rather,it’s a bridging library required by macOS to execute the java instance inthe bundle. You should copy and paste this from your JDK installation path,which should be $JAVA_HOME/lib/jli/libjli.dylib .
If you wish to pare down your JRE just a little bit further, feel free todelete all of the executables except for
java in the Home/bin/ directory.If you plan to sign your executable, do this before signing.
If you’re not code-signing or deploying to the Mac App Store, then you’redone. You can use
NSTask to execute the java executable in your bundleusing vnu.jar as its argument.
Change the
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |