使用Ant 實現批量打包Android應用

因爲公司運維須要以及應用中須要加上應用推廣的統計,每每要對應二三十個渠道,按照正常方法一個一個的去生成不一樣渠道包的應用,不只浪費了時間,並且大大下降了效率. 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 

相關文章
相關標籤/搜索