Android项目中Ant打包脚本编写

转自:http://www.iteye.com/topic/78973

Ant是一款类似make的工具,用来编译/运行/打包Java程序。在构建、包装和发布过程中几乎每一件事都可以由Ant的任务来处理。
Ant的buildfile是用XML写的。编写build.xml时,下面是一个基本的模板。一个构建文件主要由三部分组成:Project、Target、Task。

<project name="" basedir="" default="">
    <property />
    <taskdef name="" classpathref="" resource="" />
    <target name="all" depends="">
        <copy />
        <javac />
        <jar />
        <exec />
        <customTask />
    </target>
</project>

1、project

每个build.xml有且只能存在一个project。project的基本属性:

name:项目名称

default:缺省开始执行的target

basedir:用于计算所有其他路径的基路径。该属性可以被basedir property覆盖。当覆盖时,该属性被忽略。如果属性和basedir property都没有设定,就使用buildfile文件的父

目录。

2、target

一个项目可以定义一个或多个target。
一个target是一系列你想要执行的任务,如编译任务、打包任务、混淆任务。
Ant在执行时以target为单位,执行顺序是从下至上,依次执行;如果某个Target有depends属性,那么就先顺序执行depends属性中的被依赖的target,然后再执行该target。
一个target只能被执行一次,即使有多个target依赖于它。
target的基本属性: 

name:target的名字

depends:该target依赖关系。用逗号分隔的target的名字列表,也就是依赖表。Ant在执行时以target为单位,target的depends属性又决定了哪个Target先执行,因此我们可以
通过Target来构造编译顺序。;如果被依赖的target无法运行,这种depends对于指定了依赖关系的target就没有影响。Ant会依照depends属性中target出现的顺序(从左到
右)依次执行每个target。然而,要记住的是只要某个target依赖于一个target,后者就会被先执行。

举例:

<target name="D" depends="C,B,A"/>
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="E"/>

假定我们要执行target D。从它的依赖属性来看,你可能认为先执行C,然后B,最后A被执行。错了,C依赖于B,B依赖于A,所以先执行A,然后B,然后C,最后D被执行。

description: target的描述信息。

3、Task

Ant执行的一系列任务是由target构成的,而target又是由数个小的task构成的,task任务是最小的运行单位。
task主要有两类:Ant内置的task类和自定义task。

3.1. Ant内置的task类

(1)Javac

编译Java源代码,样例:

<javac 
srcdir="{src}:{src2}"
destdir="{build}" 
includes="mypackage/p1/**,mypackage/p2/**"
excludes="mypackage/p1/testpackage/**"
classpath="xyz.jar"
debug="on"/>
解释:

编译{src}和{src2}目录及其子目录下的所有Java文件;多个目录时用":"分割。
但是package/p1/**,mypackage/p2/**将被编译,而mypackage/p1/testpackage/**将不会被编译。
Class文件将放在{build}指定的目录下
classpath表示需要用到的类文件或者目录,仅指我们定义的类库;而bootclasspath参数(启动类库):它已经包含了jre/lib目录下的rt.jar,以及我们自定义的类库。
debug设置为on表示输出debug信息

(2)Java

执行指定的Java类

A.运行一个类

<java classname="${main}" classpath="${classpath}"/> 
解释:classname中指定要执行的类,classpath设定要使用的环境变量;

B.运行某一特定类,并加上运行参数

<java fork="true" classname="proguard.ProGuard" classpath="${proguard.classpath}"> 
  <arg line="-libraryjars ${proguard.classpath}"/>  
  <arg line="-injars temp/${app.project}_tmp.jar"/>  
  <arg line="-outjar temp/${app.project}_obf.jar"/>  
  <arg line="-defaultpackage ''"/>  
  <arg line="-dontusemixedcaseclassnames"/>  
  <arg line="-keep public class ${app.midlet}"/> 
</java>
解释:fork参数:为true时,在新的JVM实例中运行,不影响当前JVM工作。

(3)Jar

将编译好的CLASS文件编译成jar包。样例:

<jar destfile="{dist}/lib/app.jar"
basedir="{build}/classes"
includes="mypackage/test/**"
excludes="**/Test.class"
manifest="my.mf"
/>
解释:将{build}/classes下面的所有文件打包到{dist}/lib/app.jar中,但是包括mypackage/test/所有文件不包括所有的Test.class;manifest属性指定自己的META-INF/MANIFEST.MF文件,而不是由系统生成。

(4)exec

用来调用外部程序

<exec executable="${LIB_PATH}/preverify.exe">
    <arg line="-classpath ${compile.classpath} -d temp/build temp/obfuscate"/>
</exec>

(5)File(Directory)类

A、mkdir

创建一个目录,如果他的父目录不存在,也会被同时创建。
例子:

<mkdir dir="build/classes"/>
解释:如果build不存在,也会被同时创建

B、copy

拷贝一个(组)文件、目录
例子:
b1.拷贝单个的文件:

