在Android打包时,不同的应用市场会有不同的配置,特别是当有广告里,里面要有相应的市场标识,如果还是一个一个的生成,显然耗时又耗力,还易出错,所以面对各应用市场的多种渠道打包必须要依赖于脚本实现。这里是ant多渠道打包的实现。直接上脚本代码。
build_mulity_channel.xml
<?xml version="1.0" encoding="UTF-8"?><project name="AntDemo" default="loop-pack" > <property name="sdk-folder" value="D:\android-sdk-windows" /> <property name="platform-folder" value="${sdk-folder}\platforms\android-8" /> <property name="platform-tools-folder" value="${sdk-folder}\platform-tools" /> <property name="jdk-folder" value="D:\Program Files (x86)\Java\jdk1.6.0_45" /> <property name="ant-lib" value="D:\Ant\lib" /> <!-- tools --> <property name="android-jar" value="${platform-folder}\android.jar" /> <property name="tools.aapt" value="${platform-tools-folder}\aapt.exe" /> <property name="tools.javac" value="${jdk-folder}\bin\javac.exe" /> <property name="tools.dx" value="${platform-tools-folder}\dx.bat" /> <property name="tools.apkbuilder" value="${sdk-folder}\tools\apkbuilder.bat" /> <property name="tools.zipalign" value="${sdk-folder}\tools\zipalign.exe" /> <property name="tools.jarsigner" value="${jdk-folder}\bin\jarsigner.exe" /> <!-- dir --> <property name="project-dir" value="G:\Code\Android\Workspace\AntDemo" /> <property name="res" value="${project-dir}\res" /> <property name="gen" value="${project-dir}\gen" /> <property name="src" value="${project-dir}\src" /> <property name="bin" value="${project-dir}\bin" /> <property name="assets" value="${project-dir}\assets" /> <property name="libs" value="${project-dir}\libs" /> <!-- files --> <property name="manifest" value="${project-dir}\AndroidManifest.xml" /> <property name="java-file-gen" value="${gen}\com\example\antdemo\*.java" /> <property name="java-file-src" value="${src}\com\example\antdemo\*.java" /> <property name="keystore-name" value="${project-dir}\my.keystore" /> <property name="keystore-alias" value="ant_test" /> <!-- multi-channel --> <property name="channels" value="BaiDu:baidu,Lenovo:lenovo,XiaoMi:xiaomi" /> <property name="channelname" value="" /> <!-- task --> <!-- loop pack --> <taskdef resource="net/sf/antcontrib/antlib.xml" > <classpath> <fileset dir="${ant-lib}" /> </classpath> </taskdef> <target name="loop-pack" > <echo>Initialize... </echo> <delete dir="${bin}" /> <mkdir dir="${bin}" /> <echo>loop package... </echo> <foreach delimiter="," list="${channels}" param="nameandchannel" target="modify_manifest" > </foreach> </target> <target name="modify_manifest" > <!-- fetch channel name --> <propertyregex input="${nameandchannel}" override="true" property="channelname" regexp="(.*):" select="\1" /> <!-- fetch channel number --> <propertyregex input="${nameandchannel}" override="true" property="channelkey" regexp=":(.*)" select="\1" /> <!-- match and replace channel info --> <replaceregexp byline="false" encoding="utf-8" flags="g" > <regexp pattern="meta-data android:name="APP_PID" android:value="(.*)"" /> <substitution expression="meta-data android:name="APP_PID" android:value="${channelkey}"" /> <fileset dir="${project-dir}" includes="AndroidManifest.xml" /> </replaceregexp> <antcall target="release" /> </target> <target name="init-channel" > <echo>Initialize channel... </echo> <var name="out-dir" value="${bin}\${channelname}" /> <var name="dex-name" value="${out-dir}\classes.dex" /> <var name="pakcage-temp-name" value="${out-dir}\${ant.project.name}" /> <var name="unsigned-apk-name" value="${ant.project.name}_unsigned.apk" /> <var name="unsigned-apk-path" value="${out-dir}\${unsigned-apk-name}" /> <var name="signed-apk-name" value="${ant.project.name}_signed.apk" /> <var name="signed-apk-path" value="${out-dir}\${signed-apk-name}" /> <var name="dest-apk" value="${out-dir}/${ant.project.name}_${channelname}.apk" /> <delete dir="${out-dir}" /> <mkdir dir="${out-dir}" /> </target> <target name="gen-R" depends="init-channel" > <echo>Generating R.java from the resources... </echo> <exec executable="${tools.aapt}" failonerror="true" > <arg value="package" /> <arg value="-f" /> <arg value="-m" /> <arg value="-J" /> <arg value="${gen}" /> <arg value="-S" /> <arg value="${res}" /> <arg value="-M" /> <arg value="${manifest}" /> <arg value="-I" /> <arg value="${android-jar}" /> </exec> </target> <target name="compile" depends="gen-R" > <echo>Compile... </echo> <javac bootclasspath="${android-jar}" compiler="javac1.6" destdir="${out-dir}" encoding="utf-8" includeAntRuntime="true" listfiles="true" target="1.6" > <src path="${project-dir}" /> <classpath> <fileset dir="${libs}" includes="*.jar" /> <!-- 引用第三方jar包需要引用,用于辅助编译,并没有将jar打包进去。jar的打包在dex命令中。 --> </classpath> </javac> </target> <target name="dex" depends="compile" > <echo>Generate dex... </echo> <exec executable="${tools.dx}" failonerror="true" > <arg value="--dex" /> <arg value="--output=${dex-name}" /> <arg value="${out-dir}" /> <!-- classes文件位置 --> <arg value="${libs}" /> <!-- 把libs下所有jar打包 --> </exec> </target> <target name="package" depends="dex" > <echo> Package resource and assets... </echo> <exec executable="${tools.aapt}" failonerror="true" > <arg value="package" /> <arg value="-f" /> <arg value="-A" /> <arg value="${assets}" /> <arg value="-S" /> <arg value="${res}" /> <arg value="-I" /> <arg value="${android-jar}" /> <arg value="-M" /> <arg value="${manifest}" /> <arg value="-F" /> <arg value="${pakcage-temp-name}" /> </exec> </target> <target name="build-unsigned-apk" depends="package" > <echo> Build unsigned apk </echo> <exec executable="${tools.apkbuilder}" failonerror="true" > <arg value="${unsigned-apk-path}" /> <arg value="-v" /> <arg value="-u" /> <arg value="-z" /> <arg value="${pakcage-temp-name}" /> <arg value="-f" /> <arg value="${dex-name}" /> <arg value="-rf" /> <arg value="${src}" /> </exec> </target> <target name="sign-apk" depends="build-unsigned-apk" > <echo> Sign apk </echo> <exec executable="${tools.jarsigner}" failonerror="true" > <arg value="-keystore" /> <arg value="${keystore-name}" /> <arg value="-storepass" /> <arg value="123456" /> <arg value="-keypass" /> <arg value="123456" /> <arg value="-signedjar" /> <arg value="${signed-apk-path}" /> <arg value="${unsigned-apk-path}" /> <arg value="${keystore-alias}" /> </exec> </target> <target name="zipalign" depends="sign-apk" > <echo>Zipalign... </echo> <exec executable="${tools.zipalign}" failonerror="true" > <arg value="-v" /> <arg value="4" /> <arg value="${signed-apk-path}" /> <arg value="${dest-apk}" /> </exec> </target> <target name="release" depends="zipalign" > <delete file="${pakcage-temp-name}" /> <delete file="${unsigned-apk-path}" /> <delete file="${signed-apk-path}" /> <echo>APK is released. path:${zipalign-apk-path}_${channelname} </echo> </target></project>
注:
1、property是自定义的字段,主要是用于配置,比如sdk、jdk等的路径。
2、taskdef是引用ant的lib。在多渠道打包时,由于要用到ant-contrib-1.0b3.jar以实现foreah循环等,所以需要下载该jar放到ant的lib文件夹下。开始时,我没有配置这个引用,结果报错"failed to create task or type foreach"。错误截图如下。
3、loop-pack的target中先初始化bin文件夹(先删除后再创建)。然后再进行foreach循环。
4、foreach循环是实现循环打包的关键。
(1)、这里面有一个参数list引用的是property中的一个定义字段channels。channels中将渠道名和渠道标识写成key:value的形式,并且多个之间以逗号来分隔。
(2)、delimiter参数指的就是多个渠道之间的分隔符号,必须要一致,即使用逗号。所以如果定义时使用了分号,那么这里也要使用分号。
(3)、param相当于是循环中的一个变量,可以在其他target中引用。比如modify_manifest的target中就用到了该值。
(4)、target参数是该循环体内要调用的target。
5、modify_manifest实现AndroidManifest的动态修改。
(1)、propertyregex是属性的正则表达式,其中的input参数是输入的值(这里引用foreach循环中的param),property参数相当于是定义一个变量名以便其他地方引用(比如后边的init-channel中就引用了channelname)。regexp是正则表达式。
(2)、replaceregexp是替换的正则表达式,是通过正则表式匹配到要替换的部分。regexp中,由于双引号是xml的特殊标记,所以必须用转义来表达双引号(")。
meta-data android:name="APP_PID" android:value="(.*)"相当于meta-data android:name="APP_PID" android:value="(.*)"其中(.*)是正则匹配所有字符。要特别注意这句正则表达式的结构必须要与AndroidManifest.xml中的相一致。如果AndroidManifest.xml中使用了格式化(ctrl+shift+f),那么表达式的格造会有所不同,因为在格式化后,xml中自动补上一些空格。具体可以参看下面的未格式化和格式化的数据区别。我开始就是习惯性的进行格式化,结果怎么都无法匹配到对应的APP_PID。如果需要使用格式化的,需要修改正则表达式,同时还要将替换数据substitution也作相应的修改。
(3)、substitution是正则匹配替换的数值,这里可以使用变量,比如${channelkey}。
(4)、fileset是引用需要修改的文件。
(5)、antcall是修改之后需要继续执行的任务target。这里调用的是release.
6、在init-channel中定义了var变量,以便于后面的引用。使用var可以动态的使用foreach计算出来的值(比如channelname)。
转载请注明出处:http://blog.csdn.net/xxdddail/article/details/21384995
源码下载