Android 项目编译过程

 

Android 项目编译过程

分类: Android  4195人阅读 评论(5) 收藏 举报

Android 工程构建的持续集成,需要搭建一套编译和打包自动化流程,比如建立每日构建系统、自动生成发布文件等等。这些都需要我们对Android工程的编译和打包有一个比较深入的理解,例如知道它的每一步都做了什么,需要什么环境和工具,输入和输出是什么,等等。


首先,假定你的系统(Windows、Linux、Mac OS都行,本文默认使用Linux系统来举例子,但在 Windows中几乎没有什么差别)已经安装了JDK和Android SDK, 如果没有安装,可以参考我先前的博客: Ubuntu搭建Eclipse+JDK+SDK的Android 和 Windows搭建Eclipse+JDK+SDK的Android

再假定你的Android SDK的路径是ANDROID_SDK_HOME,你想要编译的Android OS版本是ANDROID_OS_VERSION(比如android-1.6、android-8、android-10等)。

我们重点关心的是:

    (1)这个过程的输入是什么?

    (2)这个过程的输出是什么?

    (3)这个过程使用了什么工具?

至于使用什么参数,可以自己去看对应命令的帮助文件,或者在网上搜索,这不是本文的重点。




提前列出下列步骤中需要用到的工具,如下表:

名称功能介绍在操作系统中的路径
aaptAndroid资源打包工具${ANDROID_SDK_HOME}/platform-tools/appt
aidlAndroid接口描述语言转化为.java文件的工具${ANDROID_SDK_HOME}/platform-tools/aidl
javacJava Compiler${JDK_HOME}/javac或/usr/bin/javac
dex转化.class文件为Davik VM能识别的.dex文件${ANDROID_SDK_HOME}/platform-tools/dx
apkbuilder生成apk包${ANDROID_SDK_HOME}/tools/opkbuilder
jarsigner.jar文件的签名工具${JDK_HOME}/jarsigner或/usr/bin/jarsigner
zipalign字节码对齐工具${ANDROID_SDK_HOME}/tools/zipalign


第一步:打包资源文件,生成R.java文件
【输入】Resource文件(就是工程中res中的文件)、Assets文件(相当于另外一种资源,这种资源Android系统并不像对res中的文件那样优化它)、AndroidManifest.xml文件(包名就是从这里读取的,因为生成R.java文件需要包名)、Android基础类库(Android.jar文件)
【输出】打包好的资源(一般在Android工程的bin目录可以看到一个叫resources.ap_的文件就是它了)、R.java文件(在gen目录中,大家应该很熟悉了)
【工具】aapt工具,它的路径在${ANDROID_SDK_HOME}/platform-tools/aapt(如果你使用的是Windows系统,按惯例路径应该这样写:%ANDROID_SDK_HOME%\platform-tools\aapt.exe,下同)。


第二步:处理AIDL文件,生成对应的.java文件(当然,有很多工程没有用到AIDL,那这个过程就可以省了)
【输入】源码文件、aidl文件、framework.aidl文件
【输出】对应的.java文件
【工具】aidl工具


第三步:编译Java文件,生成对应的.class文件
【输入】源码文件(包括R.java和AIDL生成的.java文件)、库文件(.jar文件)
【输出】.class文件
【工具】javac工具


第四步:把.class文件转化成Davik VM支持的.dex文件
【输入】 .class文件(包括Aidl生成.class文件,R生成的.class文件,源文件生成的.class文件),库文件(.jar文件)
【输出】.dex文件
【工具】dex工具


第五步:打包生成未签名的.apk文件
【输入】打包后的资源文件、打包后类文件(.dex文件)、libs文件(包括.so文件,当然很多工程都没有这样的文件,如果你不使用C/C++开发的话)
【输出】未签名的.apk文件
【工具】apkbuilder工具


第六步:对未签名.apk文件进行签名
【输入】未签名的.apk文件
【输出】签名的.apk文件
【工具】jarsigner


第七步:对签名后的.apk文件进行对齐处理(不进行对齐处理是不能发布到Google Market的)
【输入】签名后的.apk文件
【输出】对齐后的.apk文件
【工具】zipalign工具