<copy file="myfile.txt" tofile="mycopy.txt"/>
b2.拷贝单个的文件到指定目录下
<copy file="myfile.txt" todir="../some/other/dir"/>
b3.拷贝一个目录到另外一个目录下
<copy todir="../new/dir">
<fileset dir="src_dir"/>
</copy>
b4.拷贝一批文件到指定目录下
<copy todir="../dest/dir">
<fileset dir="src_dir">
<include name="**/*.java"/>
<iexclude name="**/Test.java"/>
</fileset>
</copy>
 
<copy todir="../dest/dir">
<fileset dir="src_dir" excludes="**/*.java"/>
</copy>
b5.拷贝一批文件到指定目录下,将文件名后增加.bak后缀
<copy todir="../backup/dir">
<fileset dir="src_dir"/>
<mapper type="glob" from="*" to="*.bak"/>
</copy>
b6.替换拷贝

<copy todir="temp/build">
   <fileset dir="temp/classes" includes="*.class" />
   <filterset>
        <filter token="@Time@" value="${app.time}"/>
   </filterset>
</copy>

 解释:<filterset>过滤集,可以将temp/classes文件夹下的存在@Time@标记的文件,替换为变量${app.time}值。这样在完成拷贝的同时也完成了替换任务。

C、 delete

删除一个(组)文件或者目录

例子:
1.删除一个文件

<delete file="/lib/ant.jar"/>
2.删除指定目录及其子目录
<delete dir="lib"/>
3.删除指定的一组文件
<delete>
<fileset dir="." includes="**/*.bak"/>
</delete>
4.删除指定目录及其子目录,包括他自己
<delete includeEmptyDirs="true">
<fileset dir="build"/>
</delete>

D、move

移动或重命名一个(组)文件、目录
例子:
1.移动或重命名一个文件

<move file="file.orig" tofile="file.moved"/>
2.移动或重命名一个文件到另一个文件夹下面
<move file="file.orig" todir="dir/to/move/to"/>
3.将一个目录移到另外一个目录下
<move todir="new/dir/to/move/to">
<fileset dir="src/dir"/>
</move>
4.将一组文件移动到另外的目录下
<move todir="some/new/dir">
<fileset dir="my/src/dir">
<include name="**/*.jar"/>
<exclude name="**/ant.jar"/>
</fileset>
</move>
5.移动文件过程中增加.bak后缀
<move todir="my/src/dir">
<fileset dir="my/src/dir">
<exclude name="**/*.bak"/>
</fileset>
<mapper type="glob" from="*" to="*.bak"/>
</move>

3.2.自定义task

自定义task必须保证该类是从Task类继承过来的。在脚本中使用标签为<taskdef> </taskdef>,样例及用法如下:

  <taskdef name="filesorter" classname="com.duomi.ant.FileSorter" classpath="${duomi.home}/ant/pkgutil.jar" /> 
  <target name="main"> 
   <filesorter file="input.txt" tofile="output.txt" /> 
  </target>
在打包脚本pkgutil.jar中,FileSorter类的源码实现如下:
public class FileSorter extends Task {
    private File file;
    private File tofile;

    // ant在进行任务处理时会调用execute()方法
    public void execute() throws BuildException {
        System.out.println("Sorting file=" + file);

        try {
            BufferedReader from = new BufferedReader(new FileReader(file));
            BufferedWriter to = new BufferedWriter(new FileWriter(tofile));
            List allLines = new ArrayList();

            // read in the input file
            String line = from.readLine();

            while (line != null) {
                allLines.add(line);
                line = from.readLine();
            }

            from.close();
            // sort the list
            Collections.sort(allLines);

            // write out the sorted list
            for (ListIterator i = allLines.listIterator(); i.hasNext();) {
                String s = (String) i.next();
                to.write(s);
                to.newLine();
            }

            to.close();
        } catch (FileNotFoundException e) {
            throw new BuildException(e);
        } catch (IOException e) {
            throw new BuildException(e);
        }
    }

    // file参数
    public void setFile(File file) {
        this.file = file;
    }

    // tofile参数
    public void setTofile(File tofile) {
        this.tofile = tofile;
    }
}
这个task类FileSorter,在使用时需要设置源文件和输出文件两个参数。Ant通过setter方法将build.xml中用到的属性名与task类中的实现方法相关联,方法就是:自定义task类中的方法名称命名规则为"set"+属性名。属性名是作为字符串来指定的,因此我们的 setter 方法的参数可以是一个字符串。在这样的情况下,Ant 将在展开值所引用的任何属性之后,使用该属性的字符串值来调用我们的方法。但有时我们想把属性的值看作是一种不同的类型。上述示例任务就是这种情况,其中的属性值引用文件系统上的文件,而不只是引用任意的字符串。可以通过将方法参数声明为 java.io.File 类型来容易地做到这点。Ant 将接受属性的字符串值,并把它解释为一个文件,然后传递给我们的方法。

Ant 能够对其他类型执行类似的转换,比如 boolean 和 int 类型。但如果提供具有相同名称但是具有不同参数的两个方法,Ant 将使用更明确的那一个方法,因此文件类型将优先于字符串类型。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值