在上一篇文章《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的内容
在这里来看一下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中。这里面,替换渠道号的写法有两种:
注意:双引号用“"”,由于贴代码的时候网页自动把“"”替换成“"”了。。
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中如果出现其他内容与替换内容一样的话也会被替换掉,不过这个概率是微乎其微的。重新选择运行选项,如下:
<?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"之间的那个空格符不能多也不能少!