当前位置: 代码迷 >> Android >> Android封装之Ant多渠道打包的实现
  详细解决方案

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

热度:89   发布时间:2016-04-28 06:34:19.0
Android打包之Ant多渠道打包的实现

在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的特殊标记,所以必须用转义来表达双引号(&quot;)。

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

源码下载


  相关解决方案