使用Ant 实现批量打包Android应用

来源:互联网 发布:大数据分析论文 编辑:程序博客网 时间:2024/05/21 15:50




http://blog.csdn.net/t12x3456/article/details/7957117

http://blog.csdn.net/t12x3456/article/details/7957117

http://blog.csdn.net/t12x3456/article/details/7957117

http://blog.csdn.net/t12x3456/article/details/7957117

自动构建工具Ant深入剖析(一) 配置环境及初步使用

分类: 自动构建工具Ant 956人阅读 评论(0) 收藏 举报
ant工具javabuild扩展shell

Ant 是什么?

Apache Ant 是一个基于 Java 的生成工具。据最初的创始人 James Duncan Davidson 介绍,这个工具的名称是 another neat tool(另一个整洁的工具) 的首字母缩写。


Ant的作用:

生成工具在软件开发中用来将源代码和其他输入文件转换为可执行文件的形式(也有可能转换为可安装的产品映像形式)。随着应用程序的生成过程变得更加复杂,确保在每次生成期间都使用精确相同的生成步骤,同时实现尽可能多的自动化,以便及时产生一致的生成版本,这就变得更加重要.


Ant的优势:

Ant是一种基于Java的build工具。理论上来说,它有些类似于(Unix)C中的make ,但没有make的缺陷。目前的最新版本为:Ant 1.8.4。  既然我们已经有了make, gnumake, nmake, jam以及其他的build工具为什么还要要一种新的build工具呢?因为Ant的原作者在多种(硬件)平台上开发软件时,无法忍受这些工具的限制和不便。类似于make的工具本质上是基于shell(语言)的:他们计算依赖关系,然后执行命令(这些命令与你在命令行敲的命令没太大区别)。这就意味着你可以很容易地通过使用OS特有的或编写新的(命令)程序扩展该工具;然而,这也意味着你将自己限制在了特定的OS,或特定的OS类型上,如Unix.

Ant就不同了。与基于shell命令的扩展模式不同,Ant用Java的类来扩展。(用户)不必编写shell命令,配置文件是基于XML的,通过调用target树,就可执行各种task。每个task由实现了一个特定Task接口的对象来运行。

Ant 定义生成文件之间的依赖关系,它使用跨平台的 Java 类。使用 Ant,您能够编写单个生成文件,这个生成文件在任何 Java 平台上都一致地操作(因为 Ant 本身也是使用 Java 语言来实现的),这就是 Ant 最大的优势


Ant生成文件剖析:

Ant 没有定义它自己的自定义语法;相反,它的生成文件是用 XML 编写的。存在一组 Ant 能够理解的预定义 XML 元素,而且还可以定义新的元素来扩展 Ant 的功能。每个生成文件由单个 project 元素组成,该元素又包含一个或多个 target 元素。一个目标(target)是生成过程中已定义的一个步骤,它执行任意数量的操作,比如编译一组源文件。并且这些操作本身是由其他专用任务标签执行的然后这些任务将根据需要被分组到各个 target 元素中。一次生成过程所必需的所有操作可以放入单个 target 元素中,但是那样会降低灵活性。将那些操作划分为逻辑生成步骤,每个步骤包含在它自己的 target 元素中,这样通常更为可取。这样可以执行整体生成过程的单独部分,却不一定要执行其他部分。

例如,通过仅调用某些目标,您可以编译项目的源代码,却不必创建可安装的项目文件

顶级 project 元素需要包含一个 default 属性,如果在 Ant 被调用时没有指定目标,这个属性将指定要执行的目标。然后需要使用 target 元素来定义该目标本身。


下面是一个最基本的生成文件:

[html] view plaincopy
  1. <?xml version="1.0"?>  
  2.   <project default="init">  
  3.   <target name="init">  
  4.    </target>  
  5. </project>  

Ant基本使用方式:

     1. 配置环境变量:

         ANT_HOME: C:\ant-1.8              -----> Ant的安装/解压目录路径

         PATH后追加: C:\ant-1.8\bin       ------>Ant中的BIN目录路径        

     2. 确认环境变量配置是否成功

         打开CMD窗口,然后输入命令:  ant:

         看到如下显示:

         

     由于Ant构建时需要默认有build.xml文件,因此有如上的提示,至此,说明Ant的环境已经配置成功.


3. 使用Ant创建一个名为HelloWorld的文件夹:

 首先需要编辑build.xml:

      

[html] view plaincopy
  1. <?xml version="1.0"?>  
  2.   <project default="init">  
  3.   <target name="init">  
  4.     <span style="color:#FF0000;"><mkdir dir="HelloWorld"></span>  
  5.   </target>  
  6. </project>  


然后切换到build.xml文件所在的目录,输入ant,若有如下提示,则创建文件夹成功:

(init 部分相当于 日志的输出)

         

 4. 也可以使用ant创建多级嵌套的文件目录

  只需要在build.xml文件中进行修改:

   

[html] view plaincopy
  1. <?xml version="1.0"?>  
  2.   <project default="init">  
  3.   <target name="init">  
  4.    <span style="color:#FF0000;"> <mkdir dir="HelloWorld\a\b\c"/></span>  
  5.   </target>  
  6. </project>  

  

5. 删除如上的多级目录:

[html] view plaincopy
  1. <?xml version="1.0"?>  
  2.   <project default="init">  
  3.   <target name="init">  
  4.     <span style="color:#FF0000;"><delete dir="HelloWorld"/></span>  
  5.   </target>  
  6. </project>  

注意:此处路径只用输入最高级目录路径,这也正是ANT工具的强大之处:

  Java中如果要删除目录,除非该目录为空才可以删除,否则就要逐步进行删除.

  而使用Ant工具,则可以直接删除含有子目录的文件夹.











使用Ant 实现批量打包Android应用

分类: Android 2787人阅读 评论(4) 收藏 举报

由于公司运维需要以及应用中需要加上应用推广的统计,往往要对应二三十个渠道,按照正常方法一个一个的去生成不同渠道包的应用,不仅浪费了时间,而且大大降低了效率.

上一篇讲到使用Ant进行Zip/Tar包的解压缩,实际上Ant工具不仅仅具有此类功能,它更强大的地方在于自动化调用程序完成项目的编译,打包,测试等. 类似于C语言中的make脚本完成这些工作的批处理任务. 不同于MakeFile的是,Ant是纯Java编写的,因此具有很好的跨平台性.


在此我主要讲下如何自动构建工具Ant, 对应用进行批量打包, 生成对应不同市场的应用:


首先分别看一下用于打包的Java工程AntTest和需要被打包进行发布的Android工程结构:




market.txt里保存需要打包的市场标识,如:

youmeng

gfan

.......

此文件里自行根据需求添加渠道名称.


然后看一下实现批量打包AntTest类中的内容:

注意:红色标注部分需要进行修改:



