使用Ant打包Android应用详解

转自:http://blog.csdn.net/w7849516230/article/details/47829111

  计划写个完整的使用Ant打包Android应用的系列文章,三篇文章。首篇详细介绍采用Ant打包Android应用的流程,列出部分定制问题及其解决方法,第二篇介绍我理解的Ant打包的思路与基本的概念和使用,最后一篇描述apk包的生成过程。
    实现的环境:
    操作系统:ubuntu 64bit 14.04
    Android SDK Build Tools:22.0.1
    Android SDK Tools:24.3.3
    Ant:1.9.4
     ProGuard:5.2.1
    JDK:1.7
一、简单应用出包流程
  这里的出包流程包括编译、代码混淆、apk签名。对于简单的Android应用,简单的几步操作就能完成:
1.生成Ant编译需要的build.xml
    在SDK目录的tools下,调用android update project生成,具体命令的用法可以查看参考1,例如:切换到你的工程目录
    android update project --name 自己起的工程名 -p .
    -p参数后面的点是表示当前目录
    在工程目录下就会生成Ant编译需要的build.xml,直接运行ant debug,即可完成编译,并在bin目录下生成debug版本的apk包。需要注意的几个问题是:
(1)自动生成的build.xml生成了几个跟Android相关的target呢:可以通过直接输入ant来查看help说明
(2)遇到 BUILD FAILED如何解决:可以查看BUILD FAILED上面的log看执行到什么地方,还有看提示在build.xml的哪一行出现问题,这里的build.xml是指在sdk/tools/ant下的,例如:
  1. [aapt] invalid resource directory name: 工程目录/bin/res crunch  
  2.   
  3. BUILD FAILED  
  4. sdk/tools/ant/build.xml:649: The following error occurred while executing this line:  
  5. build.xml:694:null returned: 1  
一般看到 res crunch,应该就是你在eclipse中工程自动编译的文件与ant生成文件冲突,只要关掉eclipse的自动编译,clean下工程重新跑ant即可。
  (3)可以留心看下project.properties和local.properties
2.添加代码混淆
在工程的project.properties文件中有注释说明如何打开代码混淆
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
去除#号即可,同时可以在 proguard-project.txt增加你需要特殊处理的配置

修改后,再执行ant release,你会在输出中看到
  1. -obfuscate:  
  2. [mkdir] Created dir:工程目录/bin/proguard  
  3. [jar] Building jar: 工程目录/bin/proguard/original.jar  
  4. [proguard] ProGuard, version 5.2.1  
  5. ...  

可以看到我用的proguard版本,但是用ant debug是没有proguard,因为只有release版本才需要混淆,具体原因后续文章会详细讲述。混淆后的mapping文件在bin目录下。
    注意的问题:工程的AndroidManifest.xml中如果配置了android:debuggable=true,那么即使ant release也不会混淆代码
3.签名
    首先给apk签名需要keystore,具体的生成此处不细讲,简单的说在eclipse中选则工程,右键android tools -> export android application 中有生成选项
    其次是在工程目录下新建ant.properties文件,里面配置你的签名信息
例如:
key.store=kestore文件的路径
key.store.password=密码
key.alias.password=密码
key.alias=别名
此时再执行ant release,在bin目录下可生成“工程名-release.apk”,你最终要的release版本的apk

到此,简单android工程的的ant编译打包完成,非常方便。

二、添加定制化
    1.加入so库
    Android应用的Ant编译默认是不会编译jni工程的,它只会处理libs中的库文件。如果你的libs中刚好有编译好的so,那打包好的apk似乎能正常运行。在配置好的jni工程,只要运行ndk的ndk-build即可完成so的编译。因此,只要在build.xml同目录中添加custom_rules.xml文件,内容如下:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <project name="工程名" default="help">  
  3. <target name="-pre-compile">  
  4.     <echo >ndk build.............................</echo>  
  5.     <exec executable="${ndk.dir}/ndk-build" >  
  6.     </exec>  
  7. </target>  
  8.   
  9. </project>  
在同目录下的local.properties中增加一行,指定你的ndk目录
ndk.dir=ndk路径
再次执行ant release,查看你的so库是否已生成

    如果你的jni工程是作为库工程存在,方法是一样的。主工程依赖你的库工程,在库工程中也生成build.xml,然后按照上面的方法操作即可。
    2.调用隐藏api,加入android.jar
    不少工程是基于Android原生代码修改而来,或者就是想调用系统隐藏的部分api,就会用到别人编译好的android.jar,或者framework.jar等其它什么名字的库文件,而且会要求加载的顺序在你选择的android编译版本之前。在eclipse的Java Build Path->Libraries中调整其加载顺序,那么ant编译怎么修改呢?还是利用前面编写的custom_rules.xml,内容如下:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <project name="hooktest" default="help">  
  3. <property name="project.target.android.jar" value="${sdk.dir}/platforms/${target}/android.jar" />  
  4. <target name="-pre-compile">  
  5.   
  6.     <echo >set project target class path.............................</echo>  
  7.   
  8.     <path id="project.target.class.path">  
  9.     <pathelement location="framework.jar"/>  
  10.     <pathelement location="${project.target.android.jar}"/>  
  11.     </path>  
  12.   
  13.     <property name="my.project.target.class.path" refid="project.target.class.path" />  
  14.     <echo message="project.target.class.path:${my.project.target.class.path}" />  
  15.   
  16. </target>  
  17. </project>  
