当我们在Eclipse中对项目Run As Android Application的时候,会在bin文件夹下生成apk及其他一些文件,至于为什么生成这些文件开始我也不明白,查了相关资料才知道原来Android项目在Eclipse中是通过Ant进行构建的。学习Ant踩了很多坑,总结下来以后方便查看,也希望帮助更多的人。欢迎评论交流哦!
1、下载Ant并配置环境变量
Ant下载地址:http://ant.apache.org/bindownload.cgi;下载后直接解压到某目录下就OK。
添加Ant环境变量:ANT_HOME,变量值指向ant目录。
添加配置到Path中:%ANT_HOME%/bin;%ANT_HOME%/lib;
通过cmd命令行查看是否配置成功:
通过Ant打包Apk还需要配置JDK、Android SDK:
- JDK的配置大家肯定都会了。
- 添加系统环境变量ANDROID_HOME,值是Android sdk的路径。
2、配置打包项目
通过cmd进入到待代打包项目目录下执行android update project -n epeiwang -p . 命令。执行该命令后刷新项目,此时项目中会多build.xml
和local.properties文件。在项目下新建名为ant.properties的文件(非必须)然后将签名文件keystore放到项目下面或其他路径下。
- build.xml :定义了基础构建方法和打包策略的脚本。
- local.properties:存放sdk路径和其他一些本地配置。
- ant.properties:定义一些变量,一般为签名文件的地址,密码、别名等。
- 签名文件:用于对Ant打包后的Apk进行签名。
local.properties
sdk.dir=D:\\adt-bundle-windows\\sdk
ant.properties
#签名文件的路径
keystore=magic.keystore
#存储库口令
storepass=123456
#密匙库口令
keypass=123456
#别名
alias=magic
3、Ant打包流程
Ant打包主要流程:
1. 删除gen、bin目录并新建
2. 生成R.java类文件
3. 编译aidl文件
4. 编译源文件生成对应的class文件
5. 将.class文件转化成.dex文件
6. 打包资源文件
7. 生成未签名的apk包
8. 对未签名的apk包进行签名
9. 对签名的apk包进行字节对齐
(原图地址:http://blog.youkuaiyun.com/jason0539/article/details/44917745)
以上流程主要借助于sdk和jdk提供的相关工具进行完成。例如:aapt、dx、apkbuilder、jarsigner等,build.xml的编写其实就是对这些工具的使用。其中生成未签名的apk包可以,通过sdklib.jar配置新的apkbuilder使用或者直接使用sdklib.jar。
通过sdklib.jar配置新的apkbuilder.bat生成未签名的apk:
因为apkbuilder.bat在新版本的Android sdk中已经被移除,所以我们需要手动创建apkbuilder.bat文件,然后将此文件放在sdk tools目录下,apkbuilder.bat文件内容如下:
@echo off
rem Copyright (C) 2007 The Android Open Source Project
rem
rem Licensed under the Apache License, Version 2.0 (the "License");
rem you may not use this file except in compliance with the License.
rem You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
rem don't modify the caller's environment
setlocal
rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
rem Check we have a valid Java.exe in the path.
set java_exe=
call lib\find_java.bat
if not defined java_exe goto :EOF
set jarfile=sdklib.jar
set frameworkdir=
if exist %frameworkdir%%jarfile% goto JarFileOk
set frameworkdir=lib\
if exist %frameworkdir%%jarfile% goto JarFileOk
set frameworkdir=..\framework\
:JarFileOk
set jarpath=%frameworkdir%%jarfile%
call "%java_exe%" -classpath %jarpath% com.android.sdklib.build.ApkBuilderMain %*
build.xml脚本中使用
<!-- 根据classes.dex文件和resources.ap_生成未签名的apk包 -->
<target
name="package"
depends="package-res-and-assets" >
<echo message="package..."/>
<exec
executable="${apkbuilder}"
failonerror="true" >
<arg value="${unsigned-package}" /><!-- 输出 -->
<arg value="-u" /><!-- u指创建未签名的包-->
<arg value="-z" /><!-- 资源压缩包 -->
<arg value="${resources-package}" />
<arg value="-f" /><!-- dex文件 -->
<arg value="${bin}/classes.dex" />
<arg value="-rf" />
<arg value="${src}" />
<arg value="-rj" />
<arg value="${libs}" />
<arg value="-nf" />
<arg value="${libs}" />
</exec>
</target>
直接使用sdklib.jar生成未签名的apk:
build.xml脚本中使用
<!-- 根据classes.dex文件和resources.ap_生成未签名的apk包 -->
<target
name="package" depends="build-res-and-assets"
>
<echo message="package..."/>
<java
classname="com.android.sdklib.build.ApkBuilderMain"
classpath="${sdklib}" >
<arg value="${unsigned-package}" />
<arg value="-u" /> <!-- 创建一个未签名的包 -->
<arg value="-z" /> <!-- 资源压缩包 -->
<arg value="${resources-package}" />
<arg value="-f" /> <!-- dex文件-->
<arg value="${bin}/classes.dex" />
</java>
</target>
4、完整的build.xml脚本
使用的时候直接复制该脚本并修改相关路径就可以,并不需要对每个工具的命令详细掌握。
通过cmd进入到待代打包项目目录下执行 ant make 命令即可进行打包。
<?xml version="1.0" encoding="UTF-8"?>
<project
name="Test_HotFix"
default="make" >
<property file="local.properties" />
<property file="ant.properties" />
<property environment="env" />
<condition
property="sdk.dir"
value="${env.ANDROID_HOME}" >
<isset property="env.ANDROID_HOME" />
</condition>
<!-- 相关目录 -->
<!-- 代表相对路径 -->
<property
name="basedir"
value="." />
<property
name="sdk-tools"
value="${sdk.dir}/tools" />
<property
name="sdk-build-tools"
value="${sdk.dir}/build-tools/android-4.4.2" />
<property
name="android-jar"
value="${sdk.dir}/platforms/android-19/android.jar" />
<property
name="framework-aidl"
value="${sdk.dir}/platforms/android-19/framework.aidl" />
<!-- 编译工具 -->
<property
name="aapt"
value="${sdk-build-tools}/aapt.exe" />
<property
name="aidl"
value="${sdk-build-tools}/aidl.exe" />
<property
name="dx"
value="${sdk-build-tools}/dx.bat" />
<property
name="apkbuilder"
value="${sdk-tools}/apkbuilder.bat" />
<property
name="jarsigner"
value="${env.JAVA_HOME}/bin/jarsigner.exe" />
<property
name="zipalign"
value="${sdk-build-tools}/zipalign.exe" />
<!-- 输入目录 -->
<property
name="assets"
value="${basedir}/assets" />
<property
name="res"
value="${basedir}/res" />
<property
name="src"
value="${basedir}/src" />
<property
name="libs"
value="${basedir}/libs" />
<!-- 输出目录 -->
<property
name="bin"
value="${basedir}/bin" />
<property
name="gen"
value="${basedir}/gen" />
<property
name="resources-package"
value="${bin}/resources.ap_" />
<property
name="unsigned-package"
value="${bin}/${ant.project.name}-unsigned.apk" />
<property
name="signed-package"
value="${bin}/${ant.project.name}-singed.apk" />
<property
name="zipalign-package"
value="${bin}/${ant.project.name}-zipalign.apk" />
<!-- 初始化 -->
<!-- 删除gen、bin目录并新建 -->
<target name="init" >
<echo message="init..." />
<delete dir="${bin}" />
<delete dir="${gen}" />
<mkdir dir="${bin}" />
<mkdir dir="${gen}" />
</target>
<!-- 生成R.java类文件 -->
<target
name="gen-R"
depends="init" >
<echo message="gen-R..." />
<exec
executable="${aapt}"
failonerror="true" >
<arg value="package" /><!-- package表示打包-->
<arg value="-m" /><!--m,J,gen表示创建包名的目录和R.java到gen目录下 -->
<arg value="-J" />
<arg value="${gen}" />
<arg value="-M" /><!-- M指定AndroidManifest.xml文件-->
<arg value="AndroidManifest.xml" />
<arg value="-S" /> <!-- S指定res目录 -->
<arg value="${res}" />
<arg value="-A" />
<arg value="${assets}" />
<arg value="-I" /><!-- I指定android包的位置-->
<arg value="${android-jar}" />
</exec>
</target>
<!-- 编译aidl文件 -->
<target
name="aidl"
depends="gen-R" >
<echo message="aidl..."/>
<apply
executable="${aidl}"
failonerror="true" >
<arg value="-p${framework-aidl}" />
<arg value="-I${src}" />
<arg value="-o${gen}" />
<fileset dir="${src}" >
<include name="**/*.aidl" />
</fileset>
</apply>
</target>
<!-- 编译源文件生成对应的class文件 -->
<target
name="compile"
depends="aidl" >
<echo message="compile..."/>
<javac
bootclasspath="${android-jar}"
destdir="${bin}"
encoding="gbk"
includeantruntime="false"
source="1.6"
target="1.6" >
<compilerarg value="-nowarn" />
<src path="${src}" />
<src path="${gen}" />
<classpath>
<fileset
dir="${libs}"
includes="*.jar" />
</classpath>
</javac>
</target>
<!-- 将.class文件转化成.dex文件 -->
<target
name="dex"
depends="compile" >
<echo message="dex..."/>
<exec
executable="${dx}"
failonerror="true" >
<arg value="--dex" />
<arg value="--output=${bin}" /><!-- 输出位置 -->
<arg value="${bin}" /><!-- classes文件位置 -->
<arg value="${libs}" /><!-- 把libs下所有jar打包 -->
</exec>
</target>
<!-- 打包资源文件(包括res、assets、AndroidManifest.xml) -->
<target
name="package-res-and-assets"
depends="dex" >
<echo message="package-res-and-assets..."/>
<exec
executable="${aapt}"
failonerror="true" >
<arg value="package" />
<arg value="-f" /><!-- 资源覆盖重写 -->
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${res}" />
<arg value="-A" /><!-- 与R.java不同,需要asset目录也打包 -->
<arg value="${assets}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" /><!-- 输出资源压缩包 -->
<arg value="${resources-package}" />
</exec>
</target>
<!-- 根据classes.dex文件和resources.ap_生成未签名的apk包 -->
<target
name="package"
depends="package-res-and-assets" >
<echo message="package..."/>
<exec
executable="${apkbuilder}"
failonerror="true" >
<arg value="${unsigned-package}" /><!-- 输出 -->
<arg value="-u" /><!-- u指创建未签名的包-->
<arg value="-z" /><!-- 资源压缩包 -->
<arg value="${resources-package}" />
<arg value="-f" /><!-- dex文件 -->
<arg value="${bin}/classes.dex" />
<arg value="-rf" />
<arg value="${src}" />
<arg value="-rj" />
<arg value="${libs}" />
<arg value="-nf" />
<arg value="${libs}" />
</exec>
</target>
<!-- 对上面生成的apk包进行签名 -->
<target
name="jarsigner"
depends="package" >
<echo message="jarsigner..."/>
<exec
executable="${jarsigner}"
failonerror="true" >
<arg value="-verbose" />
<arg value="-digestalg" />
<arg value="SHA1" />
<arg value="-sigalg" />
<arg value="SHA1withRSA" />
<arg value="-keystore" /><!-- keystore -->
<arg value="${keystore}" />
<arg value="-storepass" /><!-- 秘钥 -->
<arg value="${storepass}" />
<arg value="-keypass" /><!-- 秘钥口令-->
<arg value="${keypass}" />
<arg value="-signedjar" />
<arg value="${signed-package}" /><!--输出 -->
<arg value="${unsigned-package}" /><!-- 未签名的apk -->
<arg value="${alias}" /><!-- 别名 -->
</exec>
</target>
<!-- 对签名的apk包进行字节对齐 -->
<target
name="make"
depends="jarsigner" >
<echo message="zipalign..."/>
<exec
executable="${zipalign}"
failonerror="true" >
<arg value="-f" />
<arg value="-v" />
<arg value="4" />
<arg value="${signed-package}" />
<arg value="${zipalign-package}" />
</exec>
<echo message="make apk success!" />
</target>
</project>
参考文章:
http://blog.youkuaiyun.com/jason0539/article/details/44917745;
http://www.cnblogs.com/qianxudetianxia/archive/2012/07/04/2573687.html;
生命不止,奋斗不息!