Ant构建Java项目
我们创建HelloWorld项目,将源文件.java发到src中,编译后字节码.class放到bin中,对应的jar包放到exe目录中。
首先使用命令行来构建项目:
1.创建src目录
md src
2.在src目录中存放源文件HelloWorld.java,类HelloWorld的包名为com.tghz.test
那么创建包名路径,cd src,md com,cd com,md tghz,cd tghz,md test,然后存放HelloWorld.java到当前目录中
//HelloWorld.java public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello World"); } }
3.创建bin目录,并将编译后生成的字节码HelloWorld.class存放到该目录中
md bin
切换到项目目录下,
javac -sourcepath src\com\tghz\test -d bin src\com\tghz\test\HelloWorld.java (命令格式java -sourcepath 源文件目录 -d 目的文件存放目录 源文件.java)
可以自动在bin目录下根据HelloWorld.java的包名生成相应的目录
4.生成jar包,并将其存放到exe目录中。
切换到字节码.class目录中,即bin目录下。
首先我们要创建jar包的配置文件,该文件中描述了要执行的主类,格式为Main-Class:空格 包名.主类名 enter换行,该文件与包文件在同一级目录下。
jar包配置文件:mainconfig.txt
Main-Class: com.tghz.test.HelloWorld
执行jar -cvfm HelloWorld.jar(生成的jar文件名) mainconfig.txt(jar包配置文件) com.tghz.test(包名)
这样就生成了jar文件。
如果有多个.class文件,那个需要我们创建清单文件mymanifest,使用清单文件,将bin目录下的所有文件归档到classes.jar中。即jar cvfm classes.jar mymanifest -C bin .
执行成功后,会生成jar包,并且jar内的META-INF文件夹中MANIFEST.MF中可以看到前面进行的jar包配置。
下面我们来使用Ant来构建Java项目
Ant的构建脚本文件build file是使用XML语言写的,默认为build.xml。build.xml中包含一个根节点project,表示一个工程。每个build文件只允许包含一个project节点元素。
project节点中定义一个或多个target,表示不同的模块。而target又有一些task的集合,每一个task是一段可执行的代码。
使用ant来构建一个简单的Java项目包含三部分:
1.clean 删除之前生成的字节码.class文件和jar文件,这样我们在生成新的文件时不会冲突
2.编译源文件来生成.class文件
3.打包生成jar文件
4.运行java项目
在我们的构建文件build.xml的project下有四个target模块:clean,compile,jar,run。
下面来详细分析一下build.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <project name="HelloWorld" default="run" basedir="."> <!-- property一般是后面要用到的变量 --> <property name="src.dir" value="src"/> <property name="bin.dir" value="bin"/> <property name="jar.dir" value="exe"/> <property name="main-class" value="HelloWorld"/> <!-- "clean"用于清除之前生成的字节码和jar文件,这样生成新的时不会重复 --> <target name="clean"> <delete dir ="${bin.dir}"/> <delete dir ="${jar.dir}"/> <echo message = "clean the bin and exe"/> </target> <!-- "compile"用来编译源.java文件 --> <target name="compile" depends="clean"> <mkdir dir ="${bin.dir}"/> <javac srcdir="${src.dir}" destdir="${bin.dir}"/> <echo message="compile done!"/> </target> <!-- "jar"用来打包生成jar--> <target name="jar" depends="compile"> <mkdir dir="${jar.dir}"/> <jar destfile ="${jar.dir}/HelloWorld.jar" basedir="${bin.dir}"> <!-- 使用manifest节点来配置jar包 --> <manifest> <attribute name="Main-Class" Value="${main-class}"/> </manifest> </jar> <echo message ="created jar file"/> </target> <!-- "run"要完成的有:编译,打包生成jar,运行jar--> <target name="run" depends="jar"> <java classname ="com.tghz.test.HelloWorld" classpath="${jar.dir}/HelloWorld.jar"/> </target> </project>
在对src中的源文件进行编译时,会根据代码中的包名自动生成com/tghz/test/HelloWorld.class在bin目录中。javac srcdir="${src.dir}" (源文件目录) destdir="${bin.dir}"(目的文件目录)
在打包生成jar时,使用manifest节点来配置jar包,指明主类的名称。每个jar都包含一个清单文件,来指定jar的属性。
jar destfile ="${jar.dir}/HelloWorld.jar" (生成的jar文件的名称及相对路径) basedir="${bin.dir}"(指明当前的基路径)
创建一个名为destfile的jar文件,并将basedir目录下的所有文件添加到其中。在运行指定的jar文件时,要指名完整的类名路径和jar包名和路径java classname ="com.tghz.test.HelloWorld"(类名) classpath="${jar.dir}/HelloWorld.jar"(jar包名)
我们从命令行下进入build.xml文件所在的目录,执行ant,会默认寻找并执行build.xml文件。有时使用具有其他名称的生成文件更方便,在那样的情况下,您需要对 Ant 使用 -buildfile <file> 参数(-f <file> 是其简写形式)。我们还可以指定执行project下的某些模块,而不用全部执行。如ant
compile,这样就不会执行run了。
Eclipse对ant的支持
开源项目Eclipse提供了对Ant的大量支持,核心是Eclipse的Ant编辑器。我们可以将build.xml文件以Ant Editor的方式打开,并直接执行,那么就会执行xml中脚本了。
Ant自动编译打包android项目
对已经存在的Android项目提供Ant支持
进入sdk/tools目录下,执行android update project --name AntTest(项目名) --path F:\workspace2\AntTest1(项目路径),这样在该android项目会生成build.xml和local.properties。其中local.properties中写明了我们的android SDK的目录。
build.xml是ant构建的最重要的脚本。打开会发现其实里面有用的没几行,那是因为生成的build.xml脚本中引用了android sdk内部自带的构建脚本,<import file="${sdk.dir}/tools/ant/build.xml" />,具体的目录在{sdk目录}/tools/ant/build.xml。
这样我们的项目就支持ant编译打包了。
进入我们的项目目录下,执行ant debug,会生一个测试版的apk,默认使用debug key进行签名,生成的apk放在bin目录中。
执行ant release,会生成一个未签名的apk(your_prject_name-release-unsigned.apk)。
项目中引用了其他library项目:
如果在项目中只是引用了第三方的jar包,那么只要将jar放到libs文件夹下即可了,ant编译打包的过程中会自动将第三方的jar添加进来。但是如果我们的android项目参考了其他的library项目,这时候我们最初在执行android update命令的时候应该多一个参数 :subprojects
我们首先要做的是使我们参考的library项目也支持ant编译打包,执行android update lib-project --path (项目路径),注意此时的参数是lib-project。
然后再回到原项目,输入命令” android update project --name 项目名 -path 项目路径 --subprojects ",这下就OK了。
user library库中第三方jar包
通常情况下,在工程根目录下直接执行 ant debug 即可进行一次正常的build。默认的classpath会包括libs目录下的所有jar文件。但是如果工程中使用了USER LIBRARY,或者引用了外部的jar文件,那么在编译中就可能会遇到问题,
因为USER LIBRARY等这些jar文件不会被自动包含在classpath中,这时就要扩展ant的path变量,把自己的jar文件加入到classpath中。
通过察看sdk提供的build.xml编译脚本,可以发现javac使用的classpath定义如下:
<path id="project.javac.classpath"> <path refid="project.all.jars.path"></path> <path refid="tested.project.classpath"></path> </path> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" bootclasspathref="project.target.class.path" verbose="${verbose}" classpathref="project.javac.classpath" fork="${need.javac.fork}"> <src path="${source.absolute.dir}"></src> <src path="${gen.absolute.dir}"></src> <compilerarg line="${java.compilerargs}"></compilerarg> </javac>
其中 project.all.jars.path 包含了所有的jar文件,我们可以通过在工程目录下的build.xml中重新定义这个变量来引入其他的jar文件。
例如在我的工程中,引用了ormlite这个ORM库,为了能够在开发中使用“attach source”察看源码,该jar文件不能放在libs目录中,因为Eclipse不允许对libs目录中的jar文件“attach source”。因此我将此文件放到了libs/ormlite目录中,为了能够将这两个jar文件加入到classpath中,就要重新定义
project.all.jars.path 这个元素。
基本思路是,重新定义 -pre-compile这个target,在其中重新定义 project.all.jars.path 的值。
这段代码写在哪里呢?在每个项目的build.xml中引用了当前目录下的custom_rules.xml,那么我们就在项目根目录下创建一个custom_rules.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <project name="custom_rules" default="release"> <target name="-pre-compile"> <echo message="JARPATH=${toString:project.all.jars.path}"></echo> <echo message="JARPATH=${jar.libs.dir}"></echo> <property name="ormlite.dir" value="${jar.libs.dir}/ormlite"> </property> <path id="ormlite.lib"> <path path="${toString:project.all.jars.path}"></path> <pathelement location="${ormlite.dir}/ormlite-android-4.41.jar"></pathelement> <pathelement location="${ormlite.dir}/ormlite-core-4.41.jar"></pathelement> </path> <path id="project.all.jars.path"> <path refid="ormlite.lib"></path> </path> <echo message="JARPATH=${toString:project.all.jars.path}"></echo> </target> </project>
签名与渠道包
基于ant自动编译打包现有的android项目,可以在ant打包应用的时候加入签名信息以及自动打包渠道包。
加入签名信息
在项目的根目录下建一个ant.properties文件,输入如下内容,其中keystore密码和alias密码可以不指定(防泄漏),那么在命令执行的过程中会要求你输入。
#keystore的路径,必须使用正斜杠 key.store= "E:/wp_android_sample/me.key" #keystore的密码 #key.store.password=***** #alias名 key.alias=me #alias密码 #key.alias.password=******
在项目根目录下运行 ant release 命令就会帮你生成一个经过签名和aligned的apk,生成的apk(your_project_name-release.apk)在bin目录下.
自动打包渠道包
实现批量循环打包需要一个类似于for循环的功能,在Ant的核心包里没有相关的For循环的Task,即不支持for循环,但是ant支持第三方扩展包,以支持更多的其他功能。
于是我们要下载相应的支持for循环的扩展包。可以使用开源的Ant-contrib包。下载地址:http://ant-contrib.sourceforge.net/ 。
下载后的解压得到的jar文件放到ant的lib目录。接下来我们就可以打包渠道包了,具体做法是:
(1)首先在ant.properties文件中增加属性 market_channels (渠道列表,以逗号分割),version(应用程序版本名)
#渠道市场列表 market_channels=91,360,wandoujia,baidu #版本号 version=1.2.1
(2)在我们项目的build.xml中加入如下代码:
<!-- 渠道包打包脚本 ant deploy--> <taskdef resource="net/sf/antcontrib/antcontrib.properties"> <classpath> <pathelement location="lib/ant-contrib-1.0b3.jar"/> </classpath> </taskdef> <target name="deploy"> <foreach target="modify_manifest" list="${market_channels}" param="channel" delimiter=","> </foreach> </target> <target name="modify_manifest"> <replaceregexp flags="g" byline="false"> <!-- 匹配的内容是 android:value="*****" android:name="UMENG_CHANNEL" --> <regexp pattern='android:value="(.*)" android:name="UMENG_CHANNEL"' /> <!-- 匹配之后将其替换为 android:value="渠道名" android:name="UMENG_CHANNEL" --> <substitution expression='android:value="${channel}" android:name="UMENG_CHANNEL"' /> <!-- 正则表达式需要匹配的文件为AndroidManifest.xml --> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <property name="out.release.file" location="${out.absolute.dir}/${ant.project.name}_${channel}.apk" /> <!--包 --> <antcall target="release" /> <!--输出渠道包到bin/out目录下 --> <copy tofile="${out.absolute.dir}/out/${ant.project.name}v${version}-${channel}.apk" file="bin/${ant.project.name}-release.apk"/> </target>
在项目根目录下运行 ant deploy 命令就会帮你各个渠道的签名包了(为了全程可以自动执行,ant.properties文件中的keystore的密码可以指定,这样在执行过程中就不需要手动输入密码了),在bin目录的out目录下。