本文章由Socks完毕。博客地址:http://blog.csdn.net/zhaokaiqiang1992

转载请说明。

折腾了一下午。百度了一下午,最终实现了使用Ant对Android应用的批量打包,也算是了却了我的一桩心事。尽管网上的这部分教程也有,可是感觉写的不是具体。

更为重要的是。各种方法之间的差异比較大。对于新手来说。各种方法之间的选择是极为痛苦的,一个方法一个方法的去实验,是非常浪费时间的。

因此,我想给大家提供一套完整的,具体的Ant打包Android应用的教程,方便大家的学习和以后的參考。

废话不多说。開始解说。

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的位置,比方我的,就例如以下所看到的

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb2thaXFpYW5nMTk5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

3.配置Ant环境

在本教程中。我们使用自己配置的Ant,由于我是使用的Android Developer Tools,没有Ant插件,因此,我们统一使用自己配置的Ant。

我使用的是apache-ant-1.7.1版本号,解压,然后解压到一个目录,比方,我的就在E:\apache-ant-1.7.1

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb2thaXFpYW5nMTk5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

解压好文件之后,我们须要配置环境变量

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb2thaXFpYW5nMTk5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

然后,在Path中加入 ;%ANT_HOME%/bin;%ANT_HOME%/lib;

配置完毕之后。打开Dos窗体,输入命令ant,若例如以下所看到的。则配置成功

4.创建实例project。并创建build.xml配置文件

配置好环境变量之后。我们就能够開始測试了。首先,我们建立一个測试project,名字叫Project,文件夹结构例如以下,我仅仅是创建了一个简单的project。什么都没动哦

创建好project之后,我们须要使用android自带的命令创建我们的build.xml文件

打开dos命令窗体,使用cd /d path 的命令,到达我们工程的根文件夹,然后使用 android update project --path .
命令,在当前文件夹以下创建我们的build.xml文件。我的执行步骤例如以下。大家依照自己的实际情况改动下文件夹就可以。注意不要忘掉后面的 .

创建好之后,我们refresh一下project,然后。如今的文件夹结构例如以下所看到的

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb2thaXFpYW5nMTk5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

这样之后。我们的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保存路径,password,别名,别名password,改动后保存

key.store=D:\\android.keystore
key.store.password=123456
key.alias=android.keystore
key.alias.password=123456

7.配置自己主动打包程序

到此为止,我们已经完毕了Android端的配置信息。以下。我们就要完毕Ant自己主动打包程序的编写了

首先。Ant自己主动打包程序程序结构例如以下所看到的

我们创建一个纯Javaproject,然后创建lib文件夹。并增加两个外部导入包。

这两个外部导入包,能够在我们ant的解压文件夹的lib找到。比方我的就在E:\apache-ant-1.7.1\lib

market.txt是一个纯txt文本,里面写入的是我们要进行替换的字符串,比方,我的里面写的就是

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb2thaXFpYW5nMTk5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

一会。程序将对这里面的字符串进行一行一行的遍历。替换到相应的位置之后,打包完毕相应的apk安装包。

8.完毕Ant自己主动打包程序

准备好这一切之后,我们就能够開始Ant打包程序的编写了,我把代码写在以下,须要进行改动的地方,我都进行了凝视说明

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; /**
*
* @ClassName: AntTest
* @Description: Ant自己主动打包程序
* @author: ZhaoKaiQiang
* @time: 2014-7-24下午5:47:04
* @version: V1.0
*/
public class AntTest {
private Project project; private final static String projectBasePath = "G:\\workspace\\Project";// 要打包的项目根文件夹
private final static String copyApkPath = "G:\\";// 保存打包之后的apk的根文件夹
private final static String signApk = "Project-release.apk";// 这里的文件名称必须是准确的项目名!就是Project工程的bin文件夹以下的apk安装包的名字
private final static String reNameApk = "Project_";// 重命名之后的项目名称前缀(地图项目不用改)
private final static String placeHolder = "@market@";// 须要改动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文件:读取暂时文件里的@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");
// 将打包好的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;
}
}
}
}
}

这里大家须要改动的位置就是

可能会出错的地方就是signApk这个值。一般来说,我们的project名是Project的时候。包的名字也应该是Project.apk。可是使用Ant进行打包的时候,后面会加入一个-release后缀,因此,我们还须要把这里写成Project-release.apk

假设我们的这个属性设置错误,我们就不能在我们设置的目标位置获取到我们的apk文件。

9.在这之后,我们就能够执行我们的AntTest程序,进行打包了。假设执行结果和我以下的结果差点儿相同,那么恭喜你,打包成功!

然后,我们来到我们的目标目录。我们能够看到。打包好的apk文件。已经静静的躺在这里了

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb2thaXFpYW5nMTk5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

10.验证是否替换成功

得到我们的安装包之后,为了验证是否在清单文件里实现了替换,我们能够反编译一下我们的project。我是用的GUI界面的反编译工具ApkTool_GUI_1.3.5

使用很easy

以下。我们打开清单文件。看看相应的数据元是否改变了

确实变成了我们配置的字符串。

若执行时出现