知道了上面这些细节后,就可以实现很多我们想实现东西了,比如:编译流程自动化,例如我们可以使用某种脚本,像Windows下的批处理,linux下的Bash,Java下的Ant,Python、Perl这样的脚本语言,甚至直接用Java、.Net这们的强类型语言也是可以的。

如果真正弄懂了上面的步骤,了解了编译打包过程的本质,你完全可以以你想要的任何方式实现它的自动化,这才是真正的“举一反三,以不变应万变”。再比如,对Android SDK的精简,大家知道现在Android SDK动辙几百兆,我们完全可以应用上面的知识,只保留必要的工具,把SDK精简到10M以下。当然,还可以做很多事情,前提是你真正弄懂了它。

Ant脚本代码如下::

<?xml version="1.0" encoding="UTF-8"?> 
<project name="Umeng-Analytics-demo-Auto" default="install" basedir=".">
    <!-- 环境变量 -->  
    <property environment="env" />  
    <!-- 应用的名称 -->  
    <property name="appName" value="${ant.project.name}" />  
    <!-- 应用的包目录 -->  
    <property name="appPackage" value="com.umeng.example.auto" />  
    <!-- SDK目录(获取操作系统环境变量ANDROID_SDK_HOME的值) -->  
    <property name="sdk-folder" value="F:/android/android-sdk-windows" />  
    <!-- SDK中tools目录 -->  
    <property name="sdk-tools" value="${sdk-folder}/tools" />  
    <!-- SDK指定平台目录 -->  
    <property name="sdk-platform-folder" value="${sdk-folder}/platforms/android-17" />  
    <!-- SDK指定平台的tools目录 -->  
    <property name="sdk-platform-tools" value="${sdk-folder}/platform-tools" />  
   <property name="sdk-build-tools" value="${sdk-folder}/build-tools/17.0.0" />  
    <!-- 使用到得命令 -->  
    <property name="aapt" value="${sdk-platform-tools}\aapt" />  
    <property name="aidl" value="${sdk-platform-tools}\aidl" />  
    <property name="dx" value="${sdk-build-tools}\dx.bat" />  
    <property name="apkbuilder" value="${sdk-tools}\apkbuilder" />  
    <property name="jarsigner" value="${env.JAVA_HOME}\bin\jarsigner" />  
    <property name="zipalign" value="${sdk-tools}\zipalign" />  
    <property name="adb" value="${sdk-platform-tools}\adb" />  
  
    <!-- 生成R文件的相对目录 -->  
    <property name="outdir-gen" value="gen" />  
    <!-- 编译后的文件放置目录 -->  
    <property name="outdir-bin" value="bin" />  
  
    <!-- 生成class目录 -->  
    <property name="outdir-classes" value="${outdir-bin}" />  
    <property name="outdir-classes-ospath" value="${basedir}/${outdir-classes}" />  
  
    <!-- 资源文件目录 -->  
    <property name="resource-dir" value="res" />  
    <property name="assets-dir" value="assets" />  
  
    <!-- 配置清单文件 -->  
    <property name="android-manifest-xml" value="AndroidManifest.xml" />  
  
    <!-- 编译时需要的jar,如果项目需要使用到地图服务则需要maps.jar -->  
    <property name="android-jar" value="${sdk-platform-folder}/android.jar" />   
  
    <!-- 编译aidl文件所需的预处理框架文件framework.aidl -->  
    <property name="framework-aidl" value="${sdk-platform-folder}/framework.aidl" />  
  
    <!-- Java源文件目录 -->  
    <property name="srcdir" value="src" />  
    <property name="srcdir-ospath" value="${basedir}/${srcdir}" />  
  
    <!-- 外部类库所在目录 -->  
    <property name="external-lib" value="libs" />  
    <property name="external-lib-ospath" value="${basedir}/${external-lib}" />  
  
    <!-- proguard所在目录 -->  
    <property name="proguard-dir" value="proguard" />  
    <property name="proguard-lib" value="${proguard-dir}/proguard.jar" />  
    <property name="unoptimized" value="${proguard-dir}/unoptimized.jar" />  
    <property name="optimized" value="${proguard-dir}/optimized.jar" />  
  
    <!-- classes.dex相关变量 -->  
       <property name="dex-file" value="classes.dex" />  
    <property name="dex-path" value="${outdir-bin}/${dex-file}" />  
    <property name="dex-ospath" value="${basedir}/${dex-path}" /> 


  
    <!-- 经过aapt生成的资源包文件 -->  
    <property name="resources-package" value="${outdir-bin}/resources.ap_" />  
    <property name="resources-package-ospath" value="${basedir}/${resources-package}" />  
  
    <!-- 未签名apk包 -->  
    <property name="out-unsigned-package" value="${outdir-bin}/${appName}-unsigned.apk" />  
    <property name="out-unsigned-package-ospath" value="${basedir}/${out-unsigned-package}" />  
  
    <!-- 证书文件 -->  
    <property name="keystore-file" value="${basedir}/keystore/android.keystore" />  
  
    <!-- 已签名apk包 -->  
    <property name="out-signed-package" value="${outdir-bin}/${appName}-signed.apk" />  
    <property name="out-signed-package-ospath" value="${basedir}/${out-signed-package}" />  
   
    <!-- debug -->
    
    <property name="out-debug-package" value="${outdir-bin}/${appName}-debug.apk" />  
    <property name="out-debug-package-ospath" value="${basedir}/${out-debug-package}" />  
    <!-- 优化后apk包 -->  
    <property name="out-zipalign-package" value="${outdir-bin}/${appName}-signed.apk" />  
    <property name="out-zipalign-package-ospath" value="${basedir}/${out-zipalign-package}" />  
  
    <target name="init">  
        <echo>${appName}</echo>  
        <echo>${appPackage}</echo>  
        <echo>${sdk-folder}</echo>  
        <echo>${sdk-tools}</echo>  
        <echo>${sdk-platform-folder}</echo>  
        <echo>${sdk-platform-tools}</echo>  
        <echo>${aapt}</echo>  
        <echo>${aidl}</echo>  
        <echo>${dx}</echo>  
        <echo>${apkbuilder}</echo>  
        <echo>${jarsigner}</echo>  
        <echo>${zipalign}</echo>  
        <echo>${adb}</echo>  
        <echo>${outdir-gen}</echo>  
        <echo>${outdir-bin}</echo>  
        <echo>${outdir-classes}</echo>  
        <echo>${outdir-classes-ospath}</echo>  
        <echo>${resource-dir}</echo>  
        <echo>${assets-dir}</echo>  
        <echo>${android-manifest-xml}</echo>  
        <echo>${android-jar}</echo>  
        <echo>${android-maps-jar}</echo>  
        <echo>${framework-aidl}</echo>  
        <echo>${srcdir}</echo>  
        <echo>${srcdir-ospath}</echo>  
        <echo>${external-lib}</echo>  
        <echo>${external-lib-ospath}</echo>  
        <echo>${proguard-dir}</echo>  
        <echo>${proguard-lib}</echo>  
        <echo>${unoptimized}</echo>  
        <echo>${optimized}</echo>  
        <echo>${dex-file}</echo>  
        <echo>${dex-path}</echo>  
        <echo>${dex-ospath}</echo>  
        <echo>${resources-package}</echo>  
        <echo>${resources-package-ospath}</echo>  
        <echo>${out-unsigned-package}</echo>  
        <echo>${out-unsigned-package-ospath}</echo>  
        <echo>${keystore-file}</echo>  
        <echo>${out-signed-package}</echo>  
        <echo>${out-signed-package-ospath}</echo>  
        <echo>${out-zipalign-package}</echo>  
        <echo>${out-zipalign-package-ospath}</echo>  
    </target>  
  
    <target name="initDir" depends="init">  
        <echo>初始化文件夹...</echo>  
        <delete dir="${outdir-classes}" /> 
        <delete dir="${outdir-bin}" />  
  <delete dir="${outdir-gen}" />
        <mkdir dir="${outdir-bin}" />
        <mkdir dir="${outdir-classes}" />  
        <mkdir dir="${outdir-gen}" />
        <echo>初始化文件夹完成...</echo>  
    </target>  
  
    <!-- 根据工程中的资源文件生成R.java文件 -->  
    <target name="gen-R" depends="initDir">  
        <echo>生成R.java文件...</echo>  
        <exec executable="${aapt}" failοnerrοr="true">  
            <arg value="package" />  
            <!-- 输出详细内容 -->  
            <arg value="-v" />  
            <!-- 强制覆盖已存在的文件 -->  
            <arg value="-f" />  
            <!-- 在-J指定的位置下生成相应的包的目录 -->  
            <arg value="-m" />  
            <!-- 指定R.java文件生成的目录 -->  
             <arg value="-J" />  
            <arg value="${outdir-gen}" />   
            <!-- 指定资源文件目录 -->  
            <arg value="-S" />  
            <arg value="${resource-dir}" />  
            <!-- 指定assets文件目录 -->  
            <arg value="-A" />  
            <arg value="${assets-dir}" />  
            <!-- 指定配置清单文件 -->  
            <arg value="-M" />  
            <arg value="${android-manifest-xml}" />  
            <!-- 引入类库 -->  
            <arg value="-I" />  
            <arg value="${android-jar}" />  
        </exec>  
        <echo>R.java文件生成完成...</echo>  
    </target>  
  
    <!-- 编译aidl文件 -->  
    <target name="aidl" depends="gen-R">  
        <echo>开始编译.aidl文件为.java文件...</echo>  
        <apply executable="${aidl}" failοnerrοr="true" verbose="true"> 
            <!-- 指定预处理文件 -->  
            <arg value="-p${framework-aidl}" />  
            <!-- aidl声明的目录 -->  
            <arg value="-I${srcdir}" />  
            
            <!-- 目标文件目录 -->  
            <arg value="-o${outdir-gen}" />  
            <!-- 指定哪些文件需要编译 -->  
            <fileset dir="${srcdir}">  
                <include name="**/*.aidl" />  
            </fileset>  
        </apply>  
        <echo>aidl文件编译完成...</echo>  
    </target>  
  
    <!-- 将工程中的java源文件编译成class文件 -->  
    <target name="compile" depends="aidl">  
        <echo>编译Java源文件...</echo>  
        <!-- bootclasspath 指定引导类文件的位置-->  
        <javac encoding="utf-8" target="1.6" srcdir="." destdir="${outdir-classes}" bootclasspath="${android-jar}" verbose="true" debug="true">  
            <classpath>  
                <fileset dir="${external-lib}" includes="**/*.jar" />  
                <filelist>  
                    <file name="${android-maps-jar}" />  
                </filelist>  
            </classpath>  
        </javac>  
        <echo>Java源文件编译完成...</echo>  
    </target>  
    <!-- 将.class文件转化成.dex文件 -->  
     <target name="dex" depends="compile">  
        <echo>编译文件和引用类库转化为.dex文件...</echo>  
        <exec executable="${dx}" failοnerrοr="true">  
            <arg value="--dex" />  
            <arg value="--verbose" />  
            <arg value="--output=${dex-ospath}" />  
          <!-- 要生成.dex文件的源classes和libraries  </echo> -->
            <arg value="${outdir-classes-ospath}" />  
            <arg value="${external-lib-ospath}" />  
        </exec>  
        <echo>.dex文件转换完成...</echo>  
    </target>   
  
    <!-- 将资源文件放进输出目录 -->  
    <target name="package-res-and-assets">  
        <echo>开始转化资源文件...</echo>  
        <exec executable="${aapt}" failοnerrοr="true">  
            <arg value="package" />  
            <!-- 输出详细内容 -->  
            <!--  <arg value="-v" /> --> 
            <!-- 强制覆盖已存在的文件 -->  
            <arg value="-f" />  
            <!-- 指定资源文件目录 -->  
            <arg value="-S" />  
            <arg value="${resource-dir}" />  
            <!-- 指定assets文件目录 -->  
            <arg value="-A" />  
            <arg value="${assets-dir}" />  
            <!-- 指定配置清单文件 -->  
            <arg value="-M" />  
            <arg value="${android-manifest-xml}" />  
            <!-- 引入类库 -->  
            <arg value="-I" />  
            <arg value="${android-jar}" />  
            <!-- 指定要生成的包 -->  
            <arg value="-F" />  
            <arg value="${resources-package}" />  
        </exec>  
        <echo>资源文件转化完成...</echo>  
    </target>  
  
    <!-- 打包成未签名的apk -->  
    <target name="package" depends="dex,package-res-and-assets">  
        <echo>开始打包未签名程序...</echo>  
        <java classpath="${sdk-tools}/lib/sdklib.jar" classname="com.android.sdklib.build.ApkBuilderMain">  
              <arg value="${out-debug-package-ospath}" />  
                      <!--  输出详细内容   -->
            <arg value="-v" />         
            <!-- 指定dex文件添加到应用程序包中   -->
            <arg value="-f" />  
            <arg value="${dex-ospath}" />  
           <!--  指定资源文件添加到应用程序包中   -->
            <arg value="-z" />  
            <arg value="${resources-package-ospath}" />  
           <!--  参照源文件的目录结构   -->
            <arg value="-rf" />  
            <arg value="${srcdir-ospath}" /> 
        </java> 
        <echo>未签名程序打包完成...</echo>   
    </target>  
    
    <target name="debug" depends="dex,package">  
        <echo>Packaging ${out-debug-package}, and signing it with a debug key...</echo>  
        <java classpath="${sdk-tools}/lib/sdklib.jar" classname="com.android.sdklib.build.ApkBuilderMain">  
            <arg value="${out-debug-package-ospath}" />  
            <arg value="-z" />  
            <arg value="${resources-package-ospath}" />  
            <arg value="-f" />  
            <arg value="${dex-ospath}" />  
            <arg value="-rf" />  
            <arg value="${srcdir-ospath}" />  
            <arg value="-rj" />  
            <arg value="${external-lib-ospath}" />  
        </java>
    </target>  
     <target name="jarsigner" depends="package"> 
