android打包apk流程

android 打包apk 打包流程

最近研究了一下Android打包apk的流程,简要描述一下。

我们可以跟随android的sdk目录下的tools/ant/build.xml文件的描述来一窥打包apk流程究竟。

首先这是用ant打包的过程,eclipse打包流程应该大抵一样。用ant打包前,如果project不是用ant创建的,先需要执行android update project -p /path/to/project。该命令会在project目录下生成相应的配置文件。如build.xml(与sdk下的那个不同),project.properties,local.properties等。生成的几个文件都是项目相关的配置参数等。ant打包需要build.xml配置文件,project下的配置文件包含sdk/tools/ant/build.xml文件。

project下的build.xml相对简单了,设定一些project属性,引用了project.properties,local.properties等文件。build.xml设定了ant的默认行为(target)是help。显示相应帮助。

sdk/tools/ant/build.xml相对复杂很多,一共有1300+行。乍看很多,粗粗分析开来,一块一块也相对较为明朗。即便我对ant配置一知半解,也看个大概明白。<property>就是设定一些key-value的属性,<target>就是ant对应的目标,类似于Makefile的那个目标。

这个build.xml相应地方做了良好的注释。这个文件内容分布大概如下:

1.定义一些覆盖默认设置的属性。还是有一些挺有意思的属性值得一看的,比如android.package.excludes,设定该属性可以排除编译一部分代码。再比如version.code,version.name可以替换AndroidManifest.xml中的相关版本内容。

2.自定义了一些任务。凭借我的揣测,这是ant提供的一些扩展,这些任务是通过${sdk.dir}/tools/lib/anttasks.jar这个jar包来导入定义的。定义了很多,列举一二,如com.android.ant.NewSetupTask,com.android.ant.AaptExecTask,com.android.ant.IfElseTask等等。

3.其它属性。主要是编译流程用到的一些变量属性,包含输入目录,输出目录,工具位置等。这里可以看见一些经常看到用到的目录和工具。比如src自不用多说,还有gen目录,libs目录等。此处加一段故事,很久之前,我是用Eclipse好的project在带我的bear那里用ant编译有问题,问题在于我将外部的jar包放在了lib目录下,ant编译的时候会找不到这个jar包了,但是放在libs里就可以了,到了这就可以解释了,因为build.xml暗暗的定义了这个默认的文件夹的名字。再插一句最新的adt也支持放在libs中而不需要做多余路径设定了。

4.宏定义。定义了一些多次用的流程为宏。比如do-only-if-not-library,如果不是android library project就怎样做。package-helper等等。

5.Build过程的一些Target。第一个是nodeps,很简单是设定了一个属性,来设定targets间是否存在依赖关系。然后有-per-clean,clean清空bin,gen目录做了这么些事。(前面加-的target,从某种程度来说是private的target,因为输入ant -xxx的时候,-xxx会当作ant的参数,而不是build的目标)

然后就涉及打包流程了。-setup,做一些初始化工作,创建bin目录等,设定一些属性等。-build-setup,也是做一些build的初始化工作。然后是-per-build这个是空的,这个是用来给用户做一些自定义设定或者实现预留的,后面类似这样预留的无内容的部分我就不讲了。然后是-code-gen,这个就有意思一些了,最为人熟知的android中的R文件就要生成了,生成R文件在这个过程做了定义,通过aapt程序(这个程序很有意思,这里略去不讲,没准下回会讲)生成R文件。-code-gen过程还有一些重量级的东西。比如生成用于进程通信的aidl文件相应类的生成,还有renderscript的生成。还有BuildConfig文件的生成。然后就是激动人心的compile编译过程了,就是javac做编译,生成class文件。这里有些令人激动的事情。就是Android为了代码复用,提出了library project的概念,某种程度上还不错,但是扩展能力有限,还是有些坑爹的,而且有一些限制。此处再插故事一则,我有3个project,分别标记为a,b,c,a,b分别是library project,然后依赖是c=>b=>a(c依赖于b,b依赖于a),我想对b做代码混淆,但是出现一些依赖问题。因为android的现在的这个build过程并不把在前面-code-gen生成的依赖的子library的R文件编译到这个library自己的这里,所以在混淆b的时候,会出现a中的R无法找到的问题,因为a中的R会被便已到c中,很混乱吧。事情是这样,但是错误在自己,因为对android的library和整个project的打包流程不清楚,所以造成了上面的窘境。其实根本不用混淆b工程,因为b工程的class会最终放到c中,最后在c中混淆就行了。晕了。。。

