@linux1s1s
2019-02-15T23:11:57.000000Z
字数 7986
阅读 4786
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"?>
<project
name="AntDemo"
default="release" >
<!-- tools dir -->
<property
name="sdk-folder"
value="C:\Users\i\AppData\Local\Android\sdk" />
<property
name="platform-folder"
value="${sdk-folder}\platforms\android-22" />
<property
name="platform-tools-folder"
value="${sdk-folder}\build-tools\22.0.1" />
<property
name="jdk-folder"
value="C:\Program Files\Java\jdk1.7.0_71" />
<property
name="android-jar"
value="${platform-folder}\android.jar" />
<property
name="tools.aapt"
value="${platform-tools-folder}\aapt.exe" />
<property
name="tools.javac"
value="${jdk-folder}\bin\javac.exe" />
<property
name="tools.dx"
value="${platform-tools-folder}\dx.bat" />
<property
name="tools.apkbuilder"
value="${sdk-folder}\tools\apkbuilder.bat" />
<property
name="tools.jarsigner"
value="${jdk-folder}\bin\jarsigner.exe" />
<!-- project dir -->
<property
name="project-dir"
value="C:\Users\i\Desktop\AntDemo\AntDemo" />
<property
name="res"
value="${project-dir}\res" />
<property
name="gen"
value="${project-dir}\gen" />
<property
name="src"
value="${project-dir}\src" />
<property
name="bin"
value="${project-dir}\bin" />
<property
name="assets"
value="${project-dir}\assets" />
<property
name="libs"
value="${project-dir}\libs" />
<!-- file lists -->
<property
name="manifest"
value="${project-dir}\AndroidManifest.xml" />
<property
name="java-file-gen"
value="${gen}\com\example\antdemo\*.java" />
<property
name="java-file-src"
value="${src}\com\example\antdemo\*.java" />
<property
name="dex-name"
value="${bin}\classes.dex" />
<property
name="pakcage-temp-name"
value="${bin}\${ant.project.name}" />
<property
name="unsigned-apk-name"
value="${ant.project.name}_unsigned.apk" />
<property
name="unsigned-apk-path"
value="${bin}\${unsigned-apk-name}" />
<property
name="signed-apk-name"
value="${ant.project.name}.apk" />
<property
name="signed-apk-path"
value="${bin}\${signed-apk-name}" />
<property
name="keystore-name"
value="${project-dir}\my.keystore" />
<property
name="keystore-alias"
value="ant_test" />
<!-- task -->
<target name="init" >
<echo>
Initialize...
</echo>
<delete dir="${bin}" />
<mkdir dir="${bin}" />
</target>
<target
name="gen-R"
depends="init" >
<echo>
Generating R.java from the resources...
</echo>
<exec
executable="${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>
<target
name="compile"
depends="gen-R" >
<echo>
Compile...
</echo>
<javac
bootclasspath="${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>
<target
name="dex"
depends="compile" >
<echo>
Generate dex...
</echo>
<exec
executable="${tools.dx}"
failonerror="true" >
<arg value="--dex" />
<arg value="--output=${dex-name}" />
<arg value="${bin}" /><!-- classes文件位置 -->
<arg value="${libs}"/><!-- 把libs下所有jar打包 -->
</exec>
</target>
<target
name="package"
depends="dex" >
<echo>
Package resource and assets...
</echo>
<exec
executable="${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>
<target
name="build-unsigned-apk"
depends="package" >
<echo>
Build unsigned apk
</echo>
<!--
<exec
executable="${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>
<target
name="sign-apk"
depends="build-unsigned-apk" >
<echo>
Sign apk
</echo>
<exec
executable="${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>
<target
name="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包这篇博客,特此说明。