[关闭]
@linux1s1s 2019-02-15T23:11:57.000000Z 字数 7986 阅读 4816

Android 打包系列-基本打包流程

2016-03 AndroidBuild


Android 打包可以借助工具Ant或者Gradle,了解这些工具如何使用前,有必要了解这些工具是怎么实现打包的。

Tools

本质上Android为我们提供了打包的工具,先看第一步需要使用的工具。

aapt

此处输入图片的描述

功能:
- 使用aapt命令编译资源文件

  1. 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文件和包名.

  1. 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命令编译源文件

  1. 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文件。

dx

和上面aapt.bat文件一样位于同一个目录下dx.bat

功能: 使用dx命令,将class文件转化成dex

  1. dx --dex --output=G:\Code\Android\Workspace\AntDemo\bin\classes.dex G:\Code\Android\Workspace\AntDemo\bin

dx通配符用法如下,后面系列文章里面会介绍详细用法。
此处输入图片的描述

apkbuilder

功能: 在android3.0这个apkbuilder被废弃了。这个批处理用来将编译好的文件构造一个apk。所以android3.0以后找不到这个bat脚本了

稍微了解一下这个脚本的基本用法

  1. 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

apktool

功能: 构造apk,这个是android3.0以后替换apkbuilder的bat脚本

  1. apktool b xxx xxx_unsigned.apk

b表示build package,xxx就是刚才你释放出来的文件夹,xxx_unsigned.apk就是重新打包的文件,unsigned的后缀是为了区分这个是未签名的程序,这个时候生成的是一个没有签名的文件,是装不上的,所以下面要增加签名。

  1. apktool d -f xxx.apk xxx

d表示是decode,-f表示如果目标存在是覆盖。前面那个apk就是你要解包的文件,后面是解出来的文件夹名称。

keytool

功能:产生一个keystore文件

  1. keytool -genkey -alias ant_test1 -keyalg RSA -validity 20000 -keystore my.keystore

具体使用详见Android 打包系列-签名

jarsigner

功能: 签名apk文件

  1. 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

此处输入图片的描述

功能: Zipalign是一个android平台上整理APK文件的工具,它首次被引入是在Android 1.6版本的SDK软件开发工具包中。它能够对打包的Android应用程序进行优化, 以使Android操作系统与应用程序之间的交互作用更有效率,这能够让应用程序和整个系统运行得更快。用Zipalign处理过的应用程序执行时间达到最低限度,当设备运行APK应用程序时占更少的RAM(Random Access Memory)随机访问内存,我们强烈推荐在新的和已经发布的程序上使用zipalign工具来得到优化后的版本——即使你的程序是在老版本的Android平台下开发的。这篇文章将介绍zipalign运行原理,以及如何使用它来优化你的app。

  1. zipalign -v 4 source.apk destination.apk

其中这里-v代表详细输出, 4代表对齐为4个字节,同时-f参数如果添加则会覆盖存在的输出文件。
对于是否有效可以通过 zipalign -c -v 4 destination.apk 来查看是否成功的优化了你的apk文件,这里-c参数代表检查对齐,可以看作是只读执行,最后Android123提示大家这步可能造成文件签名问题,注意和apk签名执行的顺序。

Flow path

上面的工具介绍完以后,接着就可以了解一下打包的全局流程了。

此处输入图片的描述

上面是完整的打包工具介绍,如果我们不借助任何IDE,直接拿到工程文件,手工打包的话,就得利用上面提及的工具,然后按照上面说是的完整流程一步一步完成相应的步骤,最后得到apk并进一步zipalign优化即可。

如果不想手工那么麻烦,可以通过Ant或者Gradle来封装整个打包过程,下面举个Ant封装的例子。

