您的位置:首页 > 移动开发 > Android开发

Android打包之Ant多渠道打包的实现

2014-03-17 14:07 399 查看
在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

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: