@@ -72,7 +72,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
7272 private static final ResourceBundle I18N = ResourceBundle .getBundle (
7373 "jdk.jpackage.internal.resources.MacResources" );
7474
75- private static final String TEMPLATE_BUNDLE_ICON = "java .icns" ;
75+ private static final String TEMPLATE_BUNDLE_ICON = "JavaApp .icns" ;
7676 private static final String OS_TYPE_CODE = "APPL" ;
7777 private static final String TEMPLATE_INFO_PLIST_LITE =
7878 "Info-lite.plist.template" ;
@@ -102,6 +102,13 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
102102 params -> null ,
103103 (s , p ) -> s );
104104
105+ public static final BundlerParamInfo <String > APP_CATEGORY =
106+ new StandardBundlerParam <>(
107+ Arguments .CLIOptions .MAC_CATEGORY .getId (),
108+ String .class ,
109+ params -> "utilities" ,
110+ (s , p ) -> s );
111+
105112 public static final BundlerParamInfo <String > MAC_CF_BUNDLE_IDENTIFIER =
106113 new StandardBundlerParam <>(
107114 Arguments .CLIOptions .MAC_BUNDLE_IDENTIFIER .getId (),
@@ -146,6 +153,38 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
146153 null : Boolean .valueOf (s )
147154 );
148155
156+ public static final StandardBundlerParam <Boolean > APP_STORE =
157+ new StandardBundlerParam <>(
158+ Arguments .CLIOptions .MAC_APP_STORE .getId (),
159+ Boolean .class ,
160+ params -> false ,
161+ // valueOf(null) is false, we actually do want null in some cases
162+ (s , p ) -> (s == null || "null" .equalsIgnoreCase (s )) ?
163+ null : Boolean .valueOf (s )
164+ );
165+
166+ public static final BundlerParamInfo <Path > ENTITLEMENTS =
167+ new StandardBundlerParam <>(
168+ Arguments .CLIOptions .MAC_ENTITLEMENTS .getId (),
169+ Path .class ,
170+ params -> {
171+ try {
172+ Path path = CONFIG_ROOT .fetchFrom (params ).resolve (
173+ getLauncherName (params ) + ".entitlements" );
174+ String defPath = (APP_STORE .fetchFrom (params ) ?
175+ "sandbox.plist" : "entitlements.plist" );
176+ createResource (defPath , params )
177+ .setCategory (I18N .getString ("resource.entitlements" ))
178+ .saveToFile (path );
179+ return path ;
180+ } catch (IOException ioe ) {
181+ Log .verbose (ioe );
182+ }
183+ return null ;
184+ },
185+ (s , p ) -> Path .of (s )
186+ );
187+
149188 private static final StandardBundlerParam <String > FA_MAC_CFBUNDLETYPEROLE =
150189 new StandardBundlerParam <>(
151190 Arguments .MAC_CFBUNDLETYPEROLE ,
@@ -336,27 +375,14 @@ private void sign(Map<String, ? super Object> params) throws IOException {
336375 String signingIdentity =
337376 DEVELOPER_ID_APP_SIGNING_KEY .fetchFrom (params );
338377 if (signingIdentity != null ) {
339- prepareEntitlements (params );
340378 signAppBundle (params , root , signingIdentity ,
341379 BUNDLE_ID_SIGNING_PREFIX .fetchFrom (params ),
342- getConfig_Entitlements (params ));
380+ ENTITLEMENTS . fetchFrom (params ));
343381 }
344382 restoreKeychainList (params );
345383 }
346384 }
347385
348- static Path getConfig_Entitlements (Map <String , ? super Object > params ) {
349- return CONFIG_ROOT .fetchFrom (params ).resolve (
350- getLauncherName (params ) + ".entitlements" );
351- }
352-
353- static void prepareEntitlements (Map <String , ? super Object > params )
354- throws IOException {
355- createResource ("entitlements.plist" , params )
356- .setCategory (I18N .getString ("resource.entitlements" ))
357- .saveToFile (getConfig_Entitlements (params ));
358- }
359-
360386 private static String getLauncherName (Map <String , ? super Object > params ) {
361387 return APP_NAME .fetchFrom (params );
362388 }
@@ -391,8 +417,17 @@ private void writeRuntimeInfoPlist(Path file,
391417 String name = StandardBundlerParam .isRuntimeInstaller (params ) ?
392418 getBundleName (params ): "Java Runtime Image" ;
393419 data .put ("CF_BUNDLE_NAME" , name );
394- data .put ("CF_BUNDLE_VERSION" , VERSION .fetchFrom (params ));
395- data .put ("CF_BUNDLE_SHORT_VERSION_STRING" , VERSION .fetchFrom (params ));
420+ String ver = VERSION .fetchFrom (params );
421+ String sver = ver ;
422+ int index = ver .indexOf ("." );
423+ if (index > 0 && ((index + 1 ) < ver .length ())) {
424+ index = ver .indexOf ("." , index + 1 );
425+ if (index > 0 ) {
426+ sver = ver .substring (0 , index );
427+ }
428+ }
429+ data .put ("CF_BUNDLE_VERSION" , ver );
430+ data .put ("CF_BUNDLE_SHORT_VERSION_STRING" , sver );
396431
397432 createResource (TEMPLATE_RUNTIME_INFO_PLIST , params )
398433 .setPublicName ("Runtime-Info.plist" )
@@ -443,6 +478,8 @@ private void writeInfoPlist(Path file, Map<String, ? super Object> params)
443478 data .put ("DEPLOY_LAUNCHER_NAME" , getLauncherName (params ));
444479 data .put ("DEPLOY_BUNDLE_SHORT_VERSION" , VERSION .fetchFrom (params ));
445480 data .put ("DEPLOY_BUNDLE_CFBUNDLE_VERSION" , VERSION .fetchFrom (params ));
481+ data .put ("DEPLOY_APP_CATEGORY" , "public.app-category." +
482+ APP_CATEGORY .fetchFrom (params ));
446483
447484 StringBuilder bundleDocumentTypes = new StringBuilder ();
448485 StringBuilder exportedTypes = new StringBuilder ();
@@ -643,9 +680,8 @@ static void signAppBundle(
643680 }
644681 }).filter (p -> Files .isRegularFile (p ) &&
645682 (Files .isExecutable (p ) || p .toString ().endsWith (".dylib" ))
646- && !(p .toString ().endsWith (appExecutable )
647- || p .toString ().contains ("/Contents/runtime" )
648- || p .toString ().contains ("/Contents/Frameworks" ))
683+ && !(p .toString ().contains ("dylib.dSYM/Contents" ))
684+ && !(p .toString ().endsWith (appExecutable ))
649685 ).forEach (p -> {
650686 // noinspection ThrowableResultOfMethodCallIgnored
651687 if (toThrow .get () != null ) return ;
@@ -654,12 +690,30 @@ static void signAppBundle(
654690 if (Files .isSymbolicLink (p )) {
655691 Log .verbose (MessageFormat .format (I18N .getString (
656692 "message.ignoring.symlink" ), p .toString ()));
657- } else if (isFileSigned (p )) {
658- // executable or lib already signed
659- Log .verbose (MessageFormat .format (I18N .getString (
660- "message.already.signed" ), p .toString ()));
661693 } else {
662- List <String > args = new ArrayList <>();
694+ List <String > args ;
695+ // runtime and Framework files will be signed below
696+ // but they need to be unsigned first here
697+ if ((p .toString ().contains ("/Contents/runtime" )) ||
698+ (p .toString ().contains ("/Contents/Frameworks" ))) {
699+
700+ args = new ArrayList <>();
701+ args .addAll (Arrays .asList ("/usr/bin/codesign" ,
702+ "--remove-signature" , p .toString ()));
703+ try {
704+ Set <PosixFilePermission > oldPermissions =
705+ Files .getPosixFilePermissions (p );
706+ p .toFile ().setWritable (true , true );
707+ ProcessBuilder pb = new ProcessBuilder (args );
708+ IOUtils .exec (pb );
709+ Files .setPosixFilePermissions (p ,oldPermissions );
710+ } catch (IOException ioe ) {
711+ Log .verbose (ioe );
712+ toThrow .set (ioe );
713+ return ;
714+ }
715+ }
716+ args = new ArrayList <>();
663717 args .addAll (Arrays .asList ("/usr/bin/codesign" ,
664718 "--timestamp" ,
665719 "--options" , "runtime" ,
@@ -670,25 +724,19 @@ static void signAppBundle(
670724 args .add ("--keychain" );
671725 args .add (keyChain );
672726 }
673-
674727 if (Files .isExecutable (p )) {
675728 if (entitlements != null ) {
676729 args .add ("--entitlements" );
677730 args .add (entitlements .toString ());
678731 }
679732 }
680-
681733 args .add (p .toString ());
682-
683734 try {
684735 Set <PosixFilePermission > oldPermissions =
685736 Files .getPosixFilePermissions (p );
686737 p .toFile ().setWritable (true , true );
687-
688738 ProcessBuilder pb = new ProcessBuilder (args );
689-
690739 IOUtils .exec (pb );
691-
692740 Files .setPosixFilePermissions (p , oldPermissions );
693741 } catch (IOException ioe ) {
694742 toThrow .set (ioe );
@@ -721,6 +769,10 @@ static void signAppBundle(
721769 args .add ("--keychain" );
722770 args .add (keyChain );
723771 }
772+ if (entitlements != null ) {
773+ args .add ("--entitlements" );
774+ args .add (entitlements .toString ());
775+ }
724776 args .add (path .toString ());
725777 ProcessBuilder pb = new ProcessBuilder (args );
726778
@@ -758,6 +810,7 @@ static void signAppBundle(
758810 "--options" , "runtime" ,
759811 "--force" ,
760812 "-s" , signingIdentity ,
813+ "--prefix" , identifierPrefix ,
761814 "-vvvv" ));
762815
763816 if (keyChain != null && !keyChain .isEmpty ()) {
@@ -778,20 +831,6 @@ static void signAppBundle(
778831 IOUtils .exec (pb );
779832 }
780833
781- private static boolean isFileSigned (Path file ) {
782- ProcessBuilder pb =
783- new ProcessBuilder ("/usr/bin/codesign" ,
784- "--verify" , file .toString ());
785-
786- try {
787- IOUtils .exec (pb );
788- } catch (IOException ex ) {
789- return false ;
790- }
791-
792- return true ;
793- }
794-
795834 private static String extractBundleIdentifier (Map <String , Object > params ) {
796835 if (PREDEFINED_APP_IMAGE .fetchFrom (params ) == null ) {
797836 return null ;
0 commit comments