@@ -72,7 +72,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
72
72
private static final ResourceBundle I18N = ResourceBundle .getBundle (
73
73
"jdk.jpackage.internal.resources.MacResources" );
74
74
75
- private static final String TEMPLATE_BUNDLE_ICON = "java .icns" ;
75
+ private static final String TEMPLATE_BUNDLE_ICON = "JavaApp .icns" ;
76
76
private static final String OS_TYPE_CODE = "APPL" ;
77
77
private static final String TEMPLATE_INFO_PLIST_LITE =
78
78
"Info-lite.plist.template" ;
@@ -102,6 +102,13 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
102
102
params -> null ,
103
103
(s , p ) -> s );
104
104
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
+
105
112
public static final BundlerParamInfo <String > MAC_CF_BUNDLE_IDENTIFIER =
106
113
new StandardBundlerParam <>(
107
114
Arguments .CLIOptions .MAC_BUNDLE_IDENTIFIER .getId (),
@@ -146,6 +153,38 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder {
146
153
null : Boolean .valueOf (s )
147
154
);
148
155
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
+
149
188
private static final StandardBundlerParam <String > FA_MAC_CFBUNDLETYPEROLE =
150
189
new StandardBundlerParam <>(
151
190
Arguments .MAC_CFBUNDLETYPEROLE ,
@@ -336,27 +375,14 @@ private void sign(Map<String, ? super Object> params) throws IOException {
336
375
String signingIdentity =
337
376
DEVELOPER_ID_APP_SIGNING_KEY .fetchFrom (params );
338
377
if (signingIdentity != null ) {
339
- prepareEntitlements (params );
340
378
signAppBundle (params , root , signingIdentity ,
341
379
BUNDLE_ID_SIGNING_PREFIX .fetchFrom (params ),
342
- getConfig_Entitlements (params ));
380
+ ENTITLEMENTS . fetchFrom (params ));
343
381
}
344
382
restoreKeychainList (params );
345
383
}
346
384
}
347
385
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
-
360
386
private static String getLauncherName (Map <String , ? super Object > params ) {
361
387
return APP_NAME .fetchFrom (params );
362
388
}
@@ -391,8 +417,17 @@ private void writeRuntimeInfoPlist(Path file,
391
417
String name = StandardBundlerParam .isRuntimeInstaller (params ) ?
392
418
getBundleName (params ): "Java Runtime Image" ;
393
419
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 );
396
431
397
432
createResource (TEMPLATE_RUNTIME_INFO_PLIST , params )
398
433
.setPublicName ("Runtime-Info.plist" )
@@ -443,6 +478,8 @@ private void writeInfoPlist(Path file, Map<String, ? super Object> params)
443
478
data .put ("DEPLOY_LAUNCHER_NAME" , getLauncherName (params ));
444
479
data .put ("DEPLOY_BUNDLE_SHORT_VERSION" , VERSION .fetchFrom (params ));
445
480
data .put ("DEPLOY_BUNDLE_CFBUNDLE_VERSION" , VERSION .fetchFrom (params ));
481
+ data .put ("DEPLOY_APP_CATEGORY" , "public.app-category." +
482
+ APP_CATEGORY .fetchFrom (params ));
446
483
447
484
StringBuilder bundleDocumentTypes = new StringBuilder ();
448
485
StringBuilder exportedTypes = new StringBuilder ();
@@ -643,9 +680,8 @@ static void signAppBundle(
643
680
}
644
681
}).filter (p -> Files .isRegularFile (p ) &&
645
682
(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 ))
649
685
).forEach (p -> {
650
686
// noinspection ThrowableResultOfMethodCallIgnored
651
687
if (toThrow .get () != null ) return ;
@@ -654,12 +690,30 @@ static void signAppBundle(
654
690
if (Files .isSymbolicLink (p )) {
655
691
Log .verbose (MessageFormat .format (I18N .getString (
656
692
"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 ()));
661
693
} 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 <>();
663
717
args .addAll (Arrays .asList ("/usr/bin/codesign" ,
664
718
"--timestamp" ,
665
719
"--options" , "runtime" ,
@@ -670,25 +724,19 @@ static void signAppBundle(
670
724
args .add ("--keychain" );
671
725
args .add (keyChain );
672
726
}
673
-
674
727
if (Files .isExecutable (p )) {
675
728
if (entitlements != null ) {
676
729
args .add ("--entitlements" );
677
730
args .add (entitlements .toString ());
678
731
}
679
732
}
680
-
681
733
args .add (p .toString ());
682
-
683
734
try {
684
735
Set <PosixFilePermission > oldPermissions =
685
736
Files .getPosixFilePermissions (p );
686
737
p .toFile ().setWritable (true , true );
687
-
688
738
ProcessBuilder pb = new ProcessBuilder (args );
689
-
690
739
IOUtils .exec (pb );
691
-
692
740
Files .setPosixFilePermissions (p , oldPermissions );
693
741
} catch (IOException ioe ) {
694
742
toThrow .set (ioe );
@@ -721,6 +769,10 @@ static void signAppBundle(
721
769
args .add ("--keychain" );
722
770
args .add (keyChain );
723
771
}
772
+ if (entitlements != null ) {
773
+ args .add ("--entitlements" );
774
+ args .add (entitlements .toString ());
775
+ }
724
776
args .add (path .toString ());
725
777
ProcessBuilder pb = new ProcessBuilder (args );
726
778
@@ -758,6 +810,7 @@ static void signAppBundle(
758
810
"--options" , "runtime" ,
759
811
"--force" ,
760
812
"-s" , signingIdentity ,
813
+ "--prefix" , identifierPrefix ,
761
814
"-vvvv" ));
762
815
763
816
if (keyChain != null && !keyChain .isEmpty ()) {
@@ -778,20 +831,6 @@ static void signAppBundle(
778
831
IOUtils .exec (pb );
779
832
}
780
833
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
-
795
834
private static String extractBundleIdentifier (Map <String , Object > params ) {
796
835
if (PREDEFINED_APP_IMAGE .fetchFrom (params ) == null ) {
797
836
return null ;
0 commit comments