<echo>Packaging ${out-unsigned-package} for release...</echo> 
<exec executable="${jarsigner}" failοnerrοr="true"> 
<arg value="-verbose" /> 
<arg value="-storepass" /> 
<arg value="123456" /> 
<arg value="-keypass" /> 
<arg value="123456" /> 
<arg value="-keystore" /> 
<arg value="aeo_android.keystore" /> 
<arg value="-digestalg " /> 
<arg value="SHA1" />
<arg value="-sigalg " /> 
<arg value="MD5withRSA" />
<arg value="-signedjar" /> 
<arg value="${out-signed-package-ospath}" /> 
<arg value="${out-unsigned-package-ospath}" /> 
<arg value="aeo_android.keystore" /> 
</exec> 
</target>
    <!-- 对apk进行优化 -->  
    <target name="zipalign" depends="jarsigner">  
        <echo>开始对apk文件进行优化...</echo>  
        <exec executable="${zipalign}" failοnerrοr="true">  
            <!-- 覆盖已经存在的文件 -->  
            <arg value="-f" />  
            <!-- 输出详细内容 -->  
            <arg value="-v" />  
            <!-- 以字节为单位对齐  4 提供了32位对齐 -->  
            <arg value="4" />  
            <!-- 需要优化的apk文件 -->  
            <arg value="${out-signed-package}" />   
            <arg value="${out-unsigned-package}" />
            <!-- 优化完成的apk文件 -->  
            <arg value="${out-zipalign-package}" />  
        </exec>  
        <echo>apk文件优化完成...</echo>  
    </target>  
    
    
  
    <!-- 发布 -->  
    <target name="release" depends="package">  
        <!-- 删除未签名apk -->  
        <!--  <delete file="${out-unsigned-package-ospath}" />   -->
        <!-- <delete file="${out-signed-package}" />   -->
        <echo>APK文件生成完成,生成目录:${out-zipalign-package-ospath}</echo>  
    </target>  
  
    <!-- 安装 -->  
    <target name="install" depends="package">  
        <echo>开始安装apk文件...</echo>  
        <exec executable="${adb}" failοnerrοr="true"> 
            <arg value="install" />  
            <arg value="${out-debug-package-ospath}" />  
        </exec>  
        <echo>apk文件安装完成...</echo>  
    </target>  
  
    <!-- 重新安装 -->  
    <target name="reinstall">  
        <echo>重新安装apk文件...</echo>  
        <exec executable="${adb}" failοnerrοr="true">  
            <arg value="install" />  
            <arg value="-r" />  
            <arg value="${out-zipalign-package}" />  
        </exec>  
        <echo>重新安装apk文件完成...</echo>  
    </target>  
  
    <!-- 卸载 -->  
    <target name="uninstall">  
        <echo>开始卸载apk文件...</echo>  
        <exec executable="${adb}" failοnerrοr="true">  
            <arg value="uninstall" />  
            <arg value="${appPackage}" />  
        </exec>  
        <echo>apk文件卸载完成...</echo>  
    </target> 
</project>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值