通过Java实现apk 解压、修改、打包、签名

转载请注明:安度博客 » 通过Java实现apk 解压、修改、打包、签名

通过Runtime.getRuntime().exec 调用命令的方式对APK进行 解压、打包、签名。此文不同之处在于应用java.util.zip对APK进行解压、打包,感觉说得有点多,直接上代码。 

 

 
 
  1. import java.io.BufferedInputStream;
  2. import java.io.BufferedOutputStream;
  3. import java.io.BufferedReader;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileOutputStream;
  7. import java.io.InputStreamReader;
  8. import java.io.OutputStreamWriter;
  9. import java.util.Enumeration;
  10. import java.util.zip.CRC32;
  11. import java.util.zip.CheckedOutputStream;
  12. import java.util.zip.ZipOutputStream;
  13.  
  14. import org.apache.tools.zip.ZipEntry;
  15. import org.apache.tools.zip.ZipFile;
  16.  
  17. /**
  18. * @author showlike
  19. * @version v1.0
  20. * 2012-9-28 上午11:03:36
  21. * explain : 文件解压/打包工具
  22. */
  23. public class ZipUtil {
  24. private static final int BUFFER = 1024;
  25. private static final String BASE_DIR = "";
  26. /**符号"/"用来作为目录标识判断符*/
  27. private static final String PATH = "/";
  28. /**签名目录*/
  29. private static final String SIGN_PATH_NAME = "META-INF";
  30. /**修改文件目录*/
  31. private static final String UPDATE_PATH_NAME = "\\res\\raw\\channel";
  32. /**解压源文件目录*/
  33. private static final String SOURCE_PATH_NAME = "\\source\\";
  34. /**打包目录*/
  35. private static final String TARGET_PATH_NAME = "\\target\\";
  36. /**签名目录*/
  37. private static final String RESULT_PATH_NAME = "\\result\\";
  38. /**JDK BIN 目录*/
  39. private static final String JDK_BIN_PATH = "C:\\Program Files\\Java\\jdk1.6.0_26\\bin";
  40. /**密钥 目录*/
  41. private static final String SECRET_KEY_PATH = "F:\\document\\APK\\";
  42. /**密钥 名称*/
  43. private static final String SECRET_KEY_NAME = "sdk.keystore";
  44. /**
  45. * 解压缩zip文件
  46. * @param fileName 要解压的文件名 包含路径 如:"c:\\test.zip"
  47. * @param filePath 解压后存放文件的路径 如:"c:\\temp"
  48. * @throws Exception
  49. */
  50. @SuppressWarnings("rawtypes")
  51. public static void unZip(String fileName, String filePath) throws Exception{
  52. ZipFile zipFile = new ZipFile(fileName);
  53. Enumeration emu = zipFile.getEntries();
  54. while(emu.hasMoreElements()){
  55. ZipEntry entry = (ZipEntry) emu.nextElement();
  56. if (entry.isDirectory()){
  57. new File(filePath+entry.getName()).mkdirs();
  58. continue;
  59. }
  60. BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
  61. File file = new File(filePath + entry.getName());
  62. File parent = file.getParentFile();
  63. if(parent != null && (!parent.exists())){
  64. parent.mkdirs();
  65. }
  66. FileOutputStream fos = new FileOutputStream(file);
  67. BufferedOutputStream bos = new BufferedOutputStream(fos,BUFFER);
  68. byte [] buf = new byte[BUFFER];
  69. int len = 0;
  70. while((len=bis.read(buf,0,BUFFER))!=-1){
  71. fos.write(buf,0,len);
  72. }
  73. bos.flush();
  74. bos.close();
  75. bis.close();
  76. }
  77. zipFile.close();
  78. }
  79. /**
  80. * 压缩文件
  81. *
  82. * @param srcFile
  83. * @param destPath
  84. * @throws Exception
  85. */
  86. public static void compress(String srcFile, String destPath) throws Exception {
  87. compress(new File(srcFile), new File(destPath));
  88. }
  89. /**
  90. * 压缩
  91. *
  92. * @param srcFile
  93. * 源路径
  94. * @param destPath
  95. * 目标路径
  96. * @throws Exception
  97. */
  98. public static void compress(File srcFile, File destFile) throws Exception {
  99. // 对输出文件做CRC32校验
  100. CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(
  101. destFile), new CRC32());
  102.  
  103. ZipOutputStream zos = new ZipOutputStream(cos);
  104. compress(srcFile, zos, BASE_DIR);
  105.  
  106. zos.flush();
  107. zos.close();
  108. }
  109. /**
  110. * 压缩
  111. *
  112. * @param srcFile
  113. * 源路径
  114. * @param zos
  115. * ZipOutputStream
  116. * @param basePath
  117. * 压缩包内相对路径
  118. * @throws Exception
  119. */
  120. private static void compress(File srcFile, ZipOutputStream zos,
  121. String basePath) throws Exception {
  122. if (srcFile.isDirectory()) {
  123. compressDir(srcFile, zos, basePath);
  124. } else {
  125. compressFile(srcFile, zos, basePath);
  126. }
  127. }
  128. /**
  129. * 压缩目录
  130. *
  131. * @param dir
  132. * @param zos
  133. * @param basePath
  134. * @throws Exception
  135. */
  136. private static void compressDir(File dir, ZipOutputStream zos,
  137. String basePath) throws Exception {
  138. File[] files = dir.listFiles();
  139. // 构建空目录
  140. if (files.length < 1) {
  141. ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);
  142.  
  143. zos.putNextEntry(entry);
  144. zos.closeEntry();
  145. }
  146. String dirName = "";
  147. String path = "";
  148. for (File file : files) {
  149. //当父文件包名为空时,则不把包名添加至路径中(主要是解决压缩时会把父目录文件也打包进去)
  150. if(basePath!=null && !"".equals(basePath)){
  151. dirName=dir.getName();
  152. }
  153. path = basePath + dirName + PATH;
  154. // 递归压缩
  155. compress(file, zos, path);
  156. }
  157. }
  158.  
  159. /**
  160. * 文件压缩
  161. *
  162. * @param file
  163. * 待压缩文件
  164. * @param zos
  165. * ZipOutputStream
  166. * @param dir
  167. * 压缩文件中的当前路径
  168. * @throws Exception
  169. */
  170. private static void compressFile(File file, ZipOutputStream zos, String dir)
  171. throws Exception {
  172. /**
  173. * 压缩包内文件名定义
  174. *
  175. *
  176. * 如果有多级目录,那么这里就需要给出包含目录的文件名
  177. * 如果用WinRAR打开压缩包,中文名将显示为乱码
  178. *
  179. */
  180. if("/".equals(dir))dir="";
  181. else if(dir.startsWith("/"))dir=dir.substring(1,dir.length());
  182.  
  183. ZipEntry entry = new ZipEntry(dir + file.getName());
  184. zos.putNextEntry(entry);
  185. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
  186. int count;
  187. byte data[] = new byte[BUFFER];
  188. while ((count = bis.read(data, 0, BUFFER)) != -1) {
  189. zos.write(data, 0, count);
  190. }
  191. bis.close();
  192.  
  193. zos.closeEntry();
  194. }
  195.  
  196. public static void main(String[] args)throws Exception{
  197. StringBuffer buffer = new StringBuffer();
  198. BufferedReader br =null;
  199. OutputStreamWriter osw =null;
  200. String srcPath = "F:\\document\\APK\\new\\iGouShop.apk";
  201. String content= "channel_id=LD20120926";
  202.  
  203. File srcFile = new File(srcPath);
  204. String parentPath = srcFile.getParent(); //源文件目录
  205. String fileName = srcFile.getName(); //源文件名称
  206. String prefixName = fileName.substring(0, fileName.lastIndexOf("."));
  207. //解压源文件保存路径
  208. String sourcePath = buffer.append(parentPath).append(SOURCE_PATH_NAME).
  209. append(prefixName).append("\\").toString();
  210.  
  211. //------解压
  212. unZip(srcPath, sourcePath);
  213.  
  214. //------删除解压后的签名文件
  215. String signPathName = sourcePath+SIGN_PATH_NAME;
  216. File signFile = new File(signPathName);
  217. if(signFile.exists()){
  218. File sonFiles[] = signFile.listFiles();
  219. if(sonFiles!=null && sonFiles.length>0){
  220. //循环删除签名目录下的文件
  221. for(File f : sonFiles){
  222. f.delete();
  223. }
  224. }
  225. signFile.delete();
  226. }
  227.  
  228. //------修改内容
  229. buffer.setLength(0);
  230. String path = buffer.append(parentPath).append(SOURCE_PATH_NAME)
  231. .append(prefixName).append(UPDATE_PATH_NAME).toString();
  232. br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
  233. while((br.readLine())!=null)
  234. {
  235. osw = new OutputStreamWriter(new FileOutputStream(path));
  236. osw.write(content,0,content.length());
  237. osw.flush();
  238. }
  239.  
  240. //------打包
  241. String targetPath = parentPath+TARGET_PATH_NAME;
  242. //判断创建文件夹
  243. File targetFile = new File(targetPath);
  244. if(!targetFile.exists()){
  245. targetFile.mkdir();
  246. }
  247. compress(parentPath+SOURCE_PATH_NAME+prefixName,targetPath+fileName);
  248.  
  249. //------签名
  250. File ff =new File(JDK_BIN_PATH);
  251. String resultPath = parentPath+RESULT_PATH_NAME;
  252. //判断创建文件夹
  253. File resultFile = new File(resultPath);
  254. if(!resultFile.exists()){
  255. resultFile.mkdir();
  256. }
  257.  
  258. //组合签名命令
  259. buffer.setLength(0);
  260. buffer.append("cmd.exe /c jarsigner -keystore ")
  261. .append(SECRET_KEY_PATH).append(SECRET_KEY_NAME)
  262. .append(" -storepass winadsdk -signedjar ")
  263. .append(resultPath).append(fileName).append(" ") //签名保存路径应用名称
  264. .append(targetPath).append(fileName).append(" ") //打包保存路径应用名称
  265. .append(SECRET_KEY_NAME);
  266. //利用命令调用JDK工具命令进行签名
  267. Process process = Runtime.getRuntime().exec(buffer.toString(),null,ff);
  268. if(process.waitFor()!=0)System.out.println("文件打包失败!!!");
  269. }
  270. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值