使用ant 批量打包app
来源:互联网 发布:mac上做u盘启动盘 编辑:程序博客网 时间:2024/05/18 02:45
首先感谢这位哥们。。。。。太好了
Ant是什么:Ant是一种基于Java的build工具。理论上来说,它有些类似于(Unix)C中的make ,但没有make的缺陷。目前的最新版本为:Ant 1.9.4。
为什么要使用Ant批量打包Android应用:我们在发布App的时候,可能需要发送到十几,甚至几十个不同的分发渠道,比如360手机市场,应用包,木蚂蚁市场等等,我们可能需要对各个渠道的下载量等数据进行分析,比如使用百度移动统计等等。为了实现统计功能,我们需要在配置文件中添加一个数据元,来标识我们的应用要发布到哪一个渠道上,因此,若使用传统的方法,我们每发布一个渠道的版本,就需要修改清单文件中的数据元,然后再使用keystore进行签名和打包。若只有一两个分发渠道,工作量还是可以接受的,但是若我们的分发渠道打到几十个的时候,我们如果再手动的进行修改然后签名打包发布,那工作量就很可观了。因此,为解决这种需求,我们采用Ant来实现对Android应用的自动打包。
应用背景陈述之后,我们就正式开始了。
1.配置java环境变量
虽然现在的JDK版本版本不需要再手动的配置环境变量也能正常运行,但是,为了防止出现未知的错误,还是配置一下吧,具体怎么配置,百度下吧。
2.配置Android的SDK环境变量
除了需要Java的环境变量,我们还需要配置Android的sdk的位置,名字是ANDROID_HOME,值就是你的android的sdk的位置,比如我的,就如下所示
3.配置Ant环境
在本教程中,我们使用自己配置的Ant,因为我是使用的Android Developer Tools,没有Ant插件,因此,我们统一使用自己配置的Ant。
我使用的是apache-ant-1.7.1版本,解压,然后解压到一个文件夹,比如,我的就在E:\apache-ant-1.7.1
解压好文件之后,我们需要配置环境变量
然后,在Path中添加 ;%ANT_HOME%/bin;%ANT_HOME%/lib;
配置完成之后,打开Dos窗口,输入命令ant,若如下所示,则配置成功
4.创建实例工程,并创建build.xml配置文件
配置好环境变量之后,我们就可以开始测试了。首先,我们建立一个测试工程,名字叫Project,目录结构如下,我只是创建了一个简单的工程,什么都没动哦
创建好工程之后,我们需要使用android自带的命令创建我们的build.xml文件
打开dos命令窗口,使用cd /d path 的命令,到达我们工程的根目录,然后使用 android update project --path . 命令,在当前目录下面创建我们的build.xml文件,我的运行过程如下,大家按照自己的实际情况修改下目录即可,注意不要忘掉后面的 .
创建好之后,我们refresh一下工程,然后,现在的目录结构如下所示
这样之后,我们的build.xml文件就创建完成了
5.创建并修改配置文件
创建完build.xml文件之后,我们首先在AndroidManifest.xml文件中,添加一个数据元,代码如下
后面的name属性根据不同的平台各有差异,我们要做的,就是替代前面的value,并实现打包
修改好之后,我们复制清单文件,然后改名为AndroidManifest.xml.temp,之后修改AndroidManifest.xml.temp文件内容,将数据源换成我们的替换符,如下所示
<meta-data android:value="@market@" android:name="UMENG_CHANNEL"/> 在之后的代码中,我们会将@market@替换成我们的渠道名称
创建好之后,我们在创建一个名为 ant.properties 的文件,暂时不需要加什么东西。
在这一步结束之后,你的文件结构应该是这样的。
6.创建keystore密钥,并修改相关属性配置文件
如果要发布我们的应用,我们肯定需要一个签名的密钥,首先使用Android Tools创建一个keystore,具体怎么创建我就不详说了,百度吧
创建好之后,保存在一个位置,比如,我的在D盘根目录下面。
这一些都完成之后,我们需要对配置对配置文件进行修改。
首先,打开我们的build.xml文件,将project属性修改为我们要打包的项目的名字,比如,我们这里就是Project
修改后,保存。然后打开ant.properties文件,填入以下内容
分别代表keystore保存路径,密码,别名,别名密码,修改后保存
[html] view plaincopy
1. key.store=D:\\android.keystore
2. key.store.password=123456
3. key.alias=android.keystore
4. key.alias.password=123456
7.配置自动打包程序
到此为止,我们已经完成了Android端的配置信息,下面,我们就要完成Ant自动打包程序的编写了
首先,Ant自动打包程序程序结构如下所示
我们创建一个纯Java工程,然后创建lib文件夹,并加入两个外部导入包。这两个外部导入包,可以在我们ant的解压目录的lib找到,比如我的就在E:\apache-ant-1.7.1\lib
market.txt是一个纯txt文本,里面写入的是我们要进行替换的字符串,比如,我的里面写的就是
一会,程序将对这里面的字符串进行一行一行的遍历,替换到对应的位置之后,打包完成对应的apk安装包。
8.完成Ant自动打包程序
准备好这一切之后,我们就可以开始Ant打包程序的编写了,我把代码写在下面,需要进行修改的地方,我都进行了注释说明
[java] view plaincopy
1. package com.cn.ant;
2.
3. import java.io.BufferedReader;
4. import java.io.BufferedWriter;
5. import java.io.File;
6. import java.io.FileReader;
7. import java.io.FileWriter;
8. import java.io.IOException;
9. import java.text.SimpleDateFormat;
10.import java.util.Calendar;
11.
12.import org.apache.tools.ant.DefaultLogger;
13. import org.apache.tools.ant.Project;
14.import org.apache.tools.ant.ProjectHelper;
15.
16./**
17. *
18. * @ClassName: AntTest
19. * @Description: Ant自动打包程序
20. * @author: ZhaoKaiQiang
21. * @time: 2014-7-24下午5:47:04
22. * @version: V1.0
23. */
24.public class AntTest {
25. private Project project;
26.
27. private final static String projectBasePath = "G:\\workspace\\Project";// 要打包的项目根目录
28. private final static String copyApkPath = "G:\\";// 保存打包之后的apk的根目录
29. private final static String signApk = "Project-release.apk";// 这里的文件名必须是准确的项目名!就是Project工程的bin目录下面的apk安装包的名字
30. private final static String reNameApk = "Project_";// 重命名之后的项目名称前缀(地图项目不用改)
31. private final static String placeHolder = "@market@";// 需要修改manifest文件的地方(占位符)
32.
33. @SuppressWarnings("resource")
34. public static void main(String args[]) {
35. long startTime = 0L;
36. long endTime = 0L;
37. long totalTime = 0L;
38. Calendar date = Calendar.getInstance();
39. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss");
40. try {
41. System.out.println("---------ant批量自动化打包开始----------");
42. startTime = System.currentTimeMillis();
43. date.setTimeInMillis(startTime);
44. System.out.println("开始时间为:" + sdf.format(date.getTime()));
45. BufferedReader br = new BufferedReader(new FileReader("market.txt"));
46. String flag = null;
47. while ((flag = br.readLine()) != null) {
48. // 先修改manifest文件:读取临时文件中的@market@修改为市场标识,然后写入manifest.xml中
49. String tempFilePath = projectBasePath + File.separator
50. + "AndroidManifest.xml.temp";
51. String filePath = projectBasePath + File.separator
52. + "AndroidManifest.xml";
53. write(filePath, read(tempFilePath, flag.trim()));
54. // 执行打包命令
55. AntTest mytest = new AntTest();
56. mytest.init(projectBasePath + File.separator + "build.xml",
57. projectBasePath);
58. mytest.runTarget("clean");
59. mytest.runTarget("release");
60. // 打完包后执行重命名加拷贝操作
61. File file = new File(projectBasePath + File.separator + "bin"
62. + File.separator + signApk);// bin目录下签名的apk文件
63.
64. File renameFile = new File(copyApkPath + File.separator
65. + reNameApk + flag + ".apk");
66. // 将打包好的apk重命名后移动到copyApkPath位置
67. boolean renametag = file.renameTo(renameFile);
68. System.out.println("rename------>" + renametag);
69. System.out.println("file ------>" + file.getAbsolutePath());
70. System.out.println("rename------>"
71. + renameFile.getAbsolutePath());
72. }
73. System.out.println("---------ant批量自动化打包结束----------");
74. endTime = System.currentTimeMillis();
75. date.setTimeInMillis(endTime);
76. System.out.println("结束时间为:" + sdf.format(date.getTime()));
77. totalTime = endTime - startTime;
78. System.out.println("耗费时间为:" + getBeapartDate(totalTime));
79.
80. } catch (Exception e) {
81. e.printStackTrace();
82. System.out.println("---------ant批量自动化打包中发生异常----------");
83. endTime = System.currentTimeMillis();
84. date.setTimeInMillis(endTime);
85. System.out.println("发生异常时间为:" + sdf.format(date.getTime()));
86. totalTime = endTime - startTime;
87. System.out.println("耗费时间为:" + getBeapartDate(totalTime));
88. }
89. }
90.
91. public void init(String _buildFile, String _baseDir) throws Exception {
92. project = new Project();
93. project.init();
94. DefaultLogger consoleLogger = new DefaultLogger();
95. consoleLogger.setErrorPrintStream(System.err);
96. consoleLogger.setOutputPrintStream(System.out);
97. consoleLogger.setMessageOutputLevel(Project.MSG_INFO);
98. project.addBuildListener(consoleLogger);
99. if (_baseDir == null)
100. _baseDir = new String(".");
101. project.setBasedir(_baseDir);
102. if (_buildFile == null)
103. _buildFile = new String(projectBasePath + File.separator
104. + "build.xml");
105. ProjectHelper.configureProject(project, new File(_buildFile));
106. }
107.
108. public void runTarget(String _target) throws Exception {
109. if (project == null)
110. throw new Exception(
111. "No target can be launched because the project has not been initialized. Please call the 'init' method first !");
112. if (_target == null)
113. _target = project.getDefaultTarget();
114. project.executeTarget(_target);
115. }
116.
117. /**
118. * 根据所秒数,计算相差的时间并以**时**分**秒返回
119. *
120. * @param d1
121. * @param d2
122. * @return
123. */
124. public static String getBeapartDate(long m) {
125. m = m / 1000;
126. String beapartdate = "";
127. int nDay = (int) m / (24 * 60 * 60);
128. int nHour = (int) (m - nDay * 24 * 60 * 60) / (60 * 60);
129. int nMinute = (int) (m - nDay * 24 * 60 * 60 - nHour * 60 * 60) / 60;
130. int nSecond = (int) m - nDay * 24 * 60 * 60 - nHour * 60 * 60 - nMinute
131. * 60;
132. beapartdate = nDay + "天" + nHour + "小时" + nMinute + "分" + nSecond + "秒";
133.
134. return beapartdate;
135. }
136.
137. public static String read(String filePath, String replaceStr) {
138. BufferedReader br = null;
139. String line = null;
140. StringBuffer buf = new StringBuffer();
141.
142. try {
143. // 根据文件路径创建缓冲输入流
144. br = new BufferedReader(new FileReader(filePath));
145. // 循环读取文件的每一行, 对需要修改的行进行修改, 放入缓冲对象中
146. while ((line = br.readLine()) != null) {
147. // 此处根据实际需要修改某些行的内容
148. if (line.contains(placeHolder)) {
149. line = line.replace(placeHolder, replaceStr);
150. buf.append(line);
151. } else {
152. buf.append(line);
153. }
154. buf.append(System.getProperty("line.separator"));
155. }
156. } catch (Exception e) {
157. e.printStackTrace();
158. } finally {
159. if (br != null) {
160. try {
161. br.close();
162. } catch (IOException e) {
163. br = null;
164. }
165. }
166. }
167.
168. return buf.toString();
169. }
170.
171. /**
172. * 将内容回写到文件中
173. *
174. * @param filePath
175. * @param content
176. */
177. public static void write(String filePath, String content) {
178. BufferedWriter bw = null;
179.
180. try {
181. // 根据文件路径创建缓冲输出流
182. bw = new BufferedWriter(new FileWriter(filePath));
183. // 将内容写入文件中
184. bw.write(content);
185. } catch (Exception e) {
186. e.printStackTrace();
187. } finally {
188. // 关闭流
189. if (bw != null) {
190. try {
191. bw.close();
192. } catch (IOException e) {
193. bw = null;
194. }
195. }
196. }
197. }
198.}
这里大家需要修改的位置就是
可能会出错的地方就是signApk这个值,一般来说,我们的工程名是Project的时候,包的名字也应该是Project.apk。但是使用Ant进行打包的时候,后面会添加一个-release后缀,因此,我们还需要把这里写成Project-release.apk
如果我们的这个属性设置错误,我们就不能在我们设置的目标位置获取到我们的apk文件。
9.在这之后,我们就可以运行我们的AntTest程序,进行打包了,如果运行结果和我下面的结果差不多,那么恭喜你,打包成功!
然后,我们来到我们的目标文件夹,我们可以看到,打包好的apk文件,已经静静的躺在这里了
10.验证是否替换成功
得到我们的安装包之后,为了验证是否在清单文件中实现了替换,我们可以反编译一下我们的工程,我是用的GUI界面的反编译工具ApkTool_GUI_1.3.5
使用非常简单
下面,我们打开清单文件,看看对应的数据元是否改变了
确实变成了我们配置的字符串。
若运行时出现
Perhaps JAVA_HOME does not point to the JDK错误
设置 Eclipse菜单 – Window – Preferences – Java – Installed JREs – 选中栏目表格中的jre项 – Edit – AddExternal JARs – 选择jdk目录/lib/tools.jar - 确认其加入JRE system libraries– Finish – OK
- 使用ant 批量打包app
- Android使用Ant批量打包
- Android 使用 Ant 批量打包
- Android使用Ant批量打包
- android如何使用ant批量打包
- 使用Ant 实现批量打包Android应用
- 使用 Ant 实现批量打包Android应用
- 使用Ant 实现批量打包Android应用
- 使用Ant 实现批量打包Android应用
- 使用Ant 实现批量打包Android应用
- Eclipse下使用Ant多渠道批量打包
- Ant批量打包工具的使用
- 使用Ant批量打包Android项目
- Android 如何使用ant批量打包
- 使用Ant批量打包Android应用
- 使用Ant 实现批量打包Android应用
- 使用Ant 实现批量打包Android应用
- cocos2d-x使用ant批量打包
- java httpURL连接远程服务器并返回数据(httpurlconnection)
- backbone>>router
- vmware 下 Fedora 20装vmware tools 遇到的问题及解决
- C语言-typedef
- 从头到尾彻底理解KMP
- 使用ant 批量打包app
- DedeCMS导航下拉菜单
- static class 静态类(Java)
- ORACLE 实验一
- ios开发——FBSOpenApplicationErrorDomain模拟器无法运行问题
- Python 二进制文件读取显示 . .
- XMPP的IOS聊天客户端程序
- spring MVC 转发与重定向(传参)
- C++流的基本概念