[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. public class AntTest {  
  17.     private Project project;  
  18.   
  19.     public void init(String _buildFile, String _baseDir) throws Exception {  
  20.         project = new Project();  
  21.   
  22.         project.init();  
  23.   
  24.         DefaultLogger consoleLogger = new DefaultLogger();  
  25.         consoleLogger.setErrorPrintStream(System.err);  
  26.         consoleLogger.setOutputPrintStream(System.out);  
  27.         consoleLogger.setMessageOutputLevel(Project.MSG_INFO);  
  28.         project.addBuildListener(consoleLogger);  
  29.   
  30.         // Set the base directory. If none is given, "." is used.  
  31.         if (_baseDir == null)  
  32.             _baseDir = new String(".");  
  33.   
  34.         project.setBasedir(_baseDir);  
  35.   
  36.         if (_buildFile == null)  
  37.             _buildFile = new String(projectBasePath + File.separator  
  38.                     + "build.xml");  
  39.   
  40.         // ProjectHelper.getProjectHelper().parse(project, new  
  41.         // File(_buildFile));  
  42.         <span style="color:#FF0000;">// 关键代码</span>  
  43.         ProjectHelper.configureProject(project, new File(_buildFile));  
  44.     }  
  45.   
  46.     public void runTarget(String _target) throws Exception {  
  47.         // Test if the project exists  
  48.         if (project == null)  
  49.             throw new Exception(  
  50.                     "No target can be launched because the project has not been initialized. Please call the 'init' method first !");  
  51.         // If no target is specified, run the default one.  
  52.         if (_target == null)  
  53.             _target = project.getDefaultTarget();  
  54.   
  55.         // Run the target  
  56.         project.executeTarget(_target);  
  57.   
  58.     }  
  59.   
  60.     <span style="color:#FF0000;">private final static String projectBasePath = "D:\\android\\workspace3\\XXX";//要打包的项目根目录  
  61.     private final static String copyApkPath = "D:\\android\\apktest";//保存打包apk的根目录  
  62.     private final static String signApk = "XXX-release.apk";//这里的文件名必须是准确的项目名!  
  63.     private final static String reNameApk = "XXX_";//重命名的项目名称前缀(地图项目不用改)  
  64.     private final static String placeHolder = "@market@";//需要修改manifest文件的地方(占位符)  
  65. </span>  
  66.     public static void main(String args[]) {  
  67.         long startTime = 0L;  
  68.         long endTime = 0L;  
  69.         long totalTime = 0L;  
  70.         Calendar date = Calendar.getInstance();  
  71.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss");  
  72.         try {  
  73.             System.out.println("---------ant批量自动化打包开始----------");  
  74.             startTime = System.currentTimeMillis();  
  75.             date.setTimeInMillis(startTime);  
  76.             System.out.println("开始时间为:" + sdf.format(date.getTime()));  
  77.   
  78.             BufferedReader br = new BufferedReader(new FileReader("market.txt"));  
  79.             String flag = null;  
  80.             while ((flag = br.readLine()) != null) {  
  81.   
  82.                 // 先修改manifest文件:读取临时文件中的@market@修改为市场标识,然后写入manifest.xml中  
  83.                 String tempFilePath = projectBasePath + File.separator  
  84.                         + "AndroidManifest.xml.temp";  
  85.                 String filePath = projectBasePath + File.separator  
  86.                         + "AndroidManifest.xml";  
  87.                 write(filePath, read(tempFilePath, flag.trim()));  
  88.                 // 执行打包命令  
  89.                 AntTest mytest = new AntTest();  
  90.                 mytest.init(projectBasePath + File.separator + "build.xml",  
  91.                         projectBasePath);  
  92.                 mytest.runTarget("clean");  
  93.                 mytest.runTarget("release");  
  94.                 // 打完包后执行重命名加拷贝操作  
  95.                 File file = new File(projectBasePath + File.separator + "bin"  
  96.                         + File.separator + signApk);// bin目录下签名的apk文件  
  97.                   
  98.                 File renameFile = new File(copyApkPath + File.separator + reNameApk  
  99.                         + flag + ".apk");  
  100.                 boolean renametag = file.renameTo(renameFile);  
  101.                 System.out.println("rename------>"+renametag);  
  102.                 System.out.println("file ------>"+file.getAbsolutePath());  
  103.                 System.out.println("rename------>"+renameFile.getAbsolutePath());  
  104.             }  
  105.             System.out.println("---------ant批量自动化打包结束----------");  
  106.             endTime = System.currentTimeMillis();  
  107.             date.setTimeInMillis(endTime);  
  108.             System.out.println("结束时间为:" + sdf.format(date.getTime()));  
  109.             totalTime = endTime - startTime;  
  110.             System.out.println("耗费时间为:" + getBeapartDate(totalTime));  
  111.   
  112.         } catch (Exception e) {  
  113.             e.printStackTrace();  
  114.             System.out.println("---------ant批量自动化打包中发生异常----------");  
  115.             endTime = System.currentTimeMillis();  
  116.             date.setTimeInMillis(endTime);  
  117.             System.out.println("发生异常时间为:" + sdf.format(date.getTime()));  
  118.             totalTime = endTime - startTime;  
  119.             System.out.println("耗费时间为:" + getBeapartDate(totalTime));  
  120.         }  
  121.     }  
  122.   
  123.     /** 
  124.      * 根据所秒数,计算相差的时间并以**时**分**秒返回 
  125.      *  
  126.      * @param d1 
  127.      * @param d2 
  128.      * @return 
  129.      */  
  130.     public static String getBeapartDate(long m) {  
  131.         m = m / 1000;  
  132.         String beapartdate = "";  
  133.         int nDay = (int) m / (24 * 60 * 60);  
  134.         int nHour = (int) (m - nDay * 24 * 60 * 60) / (60 * 60);  
  135.         int nMinute = (int) (m - nDay * 24 * 60 * 60 - nHour * 60 * 60) / 60;  
  136.         int nSecond = (int) m - nDay * 24 * 60 * 60 - nHour * 60 * 60 - nMinute  
  137.                 * 60;  
  138.         beapartdate = nDay + "天" + nHour + "小时" + nMinute + "分" + nSecond + "秒";  
  139.   
  140.         return beapartdate;  
  141.     }  
  142.   
  143.     public static String read(String filePath, String replaceStr) {  
  144.         BufferedReader br = null;  
  145.         String line = null;  
  146.         StringBuffer buf = new StringBuffer();  
  147.   
  148.         try {  
  149.             // 根据文件路径创建缓冲输入流  
  150.             br = new BufferedReader(new FileReader(filePath));  
  151.   
  152.             // 循环读取文件的每一行, 对需要修改的行进行修改, 放入缓冲对象中  
  153.             while ((line = br.readLine()) != null) {  
  154.                 // 此处根据实际需要修改某些行的内容  
  155.                 if (line.contains(placeHolder)) {  
  156.                     line = line.replace(placeHolder, replaceStr);  
  157.                     buf.append(line);  
  158.                 } else {  
  159.                     buf.append(line);  
  160.                 }  
  161.                 buf.append(System.getProperty("line.separator"));  
  162.             }  
  163.         } catch (Exception e) {  
  164.             e.printStackTrace();  
  165.         } finally {  
  166.             // 关闭流  
  167.             if (br != null) {  
  168.                 try {  
  169.                     br.close();  
  170.                 } catch (IOException e) {  
  171.                     br = null;  
  172.                 }  
  173.             }  
  174.         }  
  175.   
  176.         return buf.toString();  
  177.     }  
  178.   
  179.     /** 
  180.      * 将内容回写到文件中 
  181.      *  
  182.      * @param filePath 
  183.      * @param content 
  184.      */  
  185.     public static void write(String filePath, String content) {  
  186.         BufferedWriter bw = null;  
  187.   
  188.         try {  
  189.             // 根据文件路径创建缓冲输出流  
  190.             bw = new BufferedWriter(new FileWriter(filePath));  
  191.             // 将内容写入文件中  
  192.             bw.write(content);  
  193.         } catch (Exception e) {  
  194.             e.printStackTrace();  
  195.         } finally {  
  196.             // 关闭流  
  197.             if (bw != null) {  
  198.                 try {  
  199.                     bw.close();  
  200.                 } catch (IOException e) {  
  201.                     bw = null;  
  202.                 }  
  203.             }  
  204.         }  
  205.     }  
  206. }  


然后是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 


0 0