Ant批量打包的目的是:Android应用市场繁杂,有时候可能需要统计你的app在各个渠道的下载量等信息,而统计各个渠道时是要做区分的,你需要在项目的配置文件中添加数据元,来标示我们的应用是在哪个渠道上发布的。
1、准备工作:
在正式开始Ant打包前,需要下载和配置Ant环境,下载地址:ant下载
下载后解压安装包,解压后的目录如下:
接下来就是配置Ant的环境变量:
创建ANT_HOME变量,填入路径:E:\apache-ant-1.9.7-bin\apache-ant-1.9.7
然后在Path中添加 %ANT_HOME%/bin;%ANT_HOME%/lib;
Ok,到这里,Ant环境变量算是配置完毕。
然后打开cmd命令行输入ant命令,看是不是出现下图的提示,是的话,就说明配置成功了。
2、开始Ant打包
(1)、新建一个项目,这里我的项目名称是:AntPackage,纯粹的一个空项目,啥也没呢。
然后就是使用android自带的命令创建我们的build.xml文件,在cmd命令行使用 cd
/d path 的命令,到达我们工程的根目录,然后使用 android update project --path . 命令,在当前目录下面创建我们的build.xml文件。如下图:
注意:在输入android
update project --path命令时,可能会出现下边的错误:
原因是需要配置ANDROID_HOME环境变量,ANDROID_HOME:F:\adt-bundle-windows-x86_64-20140321\adt-bundle-windows-x86_64-20140321\sdk,然后在path下添加%ANDROID_HOME%/tools;
(2)、创建完build.xml文件之后,我们首先在AndroidManifest.xml文件中,添加一个数据元,代码如下:
<meta-data android:value=" " android:name="UMENG_CHANNEL" />
后面的name属性根据不同的平台各有差异,我们要做的,就是替代前面的value,并实现打包
修改好之后,我们复制清单文件,然后改名为 AndroidManifest.xml.temp ,之后修改AndroidManifest.xml.temp文件内容,将数据源换成我们的替换符,如下所示
<meta-data android:value= "@[email protected]" android:name="UMENG_CHANNEL"/> 在之后的代码中,我们会将@[email protected]替换成我们的渠道名称
(3)、创建好之后,我们在创建一个名为 ant.properties 的文件,在里边添加你的签名文件信息,如图所示:
分别是keystore保存路径,密码,别名,别名密码
key.store=E:\\glodon.keystore key.store.password=123456 key.alias=glodon.keystore key.alias.password=123456
注意把build.xml下的name替换成当前项目的名称:
好,到目前为止,项目需要配置的信息配置的差不多了。
此时项目目录结构为:(红框为新增部分)
(3)、创建自动打包程序
新建一个java项目,我的项目名称为:AntTest
项目结构如下:
其中,market.txt填写的是发布到各个应用市场的名称,如图:
lib下的两个jar包,可以在Ant解压目录的lib下找到,复制过来就行,复制后记得右键Build
path。
接下来就是主要代码类,AntTest.java,代码如下:
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; /** * Ant自动打包程序 * @author liyx-k * */ public class AntTest { private Project project; private final static String projectBasePath = "F:\\GlodonProject\\AntPackage";// 要打包的项目根目录 private final static String copyApkPath = "E:\\MutilPackage";// 保存打包之后的apk的根目录 private final static String signApk = "AntPackage-release.apk";// 这里的文件名必须是准确的项目名!就是Project工程的bin目录下面的apk安装包的名字 private final static String reNameApk = "AntPackage_";// 重命名之后的项目名称前缀(地图项目不用改) private final static String placeHolder = "@[email protected]";// 需要修改manifest文件的地方(占位符) @SuppressWarnings("resource") 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文件:读取临时文件中的@[email protected]修改为市场标识,然后写入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"); // 将打包好的apk重命名后移动到copyApkPath位置 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)); } } 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); if (_baseDir == null) _baseDir = new String("."); project.setBasedir(_baseDir); if (_buildFile == null) _buildFile = new String(projectBasePath + File.separator + "build.xml"); ProjectHelper.configureProject(project, new File(_buildFile)); } public void runTarget(String _target) throws Exception { 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 (_target == null) _target = project.getDefaultTarget(); project.executeTarget(_target); } /** * 根据所秒数,计算相差的时间并以**时**分**秒返回 * * @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; } } } } }
其中,需要修改的地方有:
第一个是需要打包项目的根目录,第二个是生成APK的目录,第三个是生成apk的名称,一定注意- ,第四个是项目名称前缀,到这里配置应该差不多了,接下来运行看看。
三、运行AntTest项目,进行批量打包;
运行后发现下边的错误:
解决方案:
Eclipse菜单 – Window – Preferences – Java – Installed JREs – 选中栏目表格中的jre项 – Edit – Add External JARs – 选择jdk目录/lib/tools.jar - 确认其加入JRE system libraries – Finish – OK。
正确打包成功后,如图:
Ok这就打包成功了。。。。。。。。。。。。。。。。。
注意:如果项目关联的有第三方jar包,需要给依赖jar包导入build.xml和local.properties,记得把build.xml的name修改为项目的名称。否则,打包会失败的。。。。