史上最全:ant多渠道打包安卓工程(二)

背景

上一篇我们讲了如何利用ant来代替eclipse实现安卓工程的编译签名打包,这一篇重点来研究一下多渠道问题。

搞过移动开发的应该都知道,国内的安卓市场有成百上千个,我们的apk发布之前,通常要为每一个渠道打包出来一个独一无二的安装包,如果仍然安装老方法来,在每一个渠道下都执行一次ant release,肯定能实现,但试想一下,每一个apk打包出来需要几分钟,要这样执行下去的话,容易重复不说,打包的人估计也得疯掉。

有没有一种更优雅更高效的方式来实现?比如建立一个循环,让它自动执行呢?

答案肯定是有的。

ant脚本本身并不支持for循环功能,我们需要借助第三方扩展包来实现。所以在打包之前,需要下下载一个开源的Ant-contrib包,下载地址为http://download.csdn.net/detail/luochoudan/9474447, 解压之后,请将jar文件放到ant的lib目录,然后就OK了。

知识储备

开始打包之前,我们先来看三个知识点,它们与你的工程构建息息相关,很有利于排错。

  • utf-8有无BOM的区别。BOM,就是字节序标记,用来标识后面的字节是通过utf-8编码产生的,对应的编码是EFBBBF,遗憾的是很多软件并不支持BOM,反而会导致出错。Windows自带的记事本对文本文件的处理就是加了BOM符,实在是脑残设计。推荐使用Notepad++来代替记事本,注意Notepad++本身支持带BOM符和不带BOM符的utf-8编码,建议设置成默认不带BOM符的。

  • .class文件和class.dex文件。.class文件比较常见,一般的.java文件执行javac之后生成的便是.class文件,JVM可对其进行解释。class.dex是Android中的特殊产物,由.class文件经过dex工具转译而成,专门供DVM解释执行的。具体的比较可参看这篇文章http://www.w2bc.com/Article/14646

  • ant打包的过程,一般可分为7步。再次唠叨一下,这7步环环相扣,其中的逻辑处理、调度顺序已经有eclipse自带的build.xml帮你规范好了。这里只略提一下,有兴趣的可参考http://blog.csdn.net/l_serein/article/details/7635816 这篇博文,对应原生的build.xml文件,了解具体实现。

    • 生成R.java类文件,对应aapt过程;
    • 如果有.aidl文件,则将其转换为.java类文件;
    • 编译.java文件,生成.class文件,对应javac过程;
    • 将.class文件转换为class.dex文件,对应dx过程;
    • 打包资源文件,res、asset、androidmanifest等;
    • 生成未签名的apk;
    • 签名

正式打包

接下来我们一步一步来实现所谓的多渠道。

  • 首先,在ant.properties里面添加渠道列表。别问我为什么要在ant.properties里面添加,因为前面已经介绍过,ant.properties里面的属性已经被导入到build.xml中,所以写在ant.properties里面,build.xml在执行的过程中会自动读取。当然,你要愿意,也可以把这些property属性加到build.xml中。这种做法不推荐,原因很简单,耦合度太高,太乱了没法看。
  market_channels=91,360
  version=1.0.5

加入的代码如上所示,各渠道之间用”,”分割,version代表apk的版本号。后面我会给出完整的ant.properties文件,供大家参考。

  • 然后编写循环打包的脚本。
    这个地方,真的是忍不住要吐槽一下网上的十八路文章东拼西凑,基本大同小异,基本不能运行,基本就是在坑人。

    上一篇我们已经说过,eclipse自带的build.xml脚本及其完善,它已经帮你规划好了整个打包流程,我们所要做的就是在这个基础上稍微修改一下。就好比一个完善的产品,到我们手里只需要加上一些个性化的定制,完全就可以实现我们想要的功能。所以当你在csdn或者博客园或者ITeye上看到那些密密麻麻甚至好几页的build脚本时,请自动忽略它,难懂晦涩不说,关键是不好用呃,浪费时间呃!!!!!笔者写到此处,心里还在滴血…

假设你已经看过上一篇文章,此刻你的工程有了如下的目录结构,
完整的目录结构
如果有请继续往下读,否则请先阅读上一篇文章《史上最全:ant多渠道打包安卓工程(一)》

我们工程根目录下的这个build.xml文件,就是最终要执行打包的终极文件,它里面有这样两句话,请认真注意一下,

    <import
        file="custom_rules.xml"
        optional="true" />
    <import file="${sdk.dir}/tools/ant/build.xml" />   

很明显,import了两个文件,一个是eclipse的\sdk\tools\ant\build.xml,一个是custom_rules.xml文件。前一个好说,是系统自带的,每一个adt都一样的;后一个是什么呢?

其实就是留给你实现的个性化定制。一般情况下,工程并没有这个custom_rules.xml,所以构建的时候会自动忽略它。而我们要实现多渠道的自动打包,很显然,在它里面定义一下就可以了。