Ant封装打包

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project
  3. name="AntDemo"
  4. default="release" >
  5. <!-- tools dir -->
  6. <property
  7. name="sdk-folder"
  8. value="C:\Users\i\AppData\Local\Android\sdk" />
  9. <property
  10. name="platform-folder"
  11. value="${sdk-folder}\platforms\android-22" />
  12. <property
  13. name="platform-tools-folder"
  14. value="${sdk-folder}\build-tools\22.0.1" />
  15. <property
  16. name="jdk-folder"
  17. value="C:\Program Files\Java\jdk1.7.0_71" />
  18. <property
  19. name="android-jar"
  20. value="${platform-folder}\android.jar" />
  21. <property
  22. name="tools.aapt"
  23. value="${platform-tools-folder}\aapt.exe" />
  24. <property
  25. name="tools.javac"
  26. value="${jdk-folder}\bin\javac.exe" />
  27. <property
  28. name="tools.dx"
  29. value="${platform-tools-folder}\dx.bat" />
  30. <property
  31. name="tools.apkbuilder"
  32. value="${sdk-folder}\tools\apkbuilder.bat" />
  33. <property
  34. name="tools.jarsigner"
  35. value="${jdk-folder}\bin\jarsigner.exe" />
  36. <!-- project dir -->
  37. <property
  38. name="project-dir"
  39. value="C:\Users\i\Desktop\AntDemo\AntDemo" />
  40. <property
  41. name="res"
  42. value="${project-dir}\res" />
  43. <property
  44. name="gen"
  45. value="${project-dir}\gen" />
  46. <property
  47. name="src"
  48. value="${project-dir}\src" />
  49. <property
  50. name="bin"
  51. value="${project-dir}\bin" />
  52. <property
  53. name="assets"
  54. value="${project-dir}\assets" />
  55. <property
  56. name="libs"
  57. value="${project-dir}\libs" />
  58. <!-- file lists -->
  59. <property
  60. name="manifest"
  61. value="${project-dir}\AndroidManifest.xml" />
  62. <property
  63. name="java-file-gen"
  64. value="${gen}\com\example\antdemo\*.java" />
  65. <property
  66. name="java-file-src"
  67. value="${src}\com\example\antdemo\*.java" />
  68. <property
  69. name="dex-name"
  70. value="${bin}\classes.dex" />
  71. <property
  72. name="pakcage-temp-name"
  73. value="${bin}\${ant.project.name}" />
  74. <property
  75. name="unsigned-apk-name"
  76. value="${ant.project.name}_unsigned.apk" />
  77. <property
  78. name="unsigned-apk-path"
  79. value="${bin}\${unsigned-apk-name}" />
  80. <property
  81. name="signed-apk-name"
  82. value="${ant.project.name}.apk" />
  83. <property
  84. name="signed-apk-path"
  85. value="${bin}\${signed-apk-name}" />
  86. <property
  87. name="keystore-name"
  88. value="${project-dir}\my.keystore" />
  89. <property
  90. name="keystore-alias"
  91. value="ant_test" />
  92. <!-- task -->
  93. <target name="init" >
  94. <echo>
  95. Initialize...
  96. </echo>
  97. <delete dir="${bin}" />
  98. <mkdir dir="${bin}" />
  99. </target>
  100. <target
  101. name="gen-R"
  102. depends="init" >
  103. <echo>
  104. Generating R.java from the resources...
  105. </echo>
  106. <exec
  107. executable="${tools.aapt}"
  108. failonerror="true" >
  109. <arg value="package" />
  110. <arg value="-f" />
  111. <arg value="-m" />
  112. <arg value="-J" />
  113. <arg value="${gen}" />
  114. <arg value="-S" />
  115. <arg value="${res}" />
  116. <arg value="-M" />
  117. <arg value="${manifest}" />
  118. <arg value="-I" />
  119. <arg value="${android-jar}" />
  120. </exec>
  121. </target>
  122. <target
  123. name="compile"
  124. depends="gen-R" >
  125. <echo>
  126. Compile...
  127. </echo>
  128. <javac
  129. bootclasspath="${android-jar}"
  130. compiler="javac1.7"
  131. target="1.7"
  132. destdir="${bin}"
  133. encoding="utf-8"
  134. includeAntRuntime="true"
  135. listfiles="true">
  136. <src path="${project-dir}"/>
  137. <classpath>
  138. <!-- 引用第三方jar包需要引用,用于辅助编译,并没有将jar打包进去。jar的打包在dex命令中。-->
  139. <fileset dir="${libs}" includes="*.jar" />
  140. </classpath>
  141. </javac>
  142. </target>
  143. <target
  144. name="dex"
  145. depends="compile" >
  146. <echo>
  147. Generate dex...
  148. </echo>
  149. <exec
  150. executable="${tools.dx}"
  151. failonerror="true" >
  152. <arg value="--dex" />
  153. <arg value="--output=${dex-name}" />
  154. <arg value="${bin}" /><!-- classes文件位置 -->
  155. <arg value="${libs}"/><!-- 把libs下所有jar打包 -->
  156. </exec>
  157. </target>
  158. <target
  159. name="package"
  160. depends="dex" >
  161. <echo>
  162. Package resource and assets...
  163. </echo>
  164. <exec
  165. executable="${tools.aapt}"
  166. failonerror="true" >
  167. <arg value="package" />
  168. <arg value="-f" />
  169. <arg value="-A" />
  170. <arg value="${assets}" />
  171. <arg value="-S" />
  172. <arg value="${res}" />
  173. <arg value="-I" />
  174. <arg value="${android-jar}" />
  175. <arg value="-M" />
  176. <arg value="${manifest}" />
  177. <arg value="-F" />
  178. <arg value="${pakcage-temp-name}" />
  179. </exec>
  180. </target>
  181. <target
  182. name="build-unsigned-apk"
  183. depends="package" >
  184. <echo>
  185. Build unsigned apk
  186. </echo>
  187. <!--
  188. <exec
  189. executable="${tools.apkbuilder}"
  190. failonerror="true" >
  191. <arg value="${unsigned-apk-path}" />
  192. <arg value="-v" />
  193. <arg value="-u" />
  194. <arg value="-z" />
  195. <arg value="${pakcage-temp-name}" />
  196. <arg value="-f" />
  197. <arg value="${dex-name}" />
  198. <arg value="-rf" />
  199. <arg value="${src}" />
  200. </exec>
  201. -->
  202. <java classpath="${sdk-folder}/tools/lib/sdklib.jar" classname="com.android.sdklib.build.ApkBuilderMain">
  203. <arg value="${unsigned-apk-path}" />
  204. <arg value="-u" />
  205. <arg value="-z" />
  206. <arg value="${pakcage-temp-name}" />
  207. <arg value="-f" />
  208. <arg value="${dex-name}" />
  209. <arg value="-rf" />
  210. <arg value="${src}" />
  211. <arg value="-rj"/>
  212. <arg value="${libs}"/>
  213. </java>
  214. </target>
  215. <target
  216. name="sign-apk"
  217. depends="build-unsigned-apk" >
  218. <echo>
  219. Sign apk
  220. </echo>
  221. <exec
  222. executable="${tools.jarsigner}"
  223. failonerror="true" >
  224. <arg value="-keystore" />
  225. <arg value="${keystore-name}" />
  226. <arg value="-storepass" />
  227. <arg value="123456" />
  228. <arg value="-keypass" />
  229. <arg value="123456" />
  230. <arg value="-signedjar" />
  231. <arg value="${signed-apk-path}" />
  232. <arg value="${unsigned-apk-path}" />
  233. <arg value="${keystore-alias}" />
  234. </exec>
  235. </target>
  236. <target
  237. name="release"
  238. depends="sign-apk" >
  239. <delete file="${pakcage-temp-name}" />
  240. <delete file="${unsigned-apk-path}" />
  241. <echo>
  242. APK is released. path:${signed-apk-path}
  243. </echo>
  244. </target>
  245. </project>

对于build.xml来说,target是个完整的可以执行的任务,整个任务可以有依赖,依赖关系从左向右依次执行,所以从上面的build.xml可以看出完全按照上面流程图顺序执行的。

使用ant跑一下脚本:ant release

此处输入图片的描述

其实,不用通过Ant脚本,也可以直接通过bat脚本或者python/shell等其他脚本顺序执行这些打包工具即可。

注:上面有些图和xml来自如何使用Ant脚本编译出Jar和Apk包这篇博客,特此说明。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注