在上一篇文章《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批量打包就講完啦!大家動手試試吧~