Android客户端打包方案分享

基本介绍

Android应用的自动化打包是应用持续集成以及多渠道发布的基础。当前Android客户端自动化打包的主要有两种方式,Ant和Maven。两种方式本质上都是调用Android SDK里面提供的工具,不过各自有各自的特点。

1. Ant脚本

好处:开发成本较低,android sdk默认提供ant的打包脚本,可以根据需要进行修改和扩展。

不足:不天然支持包的依赖管理,需要自己写代码控制应用的依赖。

2. Maven

好处:天然支持包的依赖管理,依赖管理不需要写过多的代码。Maven插件机制容易扩展和定制,方便实现自己的打包流程。

不足:从头编写Maven脚本,或者maven插件,大家对Maven的熟悉程度稍低,门槛稍高。

这里介绍一种Ant+shell脚本的自动化打包方案。Ant脚本直接复用sdk提供的脚本并稍作扩展,对应用的包依赖和打包流程自动化控制,选择使用shell实现。

具体实施

打包整体逻辑

Shell脚本(见源码,感谢@今为帮忙重构)

Shell脚本实现了上图中的逻辑,比较简单,这里不再细述,可以看一下源码。

Ant脚本定制

这里主要描述一下对Android自带ant脚本的定制。

Android SDK里面自带的ant脚本(在~/android-sdk-linux_x86/tools/ant/build.xml),如果你的Android主工程没有支持ant构建,那么可以在主工程根目录下通过运行

android update project -p . –n projectname

来增加ant构建支持,运行后会在根目录下生成build.xml(通过<import file="${sdk.dir}/tools/ant/build.xml" />继承自SDK中的build.xml)

SDK中的build.xml有release task,包括了android打包的完成流程,看代码如下:

<target name="release"
                depends="-set-release-mode, -release-obfuscation-check, -package, -post-package, -release-prompt-for-password, -release-nosign, -release-sign, -post-build"
                description="Builds the application in release mode.">
 </target>

由代码可见,release任务依赖了8个其它的任务,其实核心的任务就2个:

l   -package 编译,生成未签名APK

l   -release-sign 签名

总结起来整个过程分解为:编译生成未签名包签名两个阶段。我们要做的就是在这两个阶段中增加一个替换渠道号的步骤,如上图中描述,主要过程核心流程:

  1. 编译生成未签名包
  2. 循环替换每个渠道号到未签名包
  3. 循环针对替换后的未签名包生成签名包

步骤1和3其实就是原来release任务的分解,代码如下:

<target name="release2"
                depends="-set-release-mode, -package, -post-package, -release-prompt-for-password, -release-nosign, -post-build"
                description="Builds the application in unsigned mode.">
    </target>
<target name="signapk"
                depends="-set-release-mode,-release-sign, -post-build"
                description="Sign apk.">

Android应用根目录下自动生成的build继承自系统的ant脚本,该脚本中的ant task可以直接复用,因此有了上面自己写的两个任务release2和signapk,分别表示了1和3阶段的任务。

步骤2的逻辑系统ant脚本里面没有现成的任务,需要自己编写,代码如下:

<target name="modichannel">
        <exec executable="${aapt}" taskName="remove">
            <arg value="remove" />
            <arg value="-v" />
            <arg value="./bin/${appname}-release-unsigned.apk" />
            <arg value="assets/channel" />
        </exec>
        <exec executable="${aapt}" taskName="add">
            <arg value="add" />
            <arg value="-v" />
            <arg value="./bin/${appname}-release-unsigned.apk" />
            <arg value="assets/channel" />
        </exec>
    </target>

这个任务做了两件事儿,第一,调用android sdk的aapt工具先删除未签名包中的默认渠道文件,第二,添加新渠道文件到未签名包。注意这里一定要用android自带的aapt工具操作apk压缩包,如果使用zip会对raw文件进行压缩,这个似乎并不符合apk打包的规范(aapt对raw文件的压缩有处理,注:对于zip和aapt压缩的区别并没有过多深入的了解,有兴趣的可以进一步探讨),导致打包出来的apk读取raw目录下的资源失败。

总结

整个打包流程,代码量不大,用shell实现打包流程控制,扩展了三个ant task。用这种方案,可以做到针对多渠道发布,只需要一次编译,多次渠道替换和签名,因为android编译很耗时,这样可以大大减少渠道的打包时间。

源码

http://code.taobao.org/p/android_build/src/

问题

总的来说还是比较简单的,当然整个过程也遇到了一些问题和雷区,列举一下,避免再次犯错,也算经验积累。

  1. 需要了解ant的继承机制,和任务依赖机制,这个是这次改造的基础,避免重复劳动,直接复用android自带ant脚本中的任务。
  2. 最纠结的过程是如何拆分release流程,插入渠道替换逻辑。这个过程遇到的问题最多。其实最后总结下来,拆分ant任务最简单的方式,在于看这个任务的子任务是否有共同的上下文依赖(比如运行时的环境变量依赖,等等),拆分到两个任务中的子任务之间最好不要有这种依赖,否则运行起来会出现变量值错误的问题,当然如果搞清楚整个流程也可以修改代码,但是工作量比较大。
  3. 对于apk压缩包的操作请使用android自带的aapt,避免直接使用zip,直接使用zip会将apk里面的raw资源压缩,导致有些rom下读取raw文件失败。

其实生成未签名包之后无需解压替换,直接aapt操作压缩包替换就好了,这样可以避免使用zip。

编写shell时当前路径要控制好,否则会很麻烦错误不断。

原文地址:https://www.cnblogs.com/youngerbaby/p/3085548.html