apk打包流程
以上图就是整个apk打包的流程.
具体流程可以分为8步:
1. 通过aapt工具将 资源文件(res)、清单文件(AndroidManifest.xml)生成对应的R.java文件.
2. 通过aidl工具 将 aidl文件转化为java文件.
3. 通过javac工具,将.java文件转化为.class文件.
4. 将libs下的jar解压到输出目录中.
5. 通过dex命令 将class文件转换为dex文件.
6. 通过aapt工具生成资源文件包.
7. 生成未签名的apk安装文件.
8. 生成签名的apk安装文件.
以上流程不管是命令行打包还是ant打包, 都是不变的,下面我们来说一下完整的ant打包.
ant使用
- ant环境变量的配置.
首先下载http://ant.apache.org/bindownload.cgi.
和jdk一样配置ANT_HOME ,在PATH中添加ANT_HOME目录下的bin目录 - 测试.
在CMD命令行中输入ant -version, 显示ant版本则说明配置成功. 使用
- ant脚本命名必须是build.xml,当然你可以不这样命名,但是这样是有好处的.
- 如何运行ant脚本: 在当前目录运行ant命令即可(已配好环境变量)
语法
首先, 我们先来看以下代码:<?xml version="1.0" encoding="UTF-8"?> <!-- <!DOCTYPE project SYSTEM "ant.dtd" > --> <!-- project根标签:代表项目; basedir属性:项目根目录; default:默认执行的任务 --> <!-- target:任务标签,每一个任务指令都需要一个target --> <!-- mkdir:创建目录标签 --> <!-- echo:打印标签,打印的内容由message属性指定 --> <project name="MyProject" default="printMessage"> <!-- 获取环境变量 --> <property environment="env"/> <!-- build所在目录 --> <property name="buildDir" location="${basedir}/build"/> <!-- 打印JAVA_HOME任务 --> <target name="printJavaHome"> <echo message="${env.JAVA_HOME}"/> </target> <!-- depends:指定任务执行顺序,依赖关系 --> <target name="printMessage" depends="printJavaHome"> <echo message="Hello ant"/> </target> <target name="mkBuildDir"> <mkdir dir="${buildDir}"/> </target> <target name="mkClassesDir"> <mkdir dir="${buildDir}/classes"/> </target> <target name="mkBinDir"> <mkdir dir="${buildDir}/bin"/> </target> <!-- 初始化任务:创建目录 --> <target name="init" depends="mkClassesDir,mkBinDir"/> <!-- 删除目录 --> <target name="deleteBuildDir"> <delete dir="${buildDir}"/> </target> </project>
注意:以上代码不具有任何参考价值, 仅作解释ant标签以及语法的使用,请勿深究.
不知道你是不是已经看出有一个符号${名称}
没错,这就是一个引用.
相信你对ant的基本的语法已经有了一定的了解, 那么, 只要使用这样的语法按照以下的命令格式就可以打包一个apk了.
具体打包命令
首先你有一个未打包的完整的项目(没有bin目录等), 在项目的根目录下新建 gen目录(参考eclipse),并且依次在gen目录下新建清单文件总包名对应的文件目录
例如: 清单文件中包名是org.example.android,那么就在gen目录中新建目录结构为 gen/org/example/android
通过命令生成R.java
aapt package -f -m -J [R文件目录(gen)] -S [资源文件目录(res)] -I [android环境jar(android.jar)] -M [清单文件(AndroidManifest.xml)]
[]的参数都是可选参数。
[-d]: 指定一个或多个设备的资源文件被添加,多个资源文件用逗号隔开__
[-f]: 是否覆盖已经存在的文件(添加此参数即为覆盖,否则不覆盖)__
[-m]: 打包资源的文件目录,目录地址是-J
参数指定__
[-J]: 指定R文件生成的目录__
[-S]: 需要打包的资源文件目录__
[-I]: 指定环境android.jar的文件目录__
[-M]: 清单文件的路径__通过aidl工具 将 aidl文件转化为java文件
aidl -I[项目的源文件目录(src)] -p[aidl框架环境文件(framework.aidl)] -o[aidl输出目录(gen)] [要转换的aidl文件(your.aidl)]
通过javac工具,将.java文件转化为.class文件
javac -encoding [编码(gbk or utf-8)] -target [版本(1.6 or 1.7)] -bootclasspath [android环境jar(android.jar)] -cp [依赖的jar(多个用;隔开;结尾)] -d [class文件输出目录] [要编译的java文件(多个用空格分开)]
将libs下的jar解压到输出目录中
jar xvf [jar文件]
通过dex命令 将class文件转换为dex文件
dx.bat –dex –output=[全路径的输出文件(classes.dex)] [全路径的class文件对应的目录]
[全路径的class文件对应的目录] : 如果此目录依赖了其他的jar文件,需要用 |分隔开
命令: dex.bat –dex –output=输出路径 需要转换的class文件对应的路径通过aapt工具生成资源文件包
aapt package -f -M [清单文件(AndroidManifest.xml)] -S [资源文件目录(res)] -A [资产文件目录(assets)] -I [android环境jar(android.jar)] -F [输出的文件(resoures.ap_)]
生成未签名的apk安装文件
apkbuilder [输出的全路径apk] -u -z [全路径打包好的资源文件包] -f [全路径dex文件] -rf [全路径的src目录] -rj [全路径的libs目录]
生成签名的apk安装文件
- 生成签名文件
keytool -genkeypair -alias “itheima” -validity 365 -keyalg “RSA” -keystore itheima.keystore
-alias : 签名的别名 -validity : 签名的时效 -keyalg : 加密的算法 -keystore : 生成的签名路径
- 通过签名文件给apk文件进行签名
jarsigner -keystore 签名文件 -storepass 签名文件的密码 -keypass 签名密码 -signedjar 生成的签名文件 未签名的文件 签名的别名
以下为参考代码,注意,代码本身没有任何参考意义,仅作帮助理解ant的使用
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE project SYSTEM "ant.dtd" > -->
<project name="MyProject" default="signedApk">
<!-- gen目录 -->
<property name="genDir" location="${basedir}/gen"/>
<!-- build目录 -->
<property name="buildDir" location="${basedir}/build"/>
<property name="classesDir" location="${basedir}/build/classes"/>
<!-- res目录 -->
<property name="resDir" location="${basedir}/res"/>
<!-- src目录 -->
<property name="srcDir" location="${basedir}/src"/>
<!-- android.jar目录 -->
<property name="androidJar" location="E:\AndroidSdk\platforms\android-19\android.jar"/>
<!-- 清单文件目录 -->
<property name="mainfestDir" location="${basedir}/AndroidManifest.xml"/>
<!-- framework.aidl所在目录 -->
<property name="frameworkAidlDir" location="E:\AndroidSdk\platforms\android-19\framework.aidl"/>
<target name="deleteDir">
<delete dir="${genDir}"/>
<delete dir="${buildDir}"/>
</target>
<!-- 任务:初始化-删除目录、创建目录 -->
<!-- 任务:创建gen目录 -->
<target name="mkGenDir" depends="deleteDir">
<mkdir dir="${genDir}"/>
<mkdir dir="${buildDir}"/>
<mkdir dir="${classesDir}"/>
</target>
<!-- aapt命令 -->
<property name="aapt" location="E:\AndroidSdk\platform-tools\aapt.exe"/>
<!-- aidl命令 -->
<property name="aidl" location="E:\AndroidSdk\platform-tools\aidl.exe"/>
<!-- 任务:生成R文件 -->
<!-- aapt package -f -m -J gen -S res -I E:\AndroidSdk\platforms\android-19\android.jar -M Android
Manifest.xml -->
<target name="genR" depends="mkGenDir">
<exec executable="${aapt}">
<arg value="p"/>
<arg value="-f"/>
<arg value="-m"/>
<arg value="-J"/>
<arg value="${genDir}"/>
<arg value="-S"/>
<arg value="${resDir}"/>
<arg value="-I"/>
<arg value="${androidJar}"/>
<arg value="-M"/>
<arg value="${mainfestDir}"/>
</exec>
</target>
<!-- aidl生成java -->
<!-- aidl -Isrc -pE:\AndroidSdk\platforms\android-19\framework.aidl -ogen src\com\android\internal
\telephony\ITelephony.aidl -->
<target name="aidlCompile" depends="genR">
<apply executable="${aidl}">
<arg value="-I${srcDir}"/>
<arg value="-p${frameworkAidlDir}"/>
<arg value="-o${genDir}"/>
<!-- 指定aidl文件所在目录,所有aidl文件-->
<fileset dir="${srcDir}" includes="**/*.aidl"/>
</apply>
</target>
<!-- 任务:java编译成class -->
<!-- javac -encoding [编码(gbk or utf-8)] -target [版本(1.6 or 1.7)]
-bootclasspath [android环境jar(android.jar)] -cp [依赖的jar(多个用;隔开;结尾)]
-d [class文件输出目录] [要编译的java文件(多个用空格分开)] -->
<property name="libsDir" location="${basedir}/libs"></property>
<target name="javaCompile" depends="aidlCompile">
<javac encoding="utf-8" bootclasspath="${androidJar}" destdir="${classesDir}">
<classpath>
<!-- 指定libs目录下所有jar包 -->
<fileset includes="**/*.jar" dir="${libsDir}"/>
</classpath>
<!-- java文件所在目录,src和gen -->
<src path="${srcDir}"/>
<src path="${genDir}"/>
</javac>
</target>
<!-- 解压libs下所有jar包 -->
<target name="unJar" depends="javaCompile">
<!-- unjar标签:解压 ,dest属性表示解压的目录-->
<unjar dest="${classesDir}">
<fileset includes="**/*.jar" dir="${libsDir}"/>
</unjar>
</target>
<!-- dx.bat命令 -->
<property name="dx" location="E:\AndroidSdk\build-tools\23.0.3\dx.bat"/>
<!-- classes.dex 目录-->
<property name="dexDir" location="${buildDir}/classes.dex"/>
<target name="dexCompile" depends="unJar">
<exec executable="${dx}">
<arg value="--dex"/>
<arg value="--output=${dexDir}"/>
<arg value="${classesDir}"/>
</exec>
</target>
<!-- 资产目录 -->
<property name="assetDir" location="${basedir}/assets"/>
<!-- resources.ap_所在目录 -->
<property name="resourcesApDir" location="${buildDir}/resources.ap_"/>
<!-- 任务:打包资源文件resources.ap_ -->
<target name="resourcesCompile" depends="dexCompile">
<exec executable="${aapt}">
<arg value="p"/>
<arg value="-f"/>
<arg value="-M"/>
<arg value="${mainfestDir}"/>
<arg value="-S"/>
<arg value="${resDir}"/>
<arg value="-A"/>
<arg value="${assetDir}"/>
<arg value="-I"/>
<arg value="${androidJar}"/>
<arg value="-F"/>
<arg value="${resourcesApDir}"/>
</exec>
</target>
<!-- apkbuilder命令 -->
<property name="apkbuilder" location="E:\AndroidSdk\tools\apkbuilder.bat"/>
<!-- 未签名apk目录 -->
<property name="unsignedApkDir" location="${buildDir}/MykeySave_unsigned.apk"/>
<!-- apkbuilder [输出的全路径apk] -u -z [全路径打包好的资源文件包] -f [全路径dex文件] -rf [全路径的src目录] -rj [全路径的libs目录] -->
<target name="unsignedApk" depends="resourcesCompile">
<exec executable="${apkbuilder}">
<arg value="${unsignedApkDir}"/>
<arg value="-u"/>
<arg value="-z"/>
<arg value="${resourcesApDir}"/>
<arg value="-f"/>
<arg value="${dexDir}"/>
<arg value="-rf"/>
<arg value="${srcDir}"/>
<arg value="-rj"/>
<arg value="${libsDir}"/>
</exec>
</target>
<!-- 签名apk -->
<property name="signedApkDir" location="${buildDir}/MykeySave_signed.apk"/>
<property environment="evn"/>
<!-- jarsigner.exe命令 -->
<property name="jarsigner" location="${evn.JAVA_HOME}/bin/jarsigner.exe"/>
<!-- 任务:生成签名apk -->
<target name="signedApk" depends="unsignedApk">
<exec executable="${jarsigner}">
<arg value="-keystore"/>
<arg value="${basedir}/mykeystore.keystore"/>
<arg value="-storepass"/>
<arg value="123456"/>
<arg value="-keypass"/>
<arg value="123456"/>
<arg value="-signedjar"/>
<arg value="${signedApkDir}"/>
<arg value="${unsignedApkDir}"/>
<arg value="mykeystore"/>
</exec>
</target>
</project>