继续说打包流程,编译完了,然后就是-obfuscate混淆过程了,混淆默认只在release模式下才进行,内部有一些判断。关于混淆的一些介绍,可以参见我的上一篇博文《ProGuard总结和混淆Android代码中遇到的问题的解决方法以及寻找getSomething游戏》。然后是-dex,转.class到.dex过程。开发Android的都知道,Android没有用标准的jvm,而是自己专门为移动设备优化实现的dalvik vm。这个过程会把所有的.class文件打包到一个.dex文件中。

至此,代码build过程就结束了。全都结束了吗?还没有,Android还有编译资源,再说还没打成apk包呢。

跟资源处理有关的过程先是-crunch这个过程就是对png图片做一些压缩处理。具体怎么处理的咱就不细究了,想知道的话可以研究源代码去。然后又到了激动人心的资源打包过程-package-resources,这个过程就是用牛x的aapt,将所有res目录下的资源文件manifest等文件打包编译处理。这其中有一个对于.9.png的说明。我们知道.9.png的图片是带一圈透明画有黑点的图片。这个过程aapt会将.9.png处理,将透明带黑点写入二进制。和原来的图是不一样了的,逆向工程的时候对.9.png有很多限制。apktool的wiki上有相关说明。xda论坛上也有相关讨论。还有一点是将普通.png改为.9.png的后,ant全程打包是不会有问题的。但是aapt确实对这种情况做了抛出异常处理,所以我猜想是在crunch时做了什么处理,还未证实。

资源文件也build好了,然后对于debug或release。就是打包成apk。然后给apk签名,签名方式上两种模式有些不同处理。debug会进行debug签名,release需要你提供你的签名文件等。然后或进行zipalign操作,字节对齐。

至此,整个过程就结束了。

还有一些关于测试和安装卸载的target就不写了。

重点过程,加粗标识了,看一遍加粗部分,基本就能知道个大概了



命令行中通过ant打包apk

ant 打包apk 命令行 apk自动打包

参考自:http://developer.Android.com/guide/developing/building/building-cmdline.html

第一步:安装ant,从官网下载最新版ant并解压缩,配置ant环境变量,ant_home和path

第二步:在cmd下切换到项目根目录,执行以下命令: android update project -t 14 -p E:\other\AntTest(项目路径)

这个命令运行后会在项目根目录下生成build.xml文件

第三步:在cmd下执行ant debug命令会在项目的bin目录下生成使用debug签名的apk

第四步:若要生成自定义签名apk,则在项目根目录下添加ant.properties文件,配置密钥的路径和别名

key.store=路径
key.store.password=
key.alias=
key.alias.password=

在cmd下执行ant release会在bin目录下生成自定义签名apk,



本文简要介绍如何通过Ant脚本Androidproject编译打包成APK文件并安装到手机。

主要步骤:

1生成R.Java类文件:利用ant和命令行使用android SDK提供的aapt.ext程序生成R.java。
2将.aidl文件生成.java类文件:利用ant和命令行使用android SDK提供的aidl.exe生成.java文件。
3第三步 编译.java类文件生成class文件:利用ant和命令行使用jdk的javac编译java类文件生成class文件。
4第四步 将class文件打包生成classes.dex文件:利用ant命令行使用android SDK提供的dx.bat命令行脚本生成classes.dex文件。
5第五步 打包资源文件(包括res、assets、androidmanifest.xml等):ant命令行使用Android SDK提供的aapt.exe生成资源包文件。
6第六步 生成未签名的apk安装文件:ant和命令行使用android SDK提供的apkbuilder.bat命令脚本生成未签名的apk安装文件。
7第七步 对未签名的apk进行签名生成签名后的android文件:ant和命令行使用jdk的jarsigner对未签名的包进行apk签名。
8第八步 安装和卸载APK文件,利用ant命令行使用Android SDK提供的adb.exe。

下面贴出build脚本和property文件:具体例子可以从http://download.csdn.net/source/3505789 下载。

<?xml version="1.0" encoding="UTF-8"?>
< project name="AntTest" default="help">

<property file="build.properties" />

<path id="android.antlibs">
<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
<pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
<pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
</path>

<path id="project.classpath">
<pathelement location="${android-jar}" />
</path>
<taskdef name="setup" classname="com.android.ant.SetupTask" classpathref="android.antlibs" />
<setup/>