工程根目录下创建custom_rules.xm,注意名字不要出错。它的内容我就直接贴代码了,笔者也是参考这篇文章http://www.cnblogs.com/yaozhongxiao/p/3523061.html ,这里稍加注释。不用粘贴复制,后面会给出完整的文件下载。

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="custom_rules" >
    <!--  引入ant/lib下新添加的ant-contrib-1.0b3.jar -->
    <taskdef resource="net/sf/antcontrib/antcontrib.properties" >
        <classpath>
            <pathelement location="lib/ant-contrib-1.0b3.jar" />
        </classpath>
    </taskdef>
    <!-- 部署函数,最终的打包由它执行  -->
    <target name="deploy" >
    <!-- 循环语句  -->
        <foreach
        <!-- 分隔符  -->
            delimiter=","
            <!-- 渠道列表 -->
            list="${market_channels}"
            <!-- 替换的参数 -->
            param="channel"
            <!-- 引入modify_manifest函数 -->
            target="modify_manifest" >
        </foreach>
    </target>

    <!-- modify_manifest实现替换mainfest文件中meta节点value的值,就是所谓的渠道号  -->
    <target name="modify_manifest" >
        <replaceregexp
            byline="false"
            flags="g" >
            <!-- 正则表达式,匹配规则,前面是name,后面是value,注意与mainfest里面的顺序对应-->
            <regexp pattern="android:name=&quot;UMENG_CHANNEL&quot; android:value=&quot;(.*)&quot;" />
            <substitution expression="android:name=&quot;UMENG_CHANNEL&quot; android:value=&quot;${channel}&quot;" />
            <fileset
                dir=""
                includes="AndroidManifest.xml" />
        </replaceregexp>

        <property name="out.release.file" location="${out.absolute.dir}/${ant.project.name}_${channel}.apk" />

        <antcall target="release" />

        <!--  输出渠道包到bin/out目录下,apk名称为"工程名v版本号-渠道号.apk" -->
        <copy
            file="bin/${ant.project.name}-release.apk"
            tofile="${out.absolute.dir}/out/${ant.project.name}v${version}-${channel}.apk" />
    </target>

    </project>
  • 添加完这个文件,基本的工作已经完成。

  • cmd下同样切换到工程根目录,运行ant deploy指令。

虽然如此,打包的路还有很长要走,因为在编译、文件转换的过程会出现各种各样的奇葩错误,但总的来说都是跟个人的配置有关,笔者在打包的过程中涕泪交零,总结一些常见的错误,需要的话可继续阅读后面的问题汇总。

如果运行ant -v deploy,一阵输出后,出现了如下画面,那就恭喜你;如果没有,也不要灰心,不要气馁,芝麻总会开花,问题总有解决的办法,多google找找原因吧。

build successful

问题汇总

  • 仍然是JDK的版本。1.5以下的应该不会有太多问题,但时至今日仍然停留在1.5的估计少之又少。
    错误描述:”-source 1.5不支持,请使用-source 1.7或者高版本…“。
    解决方案:高版本的建议 java.target和java.source都采用1.7,原因可参考上一篇文章。修改eclipse自带build.xml的第71、72行
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
  • 文件格式。utf-8不带BOM,不允许出现乱码。
    错误描述:”????字符不可映射为utf-8(GBK)…“,或者”编码utf-8的不可映射字符
    解决方案:javac编译默认采用的是gbk编码,一般需要指定为utf-8。修改eclipse自带build.xml的第73行,采用如下方法设置编码格式。如果仍然出错,请找到对应的.java文件,用notepad++打开,肯定有乱码字符出现,即使是注释,也要检查,因为注释中的乱码字符同样会导致编译失败。
<property name="java.compilerargs" value="-encoding UTF-8" />
  • dx转换报错。通常是两个错误一块出现。
    错误描述:”unexpected TOP-LEVEL Exception”异常,或者是”bad class file magic(cafebake) or version“,并且将错误定位在eclipse自带build.xml的第892行,即
<do-only-if-manifest-hasCode elseText="hasCode = false.     Skipping...">

这个问题真心困惑了好久,google了好久,最后找到了一个解决方法,在工程的project.properties里面加上这样一句话。

dex.disable.merger=true

具体原理不了解,回答者给出的解释是sdk的一个bug。

  • 仍然是文件格式,只不过这个比较隐蔽。
    错误描述:”X字节的utf-8序列的字节X无效“。
    解决方案:将notepad++编码格式设置为”utf-8 无BOM格式编码”(一般默认都是这个选项),然后用打开报错的文件,一定会发现不和谐的乱码字符,将其清理即可。值得注意的是xml文件虽然已经指定了编码格式,依然有编码问题。尤其是从别的地方粘贴过来的字符,虽然IDE中打开不会乱码,但有无BOM的区别同样会导致编译失败。
    同时建议将IDE的拼写设置一下Preference->General->Editors->Text Editors->Spelling->Encoding utf-8

  • 另一个常见的错误就是jar包重复,这个我打包过程没遇到过,不敢妄言。

尾声

每一个列出来的问题都是血泪,如果对其不熟悉,足够你头疼半天,而且网上的东西大多语焉不详,实践中很难奏效。笔者把亲身经历略作整理,每一个错误都相当经典,希望能够帮助同道中人少走弯路。

最后割肉给出ant脚本,需要的话自行下载参考,http://download.csdn.net/detail/luochoudan/9487822
欢迎留言拍砖,转载请注明出处。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值