@linux1s1s
2019-02-15T15:11:57.000000Z
字数 7986
阅读 5202
2016-03 AndroidBuild
Android 打包可以借助工具Ant或者Gradle,了解这些工具如何使用前,有必要了解这些工具是怎么实现打包的。
本质上Android为我们提供了打包的工具,先看第一步需要使用的工具。

功能:
- 使用aapt命令编译资源文件
aapt package -f -m -J gen -S res -I D:/android-sdk-windows/platforms/android-16/android.jar -M AndroidManifest.xml
这里的命令参数有点多就不全部介绍了,就说明几个:
-J 后面跟着是gen目录,也就是编译之后产生的R类,存放的资源Id
-S 后面跟着是res目录,也就是需要编译的资源目录
-l 后面跟着是系统的库,因为我们在项目资源中会用到系统的一些资源文件,所以这里需要链接一下
-M 后面跟着是工程的清单文件,需要从这个文件中得到应用的包名,然后产生对应的R文件和包名.
aapt package -f -A assets -S res -I D:/android-sdk-windows/platforms/android-17/android.jar -M AndroidManifest.xml -F bin/AntDemo
这个命令其实就是将资源文件进行编码成二进制文件,
这些二进制文件都是有自己的格式的,系统编程二进制文件是为了优化,减小包的大小。
但是这里需要注意的是assets目录是不会进行二进制编译的。

功能: 使用javac命令编译源文件
javac -target 1.6 -bootclasspath D:/android-sdk-windows/platforms/android-17/android.jar -d bin gen\com\example\antdemo\*.java src\com\example\antdemo\*.java
这里的参数没什么好说的,其实都很简单
-target:表示编译之后的class文件运行的环境版本
-bootclasspath:表示编译需要用到的系统库
-d:表示编译之后的class文件存放的目录
后面就是需要编译的java文件了,不同的包下面的java文件,可以用空格分开即可,这里需要编译gen目录下面的java文件,和src下面的所有java文件。
和上面aapt.bat文件一样位于同一个目录下dx.bat
功能: 使用dx命令,将class文件转化成dex
dx --dex --output=G:\Code\Android\Workspace\AntDemo\bin\classes.dex G:\Code\Android\Workspace\AntDemo\bin
dx通配符用法如下,后面系列文章里面会介绍详细用法。

功能: 在android3.0这个apkbuilder被废弃了。这个批处理用来将编译好的文件构造一个apk。所以android3.0以后找不到这个bat脚本了
稍微了解一下这个脚本的基本用法
apkbuilder ${output.apk.file} -u -z ${packagedresource.file} -f ${dex.file} -rf ${source.dir} -rj ${libraries.dir}
-u 表示 创建一个未签名的apk
{packagedresource.file} 这个为编译好的资源包。 例如:d:/HelloWorld/bin/resources.ap_
-f {source.dir} 这个为源文件的路径。 例如:d:/HelloWorld/src
-rj ${libraries.dir} 这个表示引用的库的路径。例如:d:/HelloWorld/libs
功能: 构造apk,这个是android3.0以后替换apkbuilder的bat脚本
apktool b xxx xxx_unsigned.apk
b表示build package,xxx就是刚才你释放出来的文件夹,xxx_unsigned.apk就是重新打包的文件,unsigned的后缀是为了区分这个是未签名的程序,这个时候生成的是一个没有签名的文件,是装不上的,所以下面要增加签名。
apktool d -f xxx.apk xxx
d表示是decode,-f表示如果目标存在是覆盖。前面那个apk就是你要解包的文件,后面是解出来的文件夹名称。
功能:产生一个keystore文件
keytool -genkey -alias ant_test1 -keyalg RSA -validity 20000 -keystore my.keystore
具体使用详见Android 打包系列-签名
功能: 签名apk文件
jarsigner -keystore G:\Code\Android\Workspace\AntDemo\build\my.keystore -storepass 123456 -keypass 123456 -signedjar G:\Code\Android\Workspace\AntDemo\bin\AntDemo_signed.apk G:\Code\Android\Workspace\AntDemo\bin\AntDemo_unsigned.apk ant_test
具体使用详见Android 打包系列-签名

