|
21 | 21 |
|
22 | 22 | package processing.mode.android; |
23 | 23 |
|
24 | | -import java.io.*; |
25 | | - |
26 | | -import org.apache.tools.ant.*; |
27 | | - |
28 | | -import processing.app.*; |
29 | | -import processing.app.exec.*; |
| 24 | +import org.apache.tools.ant.BuildException; |
| 25 | +import org.apache.tools.ant.DefaultLogger; |
| 26 | +import org.apache.tools.ant.Project; |
| 27 | +import org.apache.tools.ant.ProjectHelper; |
| 28 | +import processing.app.Base; |
| 29 | +import processing.app.Library; |
| 30 | +import processing.app.Sketch; |
| 31 | +import processing.app.SketchException; |
| 32 | +import processing.app.exec.ProcessHelper; |
| 33 | +import processing.app.exec.ProcessResult; |
30 | 34 | import processing.core.PApplet; |
31 | 35 | import processing.mode.java.JavaBuild; |
32 | 36 |
|
| 37 | +import java.io.*; |
| 38 | +import java.security.Permission; |
| 39 | + |
33 | 40 |
|
34 | 41 | class AndroidBuild extends JavaBuild { |
35 | 42 | // static final String basePackage = "changethispackage.beforesubmitting.tothemarket"; |
@@ -267,20 +274,95 @@ public File exportProject() throws IOException, SketchException { |
267 | 274 | return null; |
268 | 275 | } |
269 | 276 |
|
270 | | - |
271 | | - public boolean exportPackage() throws IOException, SketchException { |
| 277 | + public File exportPackage(String keyStorePassword) throws Exception { |
272 | 278 | File projectFolder = build("release"); |
273 | | - if (projectFolder == null) { |
274 | | - return false; |
275 | | - } |
| 279 | + if(projectFolder == null) return null; |
276 | 280 |
|
277 | | - // TODO all the signing magic needs to happen here |
| 281 | + File signedPackage = signPackage(projectFolder, keyStorePassword); |
| 282 | + if(signedPackage == null) return null; |
278 | 283 |
|
279 | 284 | File exportFolder = createExportFolder(); |
280 | 285 | Base.copyDir(projectFolder, exportFolder); |
281 | | - return true; |
| 286 | + return new File(exportFolder, "/bin/"); |
| 287 | + } |
| 288 | + |
| 289 | + private File signPackage(File projectFolder, String keyStorePassword) throws Exception { |
| 290 | + File keyStore = AndroidKeyStore.getKeyStore(); |
| 291 | + if(keyStore == null) return null; |
| 292 | + |
| 293 | + File unsignedPackage = new File(projectFolder, "bin/" + sketch.getName() + "-release-unsigned.apk"); |
| 294 | + if(!unsignedPackage.exists()) return null; |
| 295 | + |
| 296 | + JarSigner.signJar(unsignedPackage, AndroidKeyStore.ALIAS_STRING, keyStorePassword, keyStore.getAbsolutePath(), keyStorePassword); |
| 297 | + |
| 298 | + //if(verifySignedPackage(unsignedPackage)) { |
| 299 | + File signedPackage = new File(projectFolder, "bin/" + sketch.getName() + "-release-signed.apk"); |
| 300 | + if(signedPackage.exists()) { |
| 301 | + boolean deleteResult = signedPackage.delete(); |
| 302 | + if(!deleteResult) { |
| 303 | + Base.showWarning("Error during package signing", |
| 304 | + "Unable to delete old signed package"); |
| 305 | + return null; |
| 306 | + } |
| 307 | + } |
| 308 | + |
| 309 | + boolean renameResult = unsignedPackage.renameTo(signedPackage); |
| 310 | + if(!renameResult) { |
| 311 | + Base.showWarning("Error during package signing", |
| 312 | + "Unable to rename package file"); |
| 313 | + return null; |
| 314 | + } |
| 315 | + |
| 316 | + File alignedPackage = zipalignPackage(signedPackage, projectFolder); |
| 317 | + return alignedPackage; |
| 318 | + /*} else { |
| 319 | + Base.showWarning("Error during package signing", |
| 320 | + "Verification of the signed package has failed"); |
| 321 | + return null; |
| 322 | + }*/ |
282 | 323 | } |
283 | 324 |
|
| 325 | + /*private boolean verifySignedPackage(File signedPackage) throws Exception { |
| 326 | + String[] args = { |
| 327 | + "-verify", signedPackage.getCanonicalPath() |
| 328 | + }; |
| 329 | +
|
| 330 | + PrintStream defaultPrintStream = System.out; |
| 331 | +
|
| 332 | + ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| 333 | + PrintStream printStream = new PrintStream(baos); |
| 334 | + System.setOut(printStream); |
| 335 | +
|
| 336 | + SystemExitControl.forbidSystemExitCall(); |
| 337 | + try { |
| 338 | + JarSigner.main(args); |
| 339 | + } catch (SystemExitControl.ExitTrappedException ignored) { } |
| 340 | + SystemExitControl.enableSystemExitCall(); |
| 341 | +
|
| 342 | + System.setOut(defaultPrintStream); |
| 343 | + String result = baos.toString(); |
| 344 | +
|
| 345 | + baos.close(); |
| 346 | + printStream.close(); |
| 347 | +
|
| 348 | + return result.contains("verified"); |
| 349 | + } */ |
| 350 | + |
| 351 | + private File zipalignPackage(File signedPackage, File projectFolder) throws IOException, InterruptedException { |
| 352 | + String zipalignPath = sdk.getSdkFolder().getAbsolutePath() + "/tools/zipalign"; |
| 353 | + File alignedPackage = new File(projectFolder, "bin/" + sketch.getName() + "-release-signed-aligned.apk"); |
| 354 | + |
| 355 | + String[] args = { |
| 356 | + zipalignPath, "-v", "-f", "4", |
| 357 | + signedPackage.getAbsolutePath(), alignedPackage.getAbsolutePath() |
| 358 | + }; |
| 359 | + |
| 360 | + Process alignProcess = Runtime.getRuntime().exec(args); |
| 361 | + alignProcess.waitFor(); |
| 362 | + |
| 363 | + if(alignedPackage.exists()) return alignedPackage; |
| 364 | + return null; |
| 365 | + } |
284 | 366 |
|
285 | 367 | /* |
286 | 368 | // SDK tools 17 have a problem where 'dex' won't pick up the libs folder |
@@ -815,3 +897,26 @@ public void cleanup() { |
815 | 897 | tmpFolder.deleteOnExit(); |
816 | 898 | } |
817 | 899 | } |
| 900 | + |
| 901 | +// http://www.avanderw.co.za/preventing-calls-to-system-exit-in-java/ |
| 902 | +class SystemExitControl { |
| 903 | + |
| 904 | + public static class ExitTrappedException extends SecurityException { |
| 905 | + } |
| 906 | + |
| 907 | + public static void forbidSystemExitCall() { |
| 908 | + final SecurityManager securityManager = new SecurityManager() { |
| 909 | + @Override |
| 910 | + public void checkPermission(Permission permission) { |
| 911 | + if (permission.getName().contains("exitVM")) { |
| 912 | + throw new ExitTrappedException(); |
| 913 | + } |
| 914 | + } |
| 915 | + }; |
| 916 | + System.setSecurityManager(securityManager); |
| 917 | + } |
| 918 | + |
| 919 | + public static void enableSystemExitCall() { |
| 920 | + System.setSecurityManager(null); |
| 921 | + } |
| 922 | +} |
0 commit comments