I have been building MacOs Java application on Intel MacMini for number of years, essentially
- Compile/Build with maven
- Make cutdown embedded jre using jlink
- Make Appbundle using TheInfiniteKind AppBundler fork
- Sign and notarize
- Package up as a dmg using DmgCanvas
Now have it building on MacOS M1 and it builds okay. When I run on Mac M1 it works but when I try to run on Intel Macmini it fails with Unable to load JRE Environment
This kind of makes sense because when I build it I am just providing a single jre based on the M1 version of Adoptium Terium 17. But I dont understand how I provide two JRE's if this is what I need to do
Below I show the main build script
#!/bin/bash
#set -x
cd $HOME/code/jthink/songkong/src/main/scripts
hiutil -C -fapplehelpbook/SongKongHelp/SongKongHelp.helpindex applehelpbook/SongKongHelp/
cd $HOME/code/jthink/songkong
sudo rm -fr /Applications/SongKong.app
mvn -f pommacos.xml clean
mvn -f pommacos.xml -DskipTests=true install
rm -fr target/songkong-8.2
unzip target/songkong-8.2-distribution.zip -d target
ant
while read line; do
echo "$line"
if [[ "$line" = "<string>1.0</string>" ]]; then
cat mergefile.txt # or echo or printf your extra lines
fi
done < /Applications/SongKong.app/Contents/Info.plist > Info.new
while read line; do
echo "$line"
if [[ "$line" = "<false/></dict>" ]]; then
cat mergefile2.txt
fi
done < Info.new > Info.new2
rm /Applications/SongKong.app/Contents/Info.plist
rm Info.new
mv Info.new2 /Applications/SongKong.app/Contents/Info.plist
sudo cp -r target/songkong-8.2/applehelpbook/SongKongHelp /Applications/SongKong.app/Contents/Resources
export CODESIGN_ALLOCATE="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate"
/usr/bin/codesign --timestamp --options runtime \
--entitlements $HOME/code/jthink/songkong/songkong.entitlements \
--sign "Developer ID Application: P Taylor" \
--force --deep --verbose /Applications/SongKong.app
/usr/bin/codesign -vvv --deep --strict /Applications/SongKong.app
spctl -a -t exec -vv /Applications/SongKong.app
cd $HOME/code/jthink/SongKong
/usr/local/bin/dmgcanvas $HOME/code/jthink/SongKong/dmgCanvas_songkong.dmgCanvas $HOME/songkong-osx.dmg -v SongKong -identity "Developer ID Application: P Taylor" -notarizationAppleID [email protected] -notarizationPassword xxxxxxxxxxxxxxxxxxxxxx -notarizationPrimaryBundleID songkong
and the ant file used by the appbundler task
<?xml version="1.0" encoding="iso-8859-1"?>
<project name="songkong">
<property environment="env"/>
<property name="songkongsrc" value="/Users/paultaylor/code/jthink/SongKong/target/songkong-8.2"/>
<property name="resources" value="/Users/paultaylor/code/jthink/SongKong/src/main/resources"/>
<property name="songkonglib" value="${songkongsrc}/lib"/>
<property name="songkongtargetroot" value="/Applications"/>
<property name="songkongtarget" value="${songkongtargetroot}/SongKong.app"/>
<property name="songkongcontentstarget" value="${songkongtarget}/Contents"/>
<!-- Obtain path to the selected JRE -->
<exec executable="/usr/libexec/java_home"
failonerror="true"
outputproperty="runtime">
<arg value="-v"/>
<arg value="17"/>
</exec>
<taskdef name="bundleapp" classname="com.oracle.appbundler.AppBundlerTask"/>
<bundleapp outputdirectory="${songkongtargetroot}"
name="SongKong"
displayname="SongKong"
executableName="SongKong"
identifier="com.jthink.songkong"
shortversion="8.2"
mainclassname="com.jthink.songkong.cmdline.SongKong"
signature="sgkg"
applicationCategory="public.app-category.music"
icon="${songkongsrc}/songkong.icns"
>
<classpath dir="${songkonglib}">
<include name="**/*.jar"/>
</classpath>
<classpath dir="${songkongsrc}">
<include name="songkong.properties"/>
</classpath>
<librarypath dir="${songkongsrc}">
<include name="fpcalc_osx"/>
<include name="libAppleScriptEngine.dylib"/>
</librarypath>
<option value="-Dcom.mchange.v2.log.MLog=com.mchange.v2.log.jdk14logging.Jdk14MLog"/>
<option value="-Dorg.jboss.logging.provider=jdk"/>
<option value="-Djava.util.logging.config.class=com.jthink.songkong.logging.StandardLogging"/>
<option value="-Dapple.laf.useScreenMenuBar=true"/>
<option value="-Dapple.awt.brushMetalLook=true"/>
<option value="-Dsun.java2d.metal=true"/>
<option value="-XX:+HeapDumpOnOutOfMemoryError"/>
<plistentry key="NSRequiresAquaSystemAppearance" type="boolean" value="false"/>
<plistentry key="AppleWindowTabbingMode" value="manual"/>
<bundledocument extensions="mp3,wma,ogg,flac,wav,aif,aiff,aifc"
name="Music Files"
role="editor"
isPackage="false">
</bundledocument>
<jlink runtime="${runtime}">
<jmod name="java.desktop"/>
<jmod name="java.datatransfer"/>
<jmod name="java.logging"/>
<jmod name="java.management"/>
<jmod name="java.naming"/>
<jmod name="java.net.http"/>
<jmod name="java.prefs"/>
<jmod name="java.scripting"/>
<jmod name="java.sql"/>
<jmod name="jdk.management"/>
<jmod name="jdk.unsupported"/>
<jmod name="jdk.jcmd"/>
<jmod name="jdk.crypto.ec"/>
<jmod name="jdk.dynalink"/>
<argument value="--compress=2"/>
<argument value="--release-info=${runtime}/release"/>
</jlink>
</bundleapp>
<copy file="${resources}/create_itunes_model.scpt" tofile="${songkongcontentstarget}/Java/create_itunes_model.scpt"/>
<copy file="${resources}/create_music_model.scpt" tofile="${songkongcontentstarget}/Java/create_music_model.scpt"/>
<copy file="${resources}/get_playlist_folder.scpt" tofile="${songkongcontentstarget}/Java/get_playlist_folder.scpt"/>
<copy file="${resources}/get_music_playlist_folder.scpt" tofile="${songkongcontentstarget}/Java/get_music_playlist_folder.scpt"/>
<copy file="${songkongsrc}/songkong.properties" tofile="${songkongcontentstarget}/songkong.properties"/>
<copy file="${songkongsrc}/songkong1.properties" tofile="${songkongcontentstarget}/songkong1.properties"/>
<copy file="${songkongsrc}/songkong2.properties" tofile="${songkongcontentstarget}/songkong2.properties"/>
<copy file="${songkongsrc}/songkong2.properties" tofile="${songkongcontentstarget}/songkong3.properties"/>
<copy file="${songkongsrc}/songkong2.properties" tofile="${songkongcontentstarget}/songkong4.properties"/>
<copy file="${songkongsrc}/songkong5.properties" tofile="${songkongcontentstarget}/songkong5.properties"/>
<copy file="${songkongsrc}/renamemask.properties" tofile="${songkongcontentstarget}/renamemask.properties"/>
<copy file="${songkongsrc}/general.properties" tofile="${songkongcontentstarget}/general.properties"/>
<copy file="${songkongsrc}/license.properties" tofile="${songkongcontentstarget}/license.properties"/>
<copy file="${songkongsrc}/genrelist.txt" tofile="${songkongcontentstarget}/genrelist.txt"/>
<copy file="${songkongsrc}/classical_composers.txt" tofile="${songkongcontentstarget}/classical_composers.txt"/>
<copy file="${songkongsrc}/classical_conductors.txt" tofile="${songkongcontentstarget}/classical_conductors.txt"/>
<copy file="${songkongsrc}/classical_people.txt" tofile="${songkongcontentstarget}/classical_people.txt"/>
<copy file="${songkongsrc}/not_classical_release.txt" tofile="${songkongcontentstarget}/not_classical_release.txt"/>
<copy file="${songkongsrc}/license.txt" tofile="${songkongcontentstarget}/license.txt"/>
<copy file="${songkongsrc}/index.html" tofile="${songkongcontentstarget}/index.html"/>
<copy file="${songkongsrc}/pdfOSX/help.pdf" tofile="${songkongcontentstarget}/help.pdf"/>
<copy file="${songkongsrc}/osx/bin/songkong.sh" tofile="${songkongcontentstarget}/bin/songkong.sh"/>
<copy file="${songkongsrc}/osx/bin/songkongremote.sh" tofile="${songkongcontentstarget}/bin/songkongremote.sh"/>
<copy todir="${songkongcontentstarget}/style"><fileset dir="${songkongsrc}/style"/></copy>
<copy todir="${songkongcontentstarget}/lang"><fileset dir="${songkongsrc}/lang"/></copy>
<chmod file="${songkongcontentstarget}/bin/songkong.sh" perm="777"/>
<chmod file="${songkongcontentstarget}/bin/songkongremote.sh" perm="777"/>
</project>
Edit 1:.
So when you say, you want to create a universal app, as I understand:
If you want to achieve 1-4, there is a hard road ahead:
You can also customize an appbundler by forking this repository
You need to focus on this class first: https://github.com/TheInfiniteKind/appbundler/blob/master/appbundler/src/com/oracle/appbundler/AppBundlerTask.java
How it works: Challenge we need to solve is Appbundler takes only 1 runtime at any given time.
https://github.com/TheInfiniteKind/appbundler/blob/master/appbundler/src/com/oracle/appbundler/AppBundlerTask.java#L235
Later it copies the runtime contents to a directory called PlugIns
https://github.com/TheInfiniteKind/appbundler/blob/master/appbundler/src/com/oracle/appbundler/AppBundlerTask.java#L467
You can extend
AppBundlerTaskand overridepublic void execute()method.Here you can provide
List<Runtime>instead of singleRuntime.now, this execute method creates a Info.plist file, you can create two instead with different runtime elements. https://stackoverflow.com/a/54569519/1811348
I am highly in doubt if this will work for following three issues in my mind: a. How Plugins directory is loaded in the app and how its used is not known to me, so two runtimes in same dir, no idea if its okay. b. If at all we can have two plist file in same app how to toggle them with device environment variable from app side is not known to me. This env variable will decide what plist file to select. c. app size post bundling two jre's in single app.
Also note, accordingly you will have to update your ant task to provide two directories for 2 jre's.
If only 1,2,3 are correct, you can bundle two jre's in two different applications:
I think answer still remains the same as the exec tag itself is just setting your java runtime. However you can try following way as well.
Just add condition for this exec
kindly note that: this exec tag is doing same thing that
<runtime dir="${env.JAVA_HOME}" />is doing in provided article.https://docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html
eg:
From what I am guessing you are loading the jre in exec tag of ant xml.
You can use Ant conditionals if you want to negotiate based on some criteria eg: device, os, os version and so on.
also ref: https://stackoverflow.com/a/19272061/1811348
Additionally, if you want to do anything special eg: package jar for two different platforms altogether with different jdk versions you can: https://www.zghurskyi.com/maven-package-to-multiple-java-versions/