在上一篇文章《eclipse下Ant自动打包,混淆和签名》中,我们已经可以使用ant进行打包了,但是很多情况下我们需要批量打包,比如发布到平台上时需要上传每个市场的渠道包,每个apk都包含了不同的渠道号,具体数值写在AndroidManifest.xml的meta元素中,比如在AndroidManifest.xml中添加一个渠道名和渠道号可以加入<meta android:name="UMENG_CHANNEL" android:value="UMENG"></meta>。然后再打包。所以,如果渠道号有很多,在版本更新之后又要重新打包的时候,谁都不想手动将一个个不同渠道的apk导出。这时,ant批量打包就能节省好多时间了。
首先,我们在配置文件中写好需要用到的渠道名和渠道号,用ant构建时将会读取我们写好的渠道,动态替换AndroidManifest.xml中的meta节点的name和value,每替换完一个就打出一个apk包,用一个for循环不断地重复打包直到导出所有的渠道包为止。
为了方便替换,在AndroidManifest.xml中添加一个meta节点如下:
<meta-data
android:name="channelname"
android:value="channelkey" >
</meta-data>
待会儿我们在打包的时候就会把channelname替换成渠道名,把channelkey替换成渠道号。
上一篇文章讲到local.properties,我们把参数都写在这里
如下local.properties:
#下面这句是自动生成的
sdk.dir=D:\\Program Files\\Android\\android-sdk
#数字签名文件
key.store=jingchen.keystore
#别名alias
key.alias=jingchen
#数字签名的密码
key.store.password=111111
#alias的密码
key.alias.password=111111
#这里设置混淆代码
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
#写上所有的渠道,格式 渠道名:渠道号
market_channels=UMENG_CHANNEL:UMENG,JPUSH_CHANNEL:AAA,BAIDU_CHANNEL:BAIDU
#版本
version=1.0.0
上面的两个参数market_channels和version我们在custom_rules.xml会获取,无论有多少渠道都可以写上,用","分隔。下面看一下我们的custom_rules.xml的内容
新建一个custom_rules.xml
在这里来看一下build.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project
name="MainActivity"
default="help" >
<property file="local.properties" />
<property file="ant.properties" />
<property environment="env" />
<condition
property="sdk.dir"
value="${env.ANDROID_HOME}" >
<isset property="env.ANDROID_HOME" />
</condition>
<loadproperties srcFile="project.properties" />
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir" />
<import
file="custom_rules.xml"
optional="true" />
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>
它会导入当前目录下的custom_rules.xml,所以我们在当前工程目录下新建一个custom_rules.xml,里面写上我们的打包规则。所有的替换,打包和输出操作都写在custom_rules.xml中。这里面,替换渠道号的写法有两种:
注意:双引号用“"”,由于贴代码的时候网页自动把“"”替换成“"”了。。
写法1
custom_rules.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 渠道包打包脚本 ant deploy -->
<project name="custom_rules" >
<!-- 引用支持循环的jar包ant-contrib-1.0b3.jar -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties" >
<classpath>
<pathelement location="lib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<!-- 循环打包,target名为deploy,构建的时候必须选择deploy -->
<target name="deploy" >
<!-- 进来的时候先clean一下项目 -->
<antcall target="clean" />
<!-- for循环内容传进来的参数为market_channels,以","为分隔构建list,循环读取list,并将读取到的字符串以参数channel传进modify_manifest中 -->
<foreach
delimiter=","
list="${market_channels}"
param="channel"
target="modify_manifest" >
</foreach>
</target>
<target name="modify_manifest" >
<!-- 按正则匹配获取渠道名字,赋给channelname -->
<propertyregex
input="${channel}"
override="true"
property="channelname"
regexp="(.*):"
select="\1" />
<!-- 按正则匹配获取渠道号码,赋给channelkey -->
<propertyregex
input="${channel}"
override="true"
property="channelkey"
regexp=":(.*)"
select="\1" />
<!-- 将AndroidManifest.xml中的android:name="channelname"替换成为android:name="${channelname}",这里的${channelname}是我们上面正则匹配出来的内容 -->
<replaceregexp
byline="true"
encoding="utf-8"
file="AndroidManifest.xml"
match="android:name="channelname""
replace="android:name="${channelname}"" />
<!-- 将AndroidManifest.xml中的android:value="channelkey"替换成为android:value="${channelkey}" -->
<replaceregexp
byline="true"
encoding="utf-8"
file="AndroidManifest.xml"
match="android:value="channelkey""
replace="android:value="${channelkey}"" />
<!-- 用release打包 -->
<antcall target="release" />
<!-- 拷贝渠道包到指定目录下,out.absolute.dir在自带的build.xml中定义了,为bin目录,如果要修改,可以在local.properties中添加一行out.absolute.dir=指定目录 -->
<copy
file="${out.absolute.dir}/${ant.project.name}-release.apk"
tofile="${out.absolute.dir}/out/${ant.project.name}-v${version}-${channelkey}.apk" />
<!-- 打包完一个渠道包后把渠道名和渠道号替换回原来格式,这样可以进行下一次替换,AndroidManifest.xml里所有匹配的东西都会被替换 -->
<replaceregexp
byline="true"
encoding="utf-8"
file="AndroidManifest.xml"
match="android:name="${channelname}""
replace="android:name="channelname"" />
<replaceregexp
byline="true"
encoding="utf-8"
file="AndroidManifest.xml"
match="android:value="${channelkey}""
replace="android:value="channelkey"" />
</target>
</project>
以上是其中一种写法,在替换AndroidManifest.xml中的内容的时候比较灵活,不用在乎AndroidManifest.xml的格式问题,比如android:name和android:value间多一个空格或者换行啥的,都不会影响到结果(下面的写法2就必须要求android:name和android:value间必须有且只有一个空格符)。但是也有一个缺点:AndroidManifest.xml中如果出现其他内容与替换内容一样的话也会被替换掉,不过这个概率是微乎其微的。重新选择运行选项,如下:
写法2
<?xml version="1.0" encoding="UTF-8"?>
<!-- 渠道包打包脚本 ant deploy -->
<project name="custom_rules" >
<taskdef resource="net/sf/antcontrib/antcontrib.properties" >
<classpath>
<pathelement location="lib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<!-- 循环打包 -->
<target name="deploy" >
<antcall target="clean" />
<foreach
delimiter=","
list="${market_channels}"
param="channel"
target="modify_manifest" >
</foreach>
</target>
<target name="modify_manifest" >
<!-- 获取渠道名字 -->
<propertyregex
input="${channel}"
override="true"
property="channelname"
regexp="(.*):"
select="\1" />
<!-- 获取渠道号码 -->
<propertyregex
input="${channel}"
override="true"
property="channelkey"
regexp=":(.*)"
select="\1" />
<replaceregexp
byline="false"
flags="g" >
<!-- 匹配的内容是 android:name="channelname" android:value="(.*)" -->
<regexp pattern="android:name="channelname" android:value="(.*)"" />
<!-- 匹配之后将其替换为 android:name="${channelname}" android:value="channelkey" -->
<substitution expression="android:name="${channelname}" android:value="${channelkey}"" />
<!-- 正则表达式需要匹配的文件为AndroidManifest.xml -->
<fileset
dir=""
includes="AndroidManifest.xml" />
</replaceregexp>
<!-- 打包 -->
<antcall target="release" />
<!-- 拷贝渠道包到指定目录下 -->
<copy
file="${out.absolute.dir}/${ant.project.name}-release.apk"
tofile="${out.absolute.dir}/out/${ant.project.name}-v${version}-${channelkey}.apk" />
<!-- 打包完一个渠道包后把渠道名和渠道号替换回原来格式,这样可以进行下一次替换 -->
<replaceregexp
byline="false"
flags="g" >
<regexp pattern="android:name="${channelname}" android:value="(.*)"" />
<substitution expression="android:name="channelname" android:value="channelkey"" />
<!-- 正则表达式需要匹配的文件为AndroidManifest.xml -->
<fileset
dir=""
includes="AndroidManifest.xml" />
</replaceregexp>
</target>
</project>
这时候AndroidManifest.xml中的渠道meta节点就要改为下面这样了:
<meta-data
android:name="channelname" android:value="channelkey" >
</meta-data>
android:name="channelname"和android:value="channelkey"之间的那个空格符不能多也不能少!
打包结果
好啦,Ant批量打包就讲完啦!大家动手试试吧~