功能: Zipalign是一个android平台上整理APK文件的工具,它首次被引入是在Android 1.6版本的SDK软件开发工具包中。它能够对打包的Android应用程序进行优化, 以使Android操作系统与应用程序之间的交互作用更有效率,这能够让应用程序和整个系统运行得更快。用Zipalign处理过的应用程序执行时间达到最低限度,当设备运行APK应用程序时占更少的RAM(Random Access Memory)随机访问内存,我们强烈推荐在新的和已经发布的程序上使用zipalign工具来得到优化后的版本——即使你的程序是在老版本的Android平台下开发的。这篇文章将介绍zipalign运行原理,以及如何使用它来优化你的app。
zipalign -v 4 source.apk destination.apk
其中这里-v代表详细输出, 4代表对齐为4个字节,同时-f参数如果添加则会覆盖存在的输出文件。
对于是否有效可以通过 zipalign -c -v 4 destination.apk 来查看是否成功的优化了你的apk文件,这里-c参数代表检查对齐,可以看作是只读执行,最后Android123提示大家这步可能造成文件签名问题,注意和apk签名执行的顺序。
上面的工具介绍完以后,接着就可以了解一下打包的全局流程了。

上面是完整的打包工具介绍,如果我们不借助任何IDE,直接拿到工程文件,手工打包的话,就得利用上面提及的工具,然后按照上面说是的完整流程一步一步完成相应的步骤,最后得到apk并进一步zipalign优化即可。
如果不想手工那么麻烦,可以通过Ant或者Gradle来封装整个打包过程,下面举个Ant封装的例子。
<?xml version="1.0" encoding="UTF-8"?><projectname="AntDemo"default="release" ><!-- tools dir --><propertyname="sdk-folder"value="C:\Users\i\AppData\Local\Android\sdk" /><propertyname="platform-folder"value="${sdk-folder}\platforms\android-22" /><propertyname="platform-tools-folder"value="${sdk-folder}\build-tools\22.0.1" /><propertyname="jdk-folder"value="C:\Program Files\Java\jdk1.7.0_71" /><propertyname="android-jar"value="${platform-folder}\android.jar" /><propertyname="tools.aapt"value="${platform-tools-folder}\aapt.exe" /><propertyname="tools.javac"value="${jdk-folder}\bin\javac.exe" /><propertyname="tools.dx"value="${platform-tools-folder}\dx.bat" /><propertyname="tools.apkbuilder"value="${sdk-folder}\tools\apkbuilder.bat" /><propertyname="tools.jarsigner"value="${jdk-folder}\bin\jarsigner.exe" /><!-- project dir --><propertyname="project-dir"value="C:\Users\i\Desktop\AntDemo\AntDemo" /><propertyname="res"value="${project-dir}\res" /><propertyname="gen"value="${project-dir}\gen" /><propertyname="src"value="${project-dir}\src" /><propertyname="bin"value="${project-dir}\bin" /><propertyname="assets"value="${project-dir}\assets" /><propertyname="libs"value="${project-dir}\libs" /><!-- file lists --><propertyname="manifest"value="${project-dir}\AndroidManifest.xml" /><propertyname="java-file-gen"value="${gen}\com\example\antdemo\*.java" /><propertyname="java-file-src"value="${src}\com\example\antdemo\*.java" /><propertyname="dex-name"value="${bin}\classes.dex" /><propertyname="pakcage-temp-name"value="${bin}\${ant.project.name}" /><propertyname="unsigned-apk-name"value="${ant.project.name}_unsigned.apk" /><propertyname="unsigned-apk-path"value="${bin}\${unsigned-apk-name}" /><propertyname="signed-apk-name"value="${ant.project.name}.apk" /><propertyname="signed-apk-path"value="${bin}\${signed-apk-name}" /><propertyname="keystore-name"value="${project-dir}\my.keystore" /><propertyname="keystore-alias"value="ant_test" /><!-- task --><target name="init" ><echo>Initialize...</echo><delete dir="${bin}" /><mkdir dir="${bin}" /></target><targetname="gen-R"depends="init" ><echo>Generating R.java from the resources...</echo><execexecutable="${tools.aapt}"failonerror="true" ><arg value="package" /><arg value="-f" /><arg value="-m" /><arg value="-J" /><arg value="${gen}" /><arg value="-S" /><arg value="${res}" /><arg value="-M" /><arg value="${manifest}" /><arg value="-I" /><arg value="${android-jar}" /></exec></target><targetname="compile"depends="gen-R" ><echo>Compile...</echo><javacbootclasspath="${android-jar}"compiler="javac1.7"target="1.7"destdir="${bin}"encoding="utf-8"includeAntRuntime="true"listfiles="true"><src path="${project-dir}"/><classpath><!-- 引用第三方jar包需要引用,用于辅助编译,并没有将jar打包进去。jar的打包在dex命令中。--><fileset dir="${libs}" includes="*.jar" /></classpath></javac></target><targetname="dex"depends="compile" ><echo>Generate dex...</echo><execexecutable="${tools.dx}"failonerror="true" ><arg value="--dex" /><arg value="--output=${dex-name}" /><arg value="${bin}" /><!-- classes文件位置 --><arg value="${libs}"/><!-- 把libs下所有jar打包 --></exec></target><targetname="package"depends="dex" ><echo>Package resource and assets...</echo><execexecutable="${tools.aapt}"failonerror="true" ><arg value="package" /><arg value="-f" /><arg value="-A" /><arg value="${assets}" /><arg value="-S" /><arg value="${res}" /><arg value="-I" /><arg value="${android-jar}" /><arg value="-M" /><arg value="${manifest}" /><arg value="-F" /><arg value="${pakcage-temp-name}" /></exec></target><targetname="build-unsigned-apk"depends="package" ><echo>Build unsigned apk</echo><!--<execexecutable="${tools.apkbuilder}"failonerror="true" ><arg value="${unsigned-apk-path}" /><arg value="-v" /><arg value="-u" /><arg value="-z" /><arg value="${pakcage-temp-name}" /><arg value="-f" /><arg value="${dex-name}" /><arg value="-rf" /><arg value="${src}" /></exec>--><java classpath="${sdk-folder}/tools/lib/sdklib.jar" classname="com.android.sdklib.build.ApkBuilderMain"><arg value="${unsigned-apk-path}" /><arg value="-u" /><arg value="-z" /><arg value="${pakcage-temp-name}" /><arg value="-f" /><arg value="${dex-name}" /><arg value="-rf" /><arg value="${src}" /><arg value="-rj"/><arg value="${libs}"/></java></target><targetname="sign-apk"depends="build-unsigned-apk" ><echo>Sign apk</echo><execexecutable="${tools.jarsigner}"failonerror="true" ><arg value="-keystore" /><arg value="${keystore-name}" /><arg value="-storepass" /><arg value="123456" /><arg value="-keypass" /><arg value="123456" /><arg value="-signedjar" /><arg value="${signed-apk-path}" /><arg value="${unsigned-apk-path}" /><arg value="${keystore-alias}" /></exec></target><targetname="release"depends="sign-apk" ><delete file="${pakcage-temp-name}" /><delete file="${unsigned-apk-path}" /><echo>APK is released. path:${signed-apk-path}</echo></target></project>
对于build.xml来说,target是个完整的可以执行的任务,整个任务可以有依赖,依赖关系从左向右依次执行,所以从上面的build.xml可以看出完全按照上面流程图顺序执行的。
使用ant跑一下脚本:ant release

其实,不用通过Ant脚本,也可以直接通过bat脚本或者python/shell等其他脚本顺序执行这些打包工具即可。
注:上面有些图和xml来自如何使用Ant脚本编译出Jar和Apk包这篇博客,特此说明。