采用Ant打包的完美实现:编译、合并、签名、混淆、优化、自动运行对Android App快速实现自动打包进行了详细的说明,本篇在此基础上对APP的批量打包、发布进行简要的实现说明,方便进行以下场景的APP打包:
- 同一个APP,不同版本、不同内容的APK包
- 不同的APP,相应的APK包
通常可能会想到依旧采用ANT、BAT等方式来进行批量的打包处理,但事实上此类方式多数情况下打包的不够灵活(比如BAT的跨平台、打包过程中的一些特殊事务处理等),因此有必要进行自定义Application的方式来完成,总体事务处理结构如下:
-build 输出目录
-conf 打包配置目录
--weixin 某个APK待打包的资源信息目录
--res 以res为例,可放置任何其他需要的打包资源
--drawable-hdpi
--xxx
--drawable-mdpi
--xxx
--alipay
-build.xml 该文件仅包含当次需打包的所有APK配置信息
-template 模板目录
--weixin
--alipay
-complier.jar 为本文事务处理的可执行JAR包
实现思路:
- 读取用户输入指令 --> 用以进行交互性处理,比如编译完成后自动安装、自动运行等。
- 启动异步处理线程
- 读取批量的打包配置信息 --> 以JSON格式存储
- 反序列化配置信息
- 进行打包前事务处理 --> 删除编译历史、创建编译输出目录等
- 遍历打包配置项 ---foreach开始---
- 解析打包配置项
- 拷贝模板到build目录
- 替换或合并build目录中当前APK的资源
- 替换APK中某类或所有类型文件的模板变量信息 --> 如项目名、包名、版本信息、action等。
- 运行编译指令 --> linux、windows差别仅在于此
- 将打包后的APK文件复制到build主目录
- 显示编译打包时间
- 根据指令决定是否安装、运行APK
- 进行下一个编译事项 ---foreach结束---
- 显示事务整体处理耗时
读取用户输入:
/* * 读取用户输入 * @param prompt 提示文字 * @return 用户输入 */ private static String readUserInput(String prompt) { try { // 先定义接受用户输入的变量 String result; do { // 输出提示文字 System.out.print(prompt); InputStreamReader is_reader = new InputStreamReader(System.in); result = new BufferedReader(is_reader).readLine(); } while (isInvalid(result)); // 当用户输入无效的时候,反复提示要求用户输入 return result; } catch (IOException e) { e.printStackTrace(); } return ""; } private static boolean isInvalid(String str) { return str.equals(""); }
运行编译指令:ant -f .../build.xml clean release
public static void runbatwithmsg(String batName) { try { System.out.println("batName:" + batName); Process ps = Runtime.getRuntime().exec(batName); InputStream in = ps.getInputStream(); int c; while ((c = in.read()) != -1) { if (((char) c) != '\r') { System.out.print((char) c); } } in.close(); ps.waitFor(); } catch (IOException ioe) { ioe.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("child thread done"); }
文件、目录类相关:
public class FileUtils { /** * 复制单个文件 * * @param oldPath * String 原文件路径 如:c:/fqf.txt * @param newPath * String 复制后路径 如:f:/fqf.txt * @return boolean */ public static void copyFile(String oldPath, String newPath) { try { int byteread = 0; File oldfile = new File(oldPath); if (oldfile.exists()) { // 文件存在时 InputStream inStream = new FileInputStream(oldPath); // 读入原文件 FileOutputStream fs = new FileOutputStream(newPath); byte[] buffer = new byte[1024 * 10]; while ((byteread = inStream.read(buffer)) != -1) { fs.write(buffer, 0, byteread); } fs.flush(); fs.close(); inStream.close(); } } catch (Exception e) { System.out.println("复制单个文件操作出错"); e.printStackTrace(); } } /** * 复制整个文件夹内容 * * @param oldPath * String 原文件路径 如:c:/fqf * @param newPath * String 复制后路径 如:f:/fqf/ff * @return boolean */ public static void copyFolder(String oldPath, String newPath) { try { (new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹 File a = new File(oldPath); String[] file = a.list(); File temp = null; for (int i = 0; i < file.length; i++) { if (oldPath.endsWith(File.separator)) { temp = new File(oldPath + file[i]); } else { temp = new File(oldPath + File.separator + file[i]); } if (temp.isFile()) { FileInputStream input = new FileInputStream(temp); FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString()); byte[] b = new byte[1024 * 5]; int len; while ((len = input.read(b)) != -1) { output.write(b, 0, len); } output.flush(); output.close(); input.close(); } if (temp.isDirectory()) {// 如果是子文件夹 copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]); } } } catch (Exception e) { System.out.println("复制整个文件夹内容操作出错"); e.printStackTrace(); } } /** * 获得可编辑的文件列表 * * @param files * @param path */ public static void getName(List<String> files, String path) { File file = new File(path); if (file.isDirectory()) { File[] dirFile = file.listFiles(); for (File f : dirFile) { if (f.isDirectory()) getName(files, f.getAbsolutePath()); else { if (f.getName().endsWith(".java") || f.getName().endsWith(".xml") || f.getName().endsWith(".bat")) files.add(f.getAbsolutePath()); } } } } /** * 读取文件中内容 * * @param path * @return * @throws IOException */ public static String readFileToString(String path) throws IOException { String resultStr = null; FileInputStream fis = null; BufferedReader buf = null; try { fis = new FileInputStream(path); String line = null; buf = new BufferedReader(new InputStreamReader(fis, "UTF-8")); StringBuilder sb = new StringBuilder(); while ((line = buf.readLine()) != null) { sb.append(line); } return sb.toString(); } finally { if (fis != null) fis.close(); } } public static String ReadTxtFile(String FileName) { try { BufferedInputStream bufferedInputStream = new BufferedInputStream( new FileInputStream(FileName)); ByteArrayOutputStream memStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = bufferedInputStream.read(buffer)) != -1) { memStream.write(buffer, 0, len); } byte[] data = memStream.toByteArray(); bufferedInputStream.close(); memStream.close(); bufferedInputStream.close(); return new String(data, "GBK"); } catch (Exception e) { e.printStackTrace(); } return ""; } public static void deleteDir(String path, boolean bDelRoot) { File dir = new File(path); if (dir.exists() && dir.isDirectory()) { File[] tmp = dir.listFiles(); if (null != tmp) { for (int i = 0; i < tmp.length; i++) { if (tmp[i].isDirectory()) { deleteDir(path + "/" + tmp[i].getName(), true); } else { tmp[i].delete(); } } } if (bDelRoot) { dir.delete(); } } } public static void deleteFile(String file) { File f = new File(file); f.delete(); } public static BufferedOutputStream getOutputStream(File file) throws IOException { return new BufferedOutputStream(new FileOutputStream(file), 64 * 1024); } public static BufferedOutputStream getOutputStream(String file) throws IOException { return getOutputStream(new File(file)); } public static void close(OutputStream out) { if (null != out) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } out = null; } } public static void close(InputStream in) { if (null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } in = null; } } private static void createDirIfNotExist(File file) { if (null == file) return; if (!file.exists()) { File parentFile = file.getParentFile(); if (!parentFile.exists()) { parentFile.mkdirs(); } } } public static void createDirIfNotExist(String filePath) { File file = new File(filePath); createDirIfNotExist(file); } public static void writeFile(String str, String descFile, boolean append) throws Exception { if ((null == str) || (null == descFile)) { return; } createDirIfNotExist(descFile); BufferedOutputStream out = null; try { byte[] src = str.getBytes("UTF-8"); out = new BufferedOutputStream(new FileOutputStream(descFile, append), 1024 * 64); out.write(src); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { close(out); } } public static void appendFile(String str, String descFile) throws Exception { writeFile(str, descFile, true); } }