<target name="copy">
<copy todir="${outdir-gen}">
<fileset dir="${srcdir}" />
</copy>
</target>
<target name="GenRJAVA">
<echo>Generating R.java from the resources...</echo>
<mkdir dir="${outdir-gen}" />
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-m" />
<arg value="-J" />
<arg value="${outdir-gen}" />
<arg value="-M" />
<arg value="${projecthomedir}/AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
</target>
<target name="aidl" depends="copy">
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failonerror="true">
<arg value="-p${sdk.dir}" />
<arg value="-I${srcdir}" />
<fileset dir="${srcdir}">
<include name="**/*.aidl" />
</fileset>
</apply>
</target>
<!-- Compile this project's .java files into .class files. -->
<target name="compile" depends="copy, GenRJAVA, aidl">
<mkdir dir="${outdir-classes}" />
<javac encoding="UTF-8" target="1.5" debug="true" extdirs="" srcdir="${outdir-gen}" destdir="${outdir-classes}" bootclasspath="${android-jar}">
<classpath refid="project.classpath" />
</javac>
</target>

<!-- Convert this project's .class files into .dex files. -->
<target name="dex" depends="compile">
<echo>Converting compiled files and external libraries into ${outdir-dx}/test.dex...</echo>
<mkdir dir="${outdir-dx}" />
<apply executable="${dx}" failonerror="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${outdir-dx}/test.dex" />
<arg path="${outdir-classes}" />
<fileset dir="${projecthomedir}" includes="*.jar" />
</apply>
</target>
<!-- Put the project's resources into the output package file. -->
<target name="package-res">
<echo>Packaging resources and assets...</echo>
<mkdir dir="${apkdir}" />
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="${projecthomedir}/AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-A" />
<arg value="${asset-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
</target>

<target name="packageAPK" depends="dex, package-res">
<echo>Packaging apk for release...</echo>
<exec executable="${apkbuilder}" failonerror="true">
<arg value="${apkdir}/${unsignedapkname}" />
<arg value="-u" />
<arg value="-z" />
<arg value="${resources-package}" />
<arg value="-f" />
<arg value="${outdir-dx}/test.dex" />
<arg value="-rf" />
<arg value="${srcdir}" />
<arg value="-rj" />
<arg value="${outdir-gen}" />
</exec>
<echo>It will need to be signed with jarsigner before being published.</echo>
</target>
<target name="signAPK" depends="packageAPK">
<echo>signAPK ${apkdir}/${apkname}</echo>
<signjar
jar="${apkdir}/${unsignedapkname}"
signedjar="${apkdir}/${apkname}"
keystore="keystore"
storepass="123456"
alias="alias"
keypass="123456"
verbose="-verbose" />
<!--
<exec executable="${jarsigner}" failonerror="true">
<arg value="-verbose" />
<arg value="-storepass" />
<arg value="test" />
<arg value="-keypass" />
<arg value="test" />
<arg value="-keystore" />
<arg value="bbyread.keystore" />
<arg value="-signedjar" />
<arg value="${apkdir}/${apkname}" />
<arg value="${apkdir}/${unsignedapkname}" />
<arg value="byread" />
</exec>-->
</target>

<target name="installAPK" depends="signAPK">
<echo>Install APK...</echo>

<exec executable="adb" failonerror="true">
<arg value="install" />
<arg value="${apkdir}/${apkname}" />
</exec>
</target>

<target name="uninstallAPK">
<echo>uninstall APK..</echo>
<exec executable="adb" failonerror="true">
<arg value="uninstall" />
<arg value="com.anttest" />
</exec>
</target>

<target name="help" />

< /project>

property文件内容:

target=android-8
sdk.dir=D:\\Android\\android-sdk-windows

apkbuilder=${sdk.dir}\\tools\\apkbuilder.bat

android-jar=${sdk.dir}\\platforms\\android-8\\android.jar

projecthomedir=D:\\Android\\AndriodWK\\AntTest
builddir=${projecthomedir}\\build
resource-dir=${projecthomedir}\\res
asset-dir=${projecthomedir}\\assets
srcdir=${projecthomedir}\\src

outdir-gen=${builddir}\\src
outdir-classes=${builddir}\\classes
outdir-dx=${builddir}\\dx
resources-package=${builddir}\\respak
apkdir=${builddir}\\apk
unsignedapkname=unsigntest.apk
apkname=test.apk


更多相关文章

  1. 在Android中建立Android project没有R.java文件
  2. Android系统启动过程分析
  3. Android应用程序请求SurfaceFlinger服务渲染Surface的过程分析
  4. Android的相关文件类型
  5. Android根文件系统的启动过程
  6. Android焦点分发基本流程

随机推荐

  1. android 怎样用代码设置墙纸
  2. RemoteView流程
  3. android 自定义View之Path详解
  4. 百度地图集成
  5. Android 不在崩溃
  6. Android——Activity的生命周期
  7. Android WindowManager的使用 & 添加 遮
  8. 使用GDB调试Android(安卓)NDK native(C/C
  9. android之点击事件ImageView切换
  10. Android对IO进行读写操作实例