Ant自动编译打包android项目

时间:2023-02-04 07:50:01

1.  背景:

    Eclipse用起来虽然方便,但是编译打包android项目还是比较慢,尤其当要将应用打包发布到各个渠道时,用Eclipse手动打包各种渠道包就有点不切实际了,这时候我们用到Ant帮我们自动编译打包了。

2.  Ant 安装:

     ant的安装比较简单,下载ant压缩包(最新的为1.9.3版本),下载之后将其解压到某个目录(本人解压到E:\Program Files\apache-ant-1.9.3) ,然后配置环境变量(新建ANT_HOME环境变量,值为ant所在的目录,然后将ANT_HOME/bin添加到path中),如图:
      Ant自动编译打包android项目          Ant自动编译打包android项目
     打开命令行工具,输入 ant  -version ,如果出现如下结果,说明ant 安装成功。
      Ant自动编译打包android项目

3. 对已存在的Android项目提供Ant支持:

   打开命令行工具,切换路径到项目所在的目录(比如我在E:\GitHub\likebamboo\android-menudrawer\menudrawer-samples下有一个android项目),输入命令" android update project --name MenudrawSample -p ./ " 如下图:(其中 --name 参数是指定项目名称,可自己根据需要替换)。

Ant自动编译打包android项目

     这时候我们可以看到在我们的项目根目录下多了build.xml,以及local.properties两个文件。

     其中local.properties写明了我们的android SDK的目录(其实是环境变量ANDROID_HOME的值,所以如果环境变量中没有这个的,请增加)。

      build.xml则是ant构建的最重要脚本,打开一看,发现里面其实大部分都是写注释,有用的没几行,这是因为生成的这个build.xml引用了android SDK自带的构建脚本,具体目录是{sdk目录}/tools/ant/build.xml 。

Ant自动编译打包android项目     Ant自动编译打包android项目

      这样,我们项目就支持ant编译打包了,但是,有人可能会说了,我的项目有引用第三方的jar包,而且还引用了其他的android library 项目,该怎么办呢? 请往下看:

4. 项目引用了其他library项目:

      如果项目只是引用了第三方jar包,只要将jar包放在libs文件夹下就ok了,ant会在编译打包过程中会自动将第三方jar加进去的。但是当我们的android 项目参考了其他library项目,这时候我们最初在输入android update 命令的时候应该多一个参数 --subprojects : 

Ant自动编译打包android项目

      你发现报错了,不要着急,这是因为那个library 还不支持ant自动编译,我们需要先让它也支持。

      进入到library项目所在的目录,输入命令 android update lib-project -p ./  (注意是 lib-project);

Ant自动编译打包android项目

   再回到原项目,输入命令” android update project --name MenudrawSample -p ./ --subprojects "这下就OK了。

5. 编译打包项目:

       ant debug : 生成一个测试版apk,默认使用 debug key 进行签名,生成的apk(your_project_name-debug.apk)在bin目录下。

       ant release : 生成一个未签名和未aligned的apk包,生成的apk(your_project_name-release-unsigned.apk和your_project_name-release-unaligned.apk)在bin目录下






继续介绍如果如何在ant打包应用的时候加入签名信息以及自动打包渠道包


6. 加入签名信息:

在项目的根目录下建一个ant.properties文件,输入如下内容,其中keystore密码和alias密码可以不指定(防泄漏),那么在命令执行的过程中会要求你输入。

[html] view plain copy Ant自动编译打包android项目Ant自动编译打包android项目
  1. #keystore的路径,必须使用正斜杠  
  2. key.store=./me.key  
  3. #keystore的密码  
  4. #key.store.password=*****  
  5. #alias名  
  6. key.alias=me  
  7. #alias密码  
  8. #key.alias.password=******       
在项目根目录下运行 ant release 命令就会帮你生成一个经过签名和aligned的apk,生成的apk(your_project_name-release.apk)在bin目录下

注意:这里keystore路径使用的是相当路径,楼主在测试时使用了绝对路径,出现密码错误的情况,有类似情况(设置的密码明明是对的,但是还是报Keystore was tampered with, or password was incorrect: Password verification failed)可是尝试将绝对路径改为相对路径。


7. 自动打包渠道包:

 实现批量循环打包需要一个类似于for循环的功能,在Ant的核心包里没有相关的For循环的Task,即不支持for循环,但是ant支持第三方扩展包,以支持更多的其他功能。

于是我们要下载相应的支持for循环的扩展包。可以使用开源的Ant-contrib包。下载地址:http://ant-contrib.sourceforge.net/  。


注意:如果报错:

 Could not load definitions from resource net/sf/antcontrib/antcontrib.properties. It could not be found.

就是因为没有ant-contrib-1.0b3.jar包,(注意这里的包需要和custom_rules文件中的相同)


下载后的解压得到的jar文件放到ant的lib目录。接下来我们就可以打包渠道包了,具体做法是:

(1)首先在ant.properties文件中增加属性 market_channels (渠道列表,以逗号分割),version(应用程序版本名) 

#keystore的路径,必须使用正斜杠
key.store=./test3.key
#keystore的密码
key.store.password=bihansheng
#alias名
key.alias=test3
#alias密码
key.alias.password=bihansheng

#渠道市场列表
market_channels=bihansheng,baidu,91
#版本号
version=1.0.1
#包名
app.name=test3
#apk所在的文件名
apk.dir=text3