3.一个工程中多源码目录
    如果一个工程中设置了多个源码目录,不太合适的方法就是先拷贝其它的源码目录到默认的src下,在编译完成后再删除。其实顺便看看文件拷贝和删除,在多源码目录的工程中也建立custom_rules.xml,主要内容如下:
  1. <target name="-pre-build">  
  2.     <echo >copy file.............................</echo>  
  3.     <copy todir="${source.absolute.dir}">  
  4.   
  5.      <fileset dir="其它源码目录">  
  6.         <include name="**/*.java" />  
  7.         <include name="**/*.aidl" />  
  8.     </fileset>  
  9.     </copy>  
  10. </target>  
  11.   
  12. <target name="src-clean" >  
  13.     <echo >delete file.............................</echo>  
  14.     <delete dir="${source.absolute.dir}/拷贝的源码目录" />  
  15. </target>  
  16.   
  17. <target name="-post-build" depends="src-clean">  
  18. </target>  
  19. <target name="-pre-clean" depends="src-clean">  
  20. </target>  
上述代码在执行ant clean时也会执行删除拷贝的源码操作,而在编译前先拷贝源码,包括aidl文件,之后在打包完成后删除拷贝的源码目录。

   一个工程中的源码尽量就弄在一个目录里吧。其它问题还有如库工程间的资源引用,如果直接使用默认的R文件是没有问题的,但是要是在eclipse中利用build Java Build Path->project添加了子工程,并且还用了其中的R文件来应用资源,那么ant打包就还得再继续折腾

结尾:
    这里仅给出了使用Ant打包Android应用的基本过程和可能问题的解决方法,至于ant的使用和打包原理既可以看参考文章,也可以看后续的补充文章。

参考:
1.android命令详细说明http://developer.android.com/tools/help/android.html
2.ant参考手册 https://ant.apache.org/manual/
3.ant打包apk详细的过程可阅读sdk/tools/ant/build.xml文件


  上篇 《使用Ant打包Android应用详解》描述了使用Ant打包的流程,但很多步骤并没有说明如此做的原因,本篇将从Ant方面来理解,下一篇从APK生成的流程来说明。

  APK包的生成是一系列操作的结果,而Ant则是将这一系列操作流程化,提供出定制化的接口,以及可配置的参数供修改,而这些都是通过指定的构建文件来实现。我们就从Ant的打包流程来理解Ant的一些基本用法。当在命令行中执行ant,默认会去解析当前目录的build.xml作为构建文件。下面是个删除部分注视的版本:

  1. <project name="工程名" default="help">  
  2.   
  3.  <!-- The local.properties file is created and updated by the 'android' tool.  
  4.  It contains the path to the SDK. It should *NOT* be checked into  
  5.  Version Control Systems. -->  
  6.  <property file="local.properties" />  
  7.   
  8.  <property file="ant.properties" />  
  9.   
  10.  <!--  
  11.  Import per project custom build rules if present at the root of the project.  
  12.  This is the place to put custom intermediary targets such as:  
  13.  -pre-build  
  14.  -pre-compile  
  15.  -post-compile (This is typically used for code obfuscation.  
  16.  Compiled code location: ${out.classes.absolute.dir}  
  17.  If this is not done in place, override ${out.dex.input.absolute.dir})  
  18.  -post-package  
  19.  -post-build  
  20.  -pre-clean  
  21.  -->  
  22.  <import file="custom_rules.xml" optional="true" />  
  23.   
  24.  <!-- Import the actual build file.  
  25.  <import file="${sdk.dir}/tools/ant/build.xml" />  
再跟进到你的SDK目录的tools/ant/build.xml,查看Ant打包的完整过程。
    1.首先理解几个概念,project、target、task。简单来说,你的一个构建工程(project),划分了很多阶段或者子目标(target),而每个阶段目标的实现,你要提供具体的操作,比如文件复制,源码编译,这些封装好的操作就是task(可以理解为为你提供的库函数)。具体看,每个构建文件都有顶层为project的标签,作为标识,而target就是你所要执行的操作序列,target里面可以有很多的task。那么怎么确定操作序列执行的顺序呢?其中project的default指的是默认执行的target,也就是当你在命令行只输入ant不带任何参数时,执行的target。而当你指定了target后,如在命令行中输入ant help,会从你的构建文件中找到target help执行。当我们输入ant release时,对应的target如下:
  1. <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.">  
  2.  </target>  
