现在的位置: 首页 > 综合 > 正文

Eclipse下使用Ant多渠道批量打包

2018年05月27日 ⁄ 综合 ⁄ 共 6245字 ⁄ 字号 评论关闭

在上一篇文章《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中。这里面,替换渠道号的写法有两种:

注意:双引号用“&quot;”,由于贴代码的时候网页自动把“&quot;”替换成“"”了。。

写法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"之间的那个空格符不能多也不能少!

其他的和写法1差不多,可以看上面的注释。

打包结果

经过上面执行ant构建完成之后,刷新输出目录bin,可以看到有带有渠道号的apk包啦!

下面,我们将三个包反编译看看AndroidManifest.xml中的渠道信息到底有没有被替换呢?可以看到,三个apk中的渠道信息都成功被替换了!


好啦,Ant批量打包就讲完啦!大家动手试试吧~

 

 

 

 

 

 

 

抱歉!评论已关闭.