#下面的配置是区分正式打包和测试环境打包的参数
#测试环境标识 给apk命名的时候用
test.tag.name=test
#生产环境标识 给apk命名的时候用
release.tag.name=release

#测试环境服务器配置
test.server.url=192.168.1.10/bihansheng
test.server.image.url=192.168.1.9
test.bihansheng.url=192.168.1.10
#生产环境服务器配置
rel.server.url=111.111.111.222/bihansheng
rel.server.image.url=111.111.111.229
rel.bihansheng.url=www.bihansheng.com


注意: 渠道名称用逗号分开,并且不允许出现违规的字符如斜杠,否则会打包失败,同样的文件名和文件路径也不能出现违规字符


(2)在我们项目中添加custom_rules.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules" >
<!-- 引用ant-contlib这个扩展包,声明一下 -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties" >
<classpath>
<pathelement location="${ant.ANT_HOME}/lib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<!-- 定义一个时间变量,打完包后跟渠道号一起命名apk -->
<tstamp>
<format
pattern="yyyyMMddhhmm"
property="pktime"
unit="hour" />
</tstamp>
<!-- 创建apk存放目录 -->
<mkdir dir="${apk.dir}" >
</mkdir>
<!-- 替换参数 然后打包APK -->
<target name="replace_parameter" >
<!-- 替换服务器配置 -->
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!-- 这个是正则表达式匹配hostconfig中bihansheng_server的值 -->
<regexp pattern="bihansheng_server>(.*)</bihansheng_server" />
<substitution expression="bihansheng_server>${server_url}</bihansheng_server" />
<fileset
dir=""
includes="res/xml/hostconfig.xml" />
</replaceregexp>
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!-- 这个是正则表达式匹配hostconfig中bihansheng_img_server的值 -->
<regexp pattern="bihansheng_img_server>(.*)</bihansheng_img_server" />
<substitution expression="bihansheng_img_server>${server_image_url}</bihansheng_img_server" />
<fileset
dir=""
includes="res/xml/hostconfig.xml" />
</replaceregexp>
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!-- 这个是正则表达式匹配hostconfig中bihansheng_url的值 -->
<regexp pattern="bihansheng_url>(.*)</bihansheng_url" />
<substitution expression="bihansheng_url>${bihansheng_url}</bihansheng_url" />
<fileset
dir=""
includes="res/xml/hostconfig.xml" />
</replaceregexp>
</target>
<!-- 打包测试环境命令就用这个 -->
<target name="deploytest" >
<!-- 传服务器配置参数到 replace_parameter这个打包target -->
<antcall target="replace_parameter" >
<param
name="server_url"
value="${test.server.url}" />
<param
name="server_image_url"
value="${test.server.image.url}" />
<param
name="bihansheng_url"
value="${test.bihansheng.url}" />
</antcall>
<!-- 执行循环打包target foreach_replacechannel -->
<antcall target="foreach_replacechannel" >
<!-- apk命名时候用到的参数 -->
<param
name="deploy_environment"
value="${test.tag.name}" />
</antcall>
</target>
<!-- 打包生产环境命令就用这个 -->
<target name="deployrel" >
<!-- 传服务器配置参数到 replace_parameter这个打包target -->
<antcall target="replace_parameter" >
<param
name="server_url"
value="${rel.server.url}" />
<param
name="server_image_url"
value="${rel.server.image.url}" />
<param
name="bihansheng_url"
value="${rel.bihansheng.url}" />
</antcall>
<!-- 执行循环打包target foreach_replacechannel -->
<antcall target="foreach_replacechannel" >
<!-- apk命名时候用到的参数 -->
<param
name="deploy_environment"
value="${release.tag.name}" />
</antcall>
</target>
<!-- 循环打包的target -->
<target name="foreach_replacechannel" >
<!-- 开始循环打包,从market_channels参数中取出一个渠道号用channel标识,然后通过正则修改manifest文件 -->
<foreach
delimiter=","
list="${market_channels}"
param="channel"
target="modify_manifest" >
</foreach>
</target>
<target name="modify_manifest" >
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!--
这个是正则表达式匹配manifest中meta,我用的友盟的统计,我 AndroidManifest中的配置为:
<meta-data android:value="360shichang" android:name="UMENG_CHANNEL"
-->
<regexp pattern="android:value="(.*)" android:name="UMENG_CHANNEL"" />
<substitution expression="android:value="${channel}" android:name="UMENG_CHANNEL"" />
<fileset
dir=""
includes="AndroidManifest.xml" />
</replaceregexp>
<!-- 这里设置最终生成包的存放目录以及apk的名称,注意这里是文件名称,所以变量中不允许出现违规字符,否则将无法生成最终的apk(会出现output is not valid 的错误) -->
<property
name="out.final.file"
location="${apk.dir}/${app.name}_${channel}_${deploy_environment}_${pktime}.apk" />
<antcall target="clean" />
<antcall target="release" />
</target>
</project>



(3)custom_rules.xml文件中是用服务器ipizne配置文件hostconfig.xml文件,内容为: 

<?xml version="1.0" encoding="UTF-8"?>
<!-- Ϊ‹antղѼʱ۲ֽղƥƤìȫһҪٱʽۯكτݾ -->
<hostconfig>
<bihansheng_server>1111.1111.1111.1/bihansheng</bihansheng_server>
<bihansheng_img_server>1111.1111.1111.1</bihansheng_img_server>
<bihansheng_url>www.bihansheng.com</bihansheng_url>
</hostconfig>