因爲公司運維須要以及應用中須要加上應用推廣的統計,每每要對應二三十個渠道,按照正常方法一個一個的去生成不一樣渠道包的應用,不只浪費了時間,並且大大下降了效率. java
上一篇講到使用Ant進行Zip/Tar包的解壓縮,實際上Ant工具不單單具備此類功能,它更強大的地方在於自動化調用程序完成項目的編譯,打包,測試等. 相似於C語言中的make腳本完成這些工做的批處理任務. 不一樣於MakeFile的是,Ant是純Java編寫的,所以具備很好的跨平臺性. android
在此我主要講下如何自動構建工具Ant, 對應用進行批量打包, 生成對應不一樣市場的應用: apache
首先分別看一下用於打包的Java工程AntTest和須要被打包進行發佈的Android工程結構: windows
market.txt裏保存須要打包的市場標識,如: app
youmeng 運維
gfan 工具
....... 測試
此文件裏自行根據需求添加渠道名稱. ui
而後看一下實現批量打包AntTest類中的內容: spa
注意:紅色標註部分須要進行修改:
package com.cn.ant; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; import org.apache.tools.ant.DefaultLogger; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; public class AntTest { private Project project; public void init(String _buildFile, String _baseDir) throws Exception { project = new Project(); project.init(); DefaultLogger consoleLogger = new DefaultLogger(); consoleLogger.setErrorPrintStream(System.err); consoleLogger.setOutputPrintStream(System.out); consoleLogger.setMessageOutputLevel(Project.MSG_INFO); project.addBuildListener(consoleLogger); // Set the base directory. If none is given, "." is used. if (_baseDir == null) _baseDir = new String("."); project.setBasedir(_baseDir); if (_buildFile == null) _buildFile = new String(projectBasePath + File.separator + "build.xml"); // ProjectHelper.getProjectHelper().parse(project, new // File(_buildFile)); <span style="color:#FF0000;">// 關鍵代碼</span> ProjectHelper.configureProject(project, new File(_buildFile)); } public void runTarget(String _target) throws Exception { // Test if the project exists if (project == null) throw new Exception( "No target can be launched because the project has not been initialized. Please call the 'init' method first !"); // If no target is specified, run the default one. if (_target == null) _target = project.getDefaultTarget(); // Run the target project.executeTarget(_target); } <span style="color:#FF0000;">private final static String projectBasePath = "D:\\android\\workspace3\\XXX";//要打包的項目根目錄 private final static String copyApkPath = "D:\\android\\apktest";//保存打包apk的根目錄 private final static String signApk = "XXX-release.apk";//這裏的文件名必須是準確的項目名! private final static String reNameApk = "XXX_";//重命名的項目名稱前綴(地圖項目不用改) private final static String placeHolder = "@market@";//須要修改manifest文件的地方(佔位符) </span> public static void main(String args[]) { long startTime = 0L; long endTime = 0L; long totalTime = 0L; Calendar date = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss"); try { System.out.println("---------ant批量自動化打包開始----------"); startTime = System.currentTimeMillis(); date.setTimeInMillis(startTime); System.out.println("開始時間爲:" + sdf.format(date.getTime())); BufferedReader br = new BufferedReader(new FileReader("market.txt")); String flag = null; while ((flag = br.readLine()) != null) { // 先修改manifest文件:讀取臨時文件中的@market@修改成市場標識,而後寫入manifest.xml中 String tempFilePath = projectBasePath + File.separator + "AndroidManifest.xml.temp"; String filePath = projectBasePath + File.separator + "AndroidManifest.xml"; write(filePath, read(tempFilePath, flag.trim())); // 執行打包命令 AntTest mytest = new AntTest(); mytest.init(projectBasePath + File.separator + "build.xml", projectBasePath); mytest.runTarget("clean"); mytest.runTarget("release"); // 打完包後執行重命名加拷貝操做 File file = new File(projectBasePath + File.separator + "bin" + File.separator + signApk);// bin目錄下簽名的apk文件 File renameFile = new File(copyApkPath + File.separator + reNameApk + flag + ".apk"); boolean renametag = file.renameTo(renameFile); System.out.println("rename------>"+renametag); System.out.println("file ------>"+file.getAbsolutePath()); System.out.println("rename------>"+renameFile.getAbsolutePath()); } System.out.println("---------ant批量自動化打包結束----------"); endTime = System.currentTimeMillis(); date.setTimeInMillis(endTime); System.out.println("結束時間爲:" + sdf.format(date.getTime())); totalTime = endTime - startTime; System.out.println("耗費時間爲:" + getBeapartDate(totalTime)); } catch (Exception e) { e.printStackTrace(); System.out.println("---------ant批量自動化打包中發生異常----------"); endTime = System.currentTimeMillis(); date.setTimeInMillis(endTime); System.out.println("發生異常時間爲:" + sdf.format(date.getTime())); totalTime = endTime - startTime; System.out.println("耗費時間爲:" + getBeapartDate(totalTime)); } } /** * 根據所秒數,計算相差的時間並以**時**分**秒返回 * * @param d1 * @param d2 * @return */ public static String getBeapartDate(long m) { m = m / 1000; String beapartdate = ""; int nDay = (int) m / (24 * 60 * 60); int nHour = (int) (m - nDay * 24 * 60 * 60) / (60 * 60); int nMinute = (int) (m - nDay * 24 * 60 * 60 - nHour * 60 * 60) / 60; int nSecond = (int) m - nDay * 24 * 60 * 60 - nHour * 60 * 60 - nMinute * 60; beapartdate = nDay + "天" + nHour + "小時" + nMinute + "分" + nSecond + "秒"; return beapartdate; } public static String read(String filePath, String replaceStr) { BufferedReader br = null; String line = null; StringBuffer buf = new StringBuffer(); try { // 根據文件路徑建立緩衝輸入流 br = new BufferedReader(new FileReader(filePath)); // 循環讀取文件的每一行, 對須要修改的行進行修改, 放入緩衝對象中 while ((line = br.readLine()) != null) { // 此處根據實際須要修改某些行的內容 if (line.contains(placeHolder)) { line = line.replace(placeHolder, replaceStr); buf.append(line); } else { buf.append(line); } buf.append(System.getProperty("line.separator")); } } catch (Exception e) { e.printStackTrace(); } finally { // 關閉流 if (br != null) { try { br.close(); } catch (IOException e) { br = null; } } } return buf.toString(); } /** * 將內容回寫到文件中 * * @param filePath * @param content */ public static void write(String filePath, String content) { BufferedWriter bw = null; try { // 根據文件路徑建立緩衝輸出流 bw = new BufferedWriter(new FileWriter(filePath)); // 將內容寫入文件中 bw.write(content); } catch (Exception e) { e.printStackTrace(); } finally { // 關閉流 if (bw != null) { try { bw.close(); } catch (IOException e) { bw = null; } } } } }
而後是Android工程中須要進行修改的部分:
1. 修改local.properties中的sdk根目錄:
sdk.dir=D:\\android\\android-sdk-windows-r17\\android-sdk-windows-r17
2. 修改ant.properties中籤名文件的路徑和密碼(若是須要)
key.store=D:\\android\\mykeystore
key.store.password=123456
key.alias=mykey
key.alias.password=123456
3. 修改AndroidManifest.xml.temp
拷貝AndroidManifest.xml一份,命名爲AndroidManifest.xml.temp
將須要替換的地方改成佔位符,需與打包工程AntTest中的placeHolder常量一致
如: <meta-data android:value="@market @" android:name="UMENG_CHANNEL"/>
4. Build.xml中:
<project name="XXX" default="help">,XXX必須爲Android工程名稱.
若是機器沒有配置過Ant環境變量,可根據以下步驟進行配置:
ANT環境變量設置:
Windows下ANT用到的環境變量主要有2個,ANT_HOME 、PATH。 設置ANT_HOME指向ant的安裝目錄。 設置方法: ANT_HOME = D:/apache_ant_1.7.0 將%ANT_HOME%/bin; %ANT_HOME%/lib添加到環境變量的path中。 設置方法: PATH = %ANT_HOME%/bin; %ANT_HOME%/lib