target的name和description顾名思义,而depends则是该target执行前,需要执行或者说依赖的target,而且是依据从左到右的顺序依次执行。继续跟进-package它的定义:<target name="-package" depends="-dex, -package-resources">,分别是dex文件的生成和资源打包,里面又定义了很多具体的target。整个过程中就有或者说预留了一些空的target,比如-pre-build -pre-compile -post-package -post-build,是每个打包编译步骤之前后结束,通过在custom_rules.xml中重写这些target,达到定制化的要求
  2.解决了执行序列的问题,那么如何进行参数配置呢?
(1)首先在工程下的build.xml中property,可以理解为定义了部分变量或者引入了property 文件,看其部分属性:
name:property的名称,在target或者其它地方可以通过${name}的形式引用
value:具体的值或路径
file:需要加载的property文件,文件中的内容以key=value中出现,如local.properties中定义的sdk.dir=android的sdk路径
refid:引用已经定义的path信息
自己工程的build.xml中property定义的local.properties引入了android sdk/ndk,ant.properties引入了签名时需要的信息;这里有个关键的特性是,一旦定义了property,其值是不能改变的,而且会保留最先定义的值;也就是这个特性,方便了在编译过程中的一些定制化操作。如上篇中调用隐藏api,将自己的framework.jar加入到project.target.class.path中
(2)import标签,属性file:要引入的构建文件,optional:值为true时,即使import的文件不存在,也不停止编译。那么custom_rules.xml是可有可无,而${sdk.dir}/tools/ant/build.xml是定义了真正的编译步骤的文件必须存在
   3.一些用到的其它标签
(1)定义文件目录path,从ant手册中的例子看:
  1. <path id="base.path">  
  2.       <pathelement path="${classpath}"/>  
  3.       <fileset dir="lib">  
  4.         <include name="**/*.jar"/>  
  5.       </fileset>  
  6.       <pathelement location="classes"/>  
  7.  </path>  
一个可以在其它地方通过refid引用的path,里面包括了具体path路径pathelement和通过include或exclude来筛选文件的fileset
(2)copy task
  1. <copy todir="${source.absolute.dir}">  
  2.   
  3.      <fileset dir="其它源码目录">  
  4.         <include name="**/*.java" />  
  5.         <include name="**/*.aidl" />  
  6.     </fileset>  
  7.  </copy>  
odir:目标目录,源目录在fileset上定义,规则是包括所有.java文件和所有aidl文件;简单的如拷贝单个文件
<copy file="myfile.txt" tofile="mycopy.txt"/>
拷贝一个文件到某个目录
<copy file="myfile.txt" todir="../some/other/dir"/>
这些信息都可以通过查询ant参考手册https://ant.apache.org/manual/来了解,不一一叙述


通过上述描述应该可以理解并跟进整个ant打包android应用的流程,根据自己的需要进行定制化操作





  前文使用Ant打包Android应用详解》《使用Ant打包Android应用详解——Ant使用解析》讲述了如何使用Ant及打包apk,本文总结下apk包的生成过程。

    apk包就是一个zip格式文件(可通过二进制软件查看其是否压缩),利用解压缩软件可看到其结构如图所示:


  总的可分为资源、代码、签名信息,具体为资源:assets、res、resources.arsc,android应用的配置清单AndroidManifest.xml文件 代码:classes.dex 和lib目录中的共享库文件 签名:META-INF
再来看这些文件具体的生成过程如同所示:

此图省略了对aidl文件,so文件等的处理
  1.aapt资源处理:
  aapt扫描android工程目录中的资源文件,一方面处理png图片,生成二进制的xml文件(解压apk包是无法看到xml文件内容的),另一方面索引资源,生成R.java文件,将aidl文件生成对应的Java源文件
  2.编译代码
(1)src目录中的源文件,上面生成的java文件通过javac编译生成class文件,与lib库中的jar文件一起,通过dx程序转化成被dalvik虚拟机执行的dex文件
(2)jni目录中的源文件,利用ndk-build编译后生成so文件,保存在lib目录中
  3.归档
  apkbuilder(新版的sdk中已经见不到它的影子,其实都是在sdklib.jar中)将处理的资源文件、代码文件、lib库文件以zip格式归档在一个apk文件中
  4.签名
  利用jarsigner,对apk文件进行签名,相应的在META-INF目录中生成*.RSA *.SF和MANIFEST.MF,其中MANIFEST.MF文件记录了对除META-INF目录外的其它文件计算的摘要值

  对应到Ant的打包步骤上,打包生成apk文件的过程如下图所示(解析SDK中build.xml的release mode):

  基本的过程是首先初始化基本参数,如是否是库工程,是打包成debug版还是release版,是否需要使用proguard混淆代码,其次就是打包(package),最后如果是release版本就需要签名和zip包优化 。同时也可以返回查看并理解 使用Ant打包Android应用详解》中定制化的步骤及原因。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值