PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/com/yifanlu/PSXperiaTool/ApkBuilder.java

https://github.com/TheShadowOne/PSXperia
Java | 139 lines | 106 code | 16 blank | 17 comment | 11 complexity | e507369b5b62866ff167514f74bdbcde MD5 | raw file
  1. /*
  2. * PSXperia Converter Tool - Logging
  3. * Copyright (C) 2011 Yifan Lu (http://yifan.lu/)
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. package com.yifanlu.PSXperiaTool;
  19. import com.android.sdklib.internal.build.SignedJarBuilder;
  20. import java.io.*;
  21. import java.security.*;
  22. import java.security.cert.CertificateException;
  23. import java.security.cert.X509Certificate;
  24. import java.util.Arrays;
  25. public class ApkBuilder {
  26. private static final String ALIAS = "signPSXperia";
  27. private static final char[] KEYSTORE_PASSWORD = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
  28. private static final char[] ALIAS_PASSWORD = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
  29. public static final String VERSION = "0.3 Beta 2";
  30. private File mInputDir;
  31. private File mOutputApk;
  32. public ApkBuilder(File inputDir, File outputApk){
  33. this.mInputDir = inputDir;
  34. this.mOutputApk = outputApk;
  35. }
  36. public void buildApk() throws IOException, InterruptedException, GeneralSecurityException, SignedJarBuilder.IZipEntryFilter.ZipAbortException {
  37. String os = System.getProperty("os.name");
  38. Logger.verbose("Your OS: %s", os);
  39. File aaptTool;
  40. if(os.equals("Mac OS X"))
  41. aaptTool = new File("./aapt-osx");
  42. else if(os.startsWith("Windows"))
  43. aaptTool = new File("./aapt-windows.exe");
  44. else if(os.equals("Linux"))
  45. aaptTool = new File("./aapt-linux");
  46. else {
  47. Logger.warning("Does not understand OS name '%s', assuming to be Linux", os);
  48. aaptTool = new File("./aapt-linux");
  49. }
  50. InputStream in = PSXperiaTool.class.getResourceAsStream("/resources/" + aaptTool.getName());
  51. Logger.verbose("Extracting %s", aaptTool.getPath());
  52. writeStreamToFile(in, aaptTool);
  53. in.close();
  54. aaptTool.setExecutable(true);
  55. File androidFrameworkJar = new File("./android-framework.jar");
  56. Logger.verbose("Extracting %s", androidFrameworkJar.getPath());
  57. in = PSXperiaTool.class.getResourceAsStream("/resources/android-framework.jar");
  58. writeStreamToFile(in, androidFrameworkJar);
  59. in.close();
  60. File tempApk = new File(mOutputApk.getPath() + ".unsigned");
  61. String[] cmd = new String[12];
  62. cmd[0] = (aaptTool.getPath());
  63. cmd[1] = ("package");
  64. cmd[2] = ("-f");
  65. cmd[3] = ("-F");
  66. cmd[4] = (tempApk.getPath());
  67. cmd[5] = ("-S");
  68. cmd[6] = ((new File(mInputDir, "/res")).getPath());
  69. cmd[7] = ("-M");
  70. cmd[8] = ((new File(mInputDir, "/assets/AndroidManifest.xml")).getPath());
  71. cmd[9] = ("-I");
  72. cmd[10] = (androidFrameworkJar.getPath());
  73. cmd[11] = (mInputDir.getPath());
  74. Logger.debug("Running command: " + Arrays.toString(cmd).replaceAll("\\,", ""));
  75. runCmdWithOutput(cmd);
  76. Logger.info("Signing apk %s to %s", tempApk.getPath(), mOutputApk.getPath());
  77. signApk(tempApk);
  78. Logger.verbose("Cleaning up signing stuff.");
  79. tempApk.delete();
  80. androidFrameworkJar.delete();
  81. aaptTool.delete();
  82. }
  83. private void writeStreamToFile(InputStream in, File outFile) throws IOException {
  84. Logger.verbose("Writing to: %s", outFile.getPath());
  85. FileOutputStream out = new FileOutputStream(outFile);
  86. byte[] buffer = new byte[1024];
  87. int n;
  88. while((n = in.read(buffer)) != -1){
  89. out.write(buffer, 0, n);
  90. }
  91. out.close();
  92. }
  93. public static void runCmdWithOutput(String[] cmd) throws IOException, InterruptedException {
  94. Process ps = Runtime.getRuntime().exec(cmd);
  95. BufferedReader in = new BufferedReader(new InputStreamReader(ps.getErrorStream()));
  96. String line;
  97. while ((line = in.readLine()) != null) {
  98. Logger.debug(line);
  99. }
  100. in.close();
  101. if (ps.waitFor() != 0) {
  102. throw new IOException("Executable did not return without error.");
  103. }
  104. }
  105. private void signApk(File unsignedApk) throws IOException, GeneralSecurityException, SignedJarBuilder.IZipEntryFilter.ZipAbortException {
  106. FileInputStream in = new FileInputStream(unsignedApk);
  107. FileOutputStream out = new FileOutputStream(mOutputApk);
  108. KeyStore ks = getKeyStore();
  109. PrivateKey key = (PrivateKey)ks.getKey(ALIAS, ALIAS_PASSWORD);
  110. X509Certificate cert = (X509Certificate)ks.getCertificate(ALIAS);
  111. SignedJarBuilder builder = new SignedJarBuilder(out, key, cert);
  112. builder.writeZip(in, null);
  113. builder.close();
  114. out.close();
  115. in.close();
  116. }
  117. private KeyStore getKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
  118. KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
  119. InputStream is = PSXperiaTool.class.getResourceAsStream("/resources/signApk.keystore");
  120. ks.load(is, KEYSTORE_PASSWORD);
  121. return ks;
  122. }
  123. }