Skip to content

Commit 2fa0146

Browse files
committed
Implement signing and verifying packages
1 parent 08a0406 commit 2fa0146

File tree

1 file changed

+107
-3
lines changed

1 file changed

+107
-3
lines changed

src/processing/mode/android/AndroidBuild.java

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,116 @@ public File exportPackage() throws IOException, SketchException, InterruptedExce
277277
File projectFolder = build("release");
278278
if(projectFolder == null) return null;
279279

280-
File keyStore = getKeyStore();
281-
if(keyStore == null) return null;
280+
File signedPackage = signPackage();
281+
if(signedPackage == null) return null;
282282

283283
File exportFolder = createExportFolder();
284284
Base.copyDir(projectFolder, exportFolder);
285285
return new File(exportFolder, "/bin/");
286286
}
287287

288+
String combine(String[] s, String glue)
289+
{
290+
int k = s.length;
291+
if ( k == 0 )
292+
{
293+
return null;
294+
}
295+
StringBuilder out = new StringBuilder();
296+
out.append( s[0] );
297+
for ( int x=1; x < k; ++x )
298+
{
299+
out.append(glue).append(s[x]);
300+
}
301+
return out.toString();
302+
}
303+
304+
private File signPackage() throws IOException, InterruptedException {
305+
File keyStore = getKeyStore();
306+
if(keyStore == null) return null;
307+
308+
File unsignedPackage = new File(sketch.getFolder(), "android/bin/" + sketch.getName() + "-release-unsigned.apk");
309+
if(!unsignedPackage.exists()) return null;
310+
311+
// NOT sure that works: java.home returns JRE path here, need to walk back to ../../bin to find jarsigner
312+
// TODO receive generated password here
313+
String password = "generatedpasswordhere";
314+
315+
String[] args = {
316+
System.getProperty("java.home") + System.getProperty("file.separator") + ".."
317+
+ System.getProperty("file.separator") + "bin"
318+
+ System.getProperty("file.separator") + "jarsigner",
319+
"-sigalg", "SHA1withRSA",
320+
"-digestalg", "SHA1",
321+
"-keypass", password,
322+
"-storepass", password,
323+
"-keystore", keyStore.getCanonicalPath(),
324+
unsignedPackage.getCanonicalPath(),
325+
sketch.getName()
326+
};
327+
328+
System.out.println("Started signing process");
329+
System.out.println(combine(args, " "));
330+
331+
Process signingProcess = Runtime.getRuntime().exec(args);
332+
signingProcess.waitFor();
333+
334+
System.out.println("Finished signing process");
335+
336+
if(verifySignedPackage(unsignedPackage)) {
337+
File signedPackage = new File(sketch.getFolder(), "android/bin/" + sketch.getName() + "-release-signed.apk");
338+
if(signedPackage.exists()) {
339+
boolean deleteResult = signedPackage.delete();
340+
if(!deleteResult) {
341+
Base.showWarning("Error during package signing",
342+
"Unable to delete old signed package");
343+
return null;
344+
}
345+
}
346+
347+
boolean renameResult = unsignedPackage.renameTo(signedPackage);
348+
if(!renameResult) {
349+
Base.showWarning("Error during package signing",
350+
"Unable to rename package file");
351+
return null;
352+
}
353+
354+
// TODO zipalign package
355+
return signedPackage;
356+
} else {
357+
Base.showWarning("Error during package signing",
358+
"Verification of the signed package has failed");
359+
return null;
360+
}
361+
}
362+
363+
// probably not the best way to do it; should we really verify?
364+
private boolean verifySignedPackage(File signedPackage) throws IOException, InterruptedException {
365+
// same concerns about jarsigner path here as above
366+
String[] args = {
367+
System.getProperty("java.home") + System.getProperty("file.separator") + ".."
368+
+ System.getProperty("file.separator") + "bin"
369+
+ System.getProperty("file.separator") + "jarsigner",
370+
"-verify", signedPackage.getCanonicalPath()
371+
};
372+
373+
Process signingProcess = Runtime.getRuntime().exec(args);
374+
signingProcess.waitFor();
375+
376+
InputStream is = signingProcess.getInputStream();
377+
InputStreamReader isr = new InputStreamReader(is);
378+
BufferedReader br = new BufferedReader(isr);
379+
String line;
380+
381+
while((line = br.readLine()) != null) {
382+
if(line.contains("verified")) {
383+
return true;
384+
}
385+
}
386+
387+
return false;
388+
}
389+
288390
private File getKeyStore() throws IOException, InterruptedException {
289391
File keyStoreFolder = new File(sketch.getFolder(), "keystore");
290392
if(!keyStoreFolder.exists()) {
@@ -305,7 +407,9 @@ private File getKeyStore() throws IOException, InterruptedException {
305407
String password = "generatedpasswordhere";
306408

307409
String[] args = {
308-
"keytool", "-genkey",
410+
System.getProperty("java.home")
411+
+ System.getProperty("file.separator") + "bin"
412+
+ System.getProperty("file.separator") + "keytool", "-genkey",
309413
"-keystore", keyStore.getCanonicalPath(),
310414
"-alias", sketch.getName(),
311415
"-keyalg", "RSA",

0 commit comments

Comments
 (0)