使用 Ant 打包 Android 應用
http://www.oschina.net/question/54100_30501?sort=default&p=2#answers
通常我們習慣用eclipse來開發Android程式,它會自動幫我們打包當前的應用程式。如果在Navigator檢視下,我們可以看到以下幾個檔案:
在上圖中,com包放置的是我們的class檔案,classes.dex是class檔案經過轉換後的可以在dalvik上跑的精簡類檔案,resources.ap_是經過打包的資原始檔,ant.apk就是最終的打包檔案。
使用ANT來對應用打包,一般會經過以下幾個步驟:
1.用aapt命令生成R.java檔案
2.用aidl命令生成相應java檔案
3.用javac命令編譯java原始檔生成class檔案
4.用dx.bat將class檔案轉換成classes.dex檔案
5.用aapt命令生成資源包檔案resources.ap_
6.用apkbuilder.bat打包資源和classes.dex檔案,生成unsigned.apk
7.用jarsinger命令對apk認證,生成signed.apk
為了便於理解和記憶,下面來用一張流程圖來說明以上的幾個過程:
以上就是整體的流程,下面我們就對其每個部分進行做出詳細講解,把每一個步驟都弄清楚了。
我們需要先熟悉一下每一個步驟所使用到的命令:
1.aapt(Android Asset Packaging Tool)命令,根據資原始檔生成R.java檔案
引數說明:
-f 強制覆蓋已存在的檔案。
-m 在-J指定的位置下自動生成相應的包的目錄。
-J 指定R.java檔案生成的目錄。
-S 指定資源目錄。
-M 指定清單檔案。
-I 引入類庫。
注意,我們當前所在的位置是ant專案根目錄,所以必要時需要輸入很多關於命令的路徑,以下示例也是一樣。
2.aidl(Android Interface Definition Language)命令,根據.aidl定義檔案生成java檔案
上面的示例所在位置為com/scott/ant下,根據包中的Person.aidl檔案,在gen對應的目錄中生成Person.java檔案,示例中只是處理單一檔案,下文中會講述如何處理目錄中的多個aidl檔案。
3.javac(Java Compiler)命令,根據原始檔生成對應的class檔案
引數說明:
-d <目錄> 指定存放生成的類檔案的位置
-bootclasspath <路徑> 覆蓋引導類檔案的位置
示例中並沒有考慮到引用類路徑下面的類庫,複雜的情況會在稍後遇到的。
4.dx命令,將class檔案轉換成.dex檔案
以上示例是將bin目錄下的class檔案轉換成classes.dex檔案,輸出到bin目錄,我們也許會用到第三方類庫,等一會就會看到。
5.aapt將資原始檔打包
引數說明:
-f 強制覆蓋
-M 指定Manifest檔案
-S 指定資源目錄
-A 指定資產目錄
-I 指定引入的類庫
-F 指定要生成的包
6.apkbuilder命令,根據classes.dex檔案和resources.ap_生成為簽證的apk包
引數說明:
-rf 參照原始檔的目錄的結構
7.jarsigner命令,對上面生成的apk包進行簽證
在簽證的過程中,需要使用到證書檔案,需要注意的是最後的release是證書的別名,關於如何建立證書,請看下圖:
當然也可以在eclipse裡使用ADT提供的圖形介面完成以上步驟,選中專案,點選右鍵,“Android Tools=>Export Signed Application Package”,然後再其中的Keystore selection環節選擇“Create new keystore”,然後按照提示填寫資訊就可以了。
以上是我們使用到的命令,接下來我們就該來分析一下ANT所必須的build.xml:
首先我們需要定義大量的變數屬性,用來表示使用到的路徑、目錄等,如下:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
< project
name = "ant"
default = "release" >
<!-- ANT環境變數 -->
< property
environment = "env"
/>
<!-- 應用名稱 -->
< property
name = "appName"
value = "${ant.project.name}" />
<!-- SDK目錄(獲取作業系統環境變數ANDROID_SDK_HOME的值) -->
< property
name = "sdk-folder"
value = "${env.ANDROID_SDK_HOME}"
/>
<!-- SDK指定平臺目錄 -->
< property
name = "sdk-platform-folder"
value = "${sdk-folder}/platforms/android-8" />
<!-- SDK中tools目錄 -->
< property
name = "sdk-tools"
value = "${sdk-folder}/tools"
/>
<!-- SDK指定平臺中tools目錄 -->
< property
name = "sdk-platform-tools"
value = "${sdk-platform-folder}/tools"
/>
<!-- 使用到的命令(當前系統為windows,如果系統為linux,可將.bat檔案替換成相對應的命令) -->
< property
name = "aapt"
value = "${sdk-platform-tools}/aapt"
/>
< property
name = "aidl"
value = "${sdk-platform-tools}/aidl"
/>
< property
name = "dx"
value = "${sdk-platform-tools}/dx.bat"
/>
< property
name = "apkbuilder"
value = "${sdk-tools}/apkbuilder.bat"
/>
< property
name = "jarsigner"
value = "${env.JAVA_HOME}/bin/jarsigner"
/>
<!-- 編譯需要的jar; 如果專案使用到地圖服務則需要maps.jar -->
< property
name = "android-jar"
value = "${sdk-platform-folder}/android.jar"
/>
< property
name = "android-maps-jar"
value = "${sdk-folder}/add-ons/addon_google_apis_google_inc_8/libs/maps.jar" />
<!-- 編譯aidl檔案所需的預處理框架檔案framework.aidl -->
< property
name = "framework-aidl"
value = "${sdk-platform-folder}/framework.aidl"
/>
<!-- 生成R檔案的相對目錄 -->
< property
name = "outdir-gen"
value = "gen"
/>
<!-- 編譯後的檔案放置目錄 -->
< property
name = "outdir-bin"
value = "bin"
/>
<!-- 清單檔案 -->
< property
name = "manifest-xml"
value = "AndroidManifest.xml"
/>
<!-- 原始檔目錄 -->
< property
name = "resource-dir"
value = "res"
/>
< property
name = "asset-dir"
value = "assets"
/>
<!-- java原始檔目錄 -->
< property
name = "srcdir"
value = "src"
/>
< property
name = "srcdir-ospath"
value = "${basedir}/${srcdir}"
/>
<!-- 外部類庫所在目錄 -->
< property
name = "external-lib"
value = "lib"
/>
< property
name = "external-lib-ospath"
value = "${basedir}/${external-lib}"
/>
<!-- 生成class目錄 -->
< property
name = "outdir-classes"
value = "${outdir-bin}"
/>
< property
name = "outdir-classes-ospath"
value = "${basedir}/${outdir-classes}"
/>
<!-- 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}/release.keystore"
/>
<!-- 已認證apk包 -->
< property
name = "out-signed-package"
value = "${outdir-bin}/${appName}.apk"
/>
< property
name = "out-signed-package-ospath"
value = "${basedir}/${out-signed-package}"
/>
...
</ project >
|
1 2 3 4 5 6 7 |
<!-- 初始化工作 -->
< target
name = "init" >
< echo >Initializing all output directories...</ echo >
< delete
dir = "${outdir-bin}"
/>
< mkdir
dir = "${outdir-bin}"
/>
< mkdir
dir = "${outdir-classes}"
/>
</ target >
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- 根據工程中的資原始檔生成R.java檔案 -->
< target
name = "gen-R"
depends = "init" >
< echo >Generating R.java from the resources...</ echo >
< exec
executable = "${aapt}"
failonerror = "true" >
< arg
value = "package"
/>
< arg
value = "-f"
/>
< arg
value = "-m"
/>
< arg
value = "-J"
/>
< arg
value = "${outdir-gen}"
/>
< arg
value = "-S"
/>
< arg
value = "${resource-dir}"
/>
< arg
value = "-M"
/>
< arg
value = "${manifest-xml}"
/>
< arg
value = "-I"
/>
< arg
value = "${android-jar}"
/>
</ exec >
</ target >
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!-- 編譯aidl檔案 -->
< target
name = "aidl"
depends = "gen-R" >
< echo >Compiling .aidl into java files...</ echo >
< apply
executable = "${aidl}"
failonerror = "true" >
<!-- 指定預處理檔案 -->
< arg
value = "-p${framework-aidl}" />
<!-- aidl宣告的目錄 -->
< arg
value = "-I${srcdir}" />
<!-- 目標檔案目錄 -->
< arg
value = "-o${outdir-gen}" />
<!-- 指定哪些檔案需要編譯 -->
< fileset
dir = "${srcdir}" >
< include
name = "**/*.aidl" />
</ fileset >
</ apply >
</ target >
|
接下來是將原始檔編譯成class檔案:
?1 2 3 4 5 6 7 8 9 10 11 12 |
<!-- 將工程中的java原始檔編譯成class檔案 -->
< target
name = "compile"
depends = "aidl" >
< echo >Compiling java source code...</ echo >
< javac
encoding = "utf-8"
target = "1.5"
srcdir = "."
destdir = "${outdir-classes}"
bootclasspath = "${android-jar}" >
< classpath >
< fileset
dir = "${external-lib}"
includes = "*.jar" />
< filelist >
< file
name = "${android-maps-jar}" />
</ filelist >
</ classpath >
</ javac >
</ target >
|
接著是將class檔案轉換成classes.dex:
?1 2 3 4 5 6 7 8 9 10 11 12 |
<!-- 將.class檔案轉化成.dex檔案 -->
< target
name = "dex"
depends = "compile" >
< echo >Converting compiled files and external libraries into a .dex file...</ echo >
< exec
executable = "${dx}"
failonerror = "true" >
< arg
value = "--dex"
/>
<!-- 輸出檔案 -->
< arg
value = "--output=${dex-ospath}"
/>
<!-- 要生成.dex檔案的源classes和libraries -->
< arg
value = "${outdir-classes-ospath}"
/>
< arg
value = "${external-lib-ospath}" />
</ exec >
</ target >
|
然後是將資原始檔打包:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!-- 將資原始檔放進輸出目錄 -->
< target
name = "package-res-and-assets" >
< echo >Packaging resources and assets...</ echo >
< exec
executable = "${aapt}"
failonerror = "true" >
< arg
value = "package"
/>
< arg
value = "-f"
/>
< arg
value = "-M"
/>
< arg
value = "${manifest-xml}"
/>
< arg
value = "-S"
/>
< arg
value = "${resource-dir}"
/>
< arg
value = "-A"
/>
< arg
value = "${asset-dir}"
/>
< arg
value = "-I"
/>
< arg
value = "${android-jar}"
/>
< arg
value = "-F"
/>
< arg
value = "${resources-package}"
/>
</ exec >
</ target >
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!-- 打包成未簽證的apk -->
< target
name = "package"
depends = "dex, package-res-and-assets" >
< echo >Packaging unsigned apk for release...</ echo >
< exec
executable = "${apkbuilder}"
failonerror = "true" >
< arg
value = "${out-unsigned-package-ospath}"
/>
< arg
value = "-u"
/>
< arg
value = "-z"
/>
< arg
value = "${resources-package-ospath}"
/>
< arg
value = "-f"
/>
< arg
value = "${dex-ospath}"
/>
< arg
value = "-rf"
/>
< arg
value = "${srcdir-ospath}"
/>
</ exec >
< echo >It will need to be signed with jarsigner before being published.</ echo >
</ target >
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- 對apk進行簽證 -->
< target
name = "jarsigner"
depends = "package" >
< echo >Packaging signed apk for release...</ echo >
< exec
executable = "${jarsigner}"
failonerror = "true" >
< arg
value = "-keystore"
/>
< arg
value = "${keystore-file}"
/>
< arg
value = "-storepass"
/>
< arg
value = "123456"
/>
< arg
value = "-keypass"
/>
< arg
value = "123456"
/>
< arg
value = "-signedjar"
/>
< arg
value = "${out-signed-package-ospath}"
/>
< arg
value = "${out-unsigned-package-ospath}" />
<!-- 不要忘了證書的別名 -->
< arg
value = "release" />
</ exec >
</ target >
|
1 2 3 4 5 6 |
<!-- 釋出 -->
|