Skip to content

Commit 11c8c78

Browse files
author
Andy Herrick
committed
8248904: Add support to jpackage for the Mac App Store
Reviewed-by: asemenyuk, almatvee, kizune, kcr
1 parent dc93138 commit 11c8c78

File tree

23 files changed

+269
-105
lines changed

23 files changed

+269
-105
lines changed

src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class LinuxAppImageBuilder extends AbstractAppImageBuilder {
5454
},
5555
(s, p) -> Path.of(s));
5656

57-
final static String DEFAULT_ICON = "java32.png";
57+
final static String DEFAULT_ICON = "JavaApp.png";
5858

5959
LinuxAppImageBuilder(Path imageOutDir) {
6060
super(imageOutDir);

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.Optional;
3232
import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
3333
import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER;
34+
import static jdk.jpackage.internal.MacAppImageBuilder.APP_STORE;
3435
import static jdk.jpackage.internal.StandardBundlerParam.MAIN_CLASS;
3536
import static jdk.jpackage.internal.StandardBundlerParam.VERBOSE;
3637
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
@@ -41,7 +42,7 @@ public MacAppBundler() {
4142
setParamsValidator(MacAppBundler::doValidate);
4243
}
4344

44-
private static final String TEMPLATE_BUNDLE_ICON = "java.icns";
45+
private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns";
4546

4647
public static final BundlerParamInfo<String> MAC_CF_BUNDLE_NAME =
4748
new StandardBundlerParam<>(
@@ -62,11 +63,20 @@ public MacAppBundler() {
6263
"mac.signing-key-developer-id-app",
6364
String.class,
6465
params -> {
65-
String result = MacBaseInstallerBundler.findKey(
66-
"Developer ID Application: ",
67-
SIGNING_KEY_USER.fetchFrom(params),
68-
SIGNING_KEYCHAIN.fetchFrom(params),
69-
VERBOSE.fetchFrom(params));
66+
String user = SIGNING_KEY_USER.fetchFrom(params);
67+
String keychain = SIGNING_KEYCHAIN.fetchFrom(params);
68+
String result = null;
69+
if (APP_STORE.fetchFrom(params)) {
70+
result = MacBaseInstallerBundler.findKey(
71+
"3rd Party Mac Developer Application: ",
72+
user, keychain);
73+
}
74+
// if either not signing for app store or couldn't find
75+
if (result == null) {
76+
result = MacBaseInstallerBundler.findKey(
77+
"Developer ID Application: ", user, keychain);
78+
}
79+
7080
if (result != null) {
7181
MacCertificate certificate = new MacCertificate(result);
7282

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java

Lines changed: 84 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,13 @@ public String getBundleType() {
152152
return "INSTALLER";
153153
}
154154

155-
public static String findKey(String keyPrefix, String teamName, String keychainName,
156-
boolean verbose) {
157-
String key = (teamName.startsWith(keyPrefix)
158-
|| teamName.startsWith("3rd Party Mac Developer"))
159-
? teamName : (keyPrefix + teamName);
160-
if (Platform.getPlatform() != Platform.MAC) {
161-
return null;
162-
}
155+
public static String findKey(String keyPrefix, String teamName, String keychainName) {
156+
157+
boolean useAsIs = teamName.startsWith(keyPrefix)
158+
|| teamName.startsWith("Developer ID")
159+
|| teamName.startsWith("3rd Party Mac");
160+
161+
String key = (useAsIs) ? teamName : (keyPrefix + teamName);
163162

164163
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
165164
PrintStream ps = new PrintStream(baos)) {

src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class MacDmgBundler extends MacBaseInstallerBundler {
5858
static final String BACKGROUND_IMAGE_FOLDER =".background";
5959
static final String BACKGROUND_IMAGE = "background.tiff";
6060
static final String DEFAULT_DMG_SETUP_SCRIPT = "DMGsetup.scpt";
61-
static final String TEMPLATE_BUNDLE_ICON = "java.icns";
61+
static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns";
6262

6363
static final String DEFAULT_LICENSE_PLIST="lic_template.plist";
6464

0 commit comments

Comments
 (0)