Perhaps JAVA_HOME does not point to the JDK 错误

设置 Eclipse菜单 – Window – Preferences – Java – Installed JREs – 选中栏目表格中的jre项 – Edit – Add External JARs – 选择jdk文件夹/lib/tools.jar - 确认其增加JRE system libraries– Finish – OK

至此为止。使用Ant对android进行批量打包的教程到此结束,写了两个小时。好累啊。

文章中的演示样例代码和工具下载地址:

http://download.csdn.net/detail/bz419927089/7674043

【Android开发经验】使用Ant批量打包Android应用全然指南的更多相关文章

  1. 用Ant手动打包android程序,android分包机制解决65536方法过多异常

    Android利用ant手动打包 首先我们要给自己的IDE eclispe配置ant,默认的eclipse是集成了ant构建工具的,但是google提供的Android集成开发工具ADT,里面封装了E ...

  2. Android项目使用Ant多渠道打包(最新sdk)

    参考文章: http://blog.csdn.net/liuhe688/article/details/6679879 http://www.eoeandroid.com/thread-323111- ...

  3. cocos2d-x使用ant批量打包

    当项目需要在多渠道上线时,要打很多的渠道包,少则几十个,多种几百个.它们的区别一般只是渠道id或部分配置信息不同,这些信息均可写在配置文件中. 例如常见的渠道id不同,一般定义在AndroidMani ...

  4. CygWin模拟Linux环境进行Ant批量打包

    运行环境:Windows7 + Cygwin + ant 第一种:有源码 这种方式比较 简单.利用ant打包.直接shell脚本修改 配置渠道号的文件.我们目前是用的umeng的.在AndroidMa ...

  5. Android Ant批量打包

    一.配置Ant环境变量 JAVA_HOME=/software/jdk1.6.0_24 ANT_HOME=/software/apache-ant-1.9.2 Android_Home=/softwa ...

  6. cocos2dx Android 使用ant 批量打包

    参考文章: 例子:http://www.2cto.com/kf/201305/208139.html http://blog.csdn.net/ljb_blog/article/details/127 ...

  7. Android开发经验01:31个Android开发实战经验

    1. 在Android library中不能使用switch-case语句访问资源ID:在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案 2. 不能 ...

  8. Android批量打包提速 - 1分钟900个市场不是梦

    版权声明: 欢迎转载,但请保留文章原始出处 作者:GavinCT 出处:http://www.cnblogs.com/ct2011/p/4152323.html 黎明前的黑暗 使用Ant或者Gradl ...

  9. 项目androidAnt编译打包Android项目

    时间紧张,先记一笔,后续优化与完善. Ant编译打包Android项目 在Eclipse中对Android项目停止编译和打包如果项目比较大的话会比较慢,所以改为Ant工具来停止编译和打包 Ant环境配 ...

随机推荐

  1. 查询json数据结构的8种方式

    查询json数据结构的8种方式 你有没有对“在复杂的JSON数据结构中查找匹配内容”而烦恼.这里有8种不同的方式可以做到: JsonSQL JsonSQL实现了使用SQL select语句在json数 ...

  2. html5自带表单验证-美化改造

    神奇的代码 暂且叫做html5.css /* === HTML5 validation styles === */ .myform select:required, .myform input:req ...

  3. 函数 buf_chunk_init

    http://www.tuicool.com/articles/3QbYfm http://www.360doc.com/content/13/1216/17/12904276_337644353.s ...

  4. bzoj1015:1015: [JSOI2008]星球大战starwar

    应该是全部读入之后再添加边用并查集就可以了. yyl用空间换时间.u[]v[]等将边预存起来. #include<cstdio> #include<cstring> #incl ...

  5. SHOI2008小约翰的游戏John

    1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1139  Solved: 701[Submit][ ...

  6. JPA-一对多关系

    JPA中,一对多关系使用@OneToMany标示 关系维护端: package com.yl.demo1.bean.oneTomany; import javax.persistence.Cascad ...

  7. Ext入门学习系列(二)弹出窗体

    第二章 弹出窗体 上节学习了Ext的环境搭建和最基本的一个操作——弹出对话框,作为一个引子,本节讲述如何弹出一个新窗体,从实例讲解Ext的基本运行原理. 一.Ext的窗体长什么样? 先来看看几个效果, ...

  8. 可用于Hadoop下的ETL工具——Kettle

    看大家分享了好多hadoop相关的一些内容,我为大家介绍一款ETL工具——Kettle.    Kettle是pentaho公司开源的一款ETL工具,跟hadoop一样,也是java实现,其目的就是做 ...

  9. HDU 5607 graph 矩阵快速幂 + 快速幂

    这道题得到了学长的助攻,其实就是一个马尔科夫链,算出一步转移矩阵进行矩阵快速幂就行了,无奈手残 这是我第一回写矩阵快速幂,写的各种毛病,等到调完了已经8点44了,交了一发,返回PE,(发现是少了换行) ...

  10. JRebel 5.3.2

    http://www.blogjava.net/xylz/archive/2013/09/15/404098.html   此为单文件版本,无需license文件 IDE(Eclipse.IDEA可能 ...