1. 程式人生 > >用ant的build.xml構建自動化打包android apk 完全詳解(打包系列教程之二)

用ant的build.xml構建自動化打包android apk 完全詳解(打包系列教程之二)

打包系列教程目錄:


通過上一篇文章內容的學習,我們基本已經明白了android打包簽名apk的主要操作與流程,那麼這一篇文章我們就將上一篇文章的打包內容轉化成ant的build.xml檔案進行自動化打包,這樣可以避免我們上一篇文章的敲打命令列的繁瑣操作,從而讓我們離自動化操作更近一步(建議先了解一下ant的基本用法,可以看這篇文章:http://blog.csdn.net/jason0539/article/details/44836769)。

我們還是跟上一篇一樣,根據以下步驟一步步來進行。

(1). 生成用於應用的R.java;

(2). 編譯所有java檔案為class檔案;

(3). 打包class檔案和jar包為classes.dex;

(4). 打包assets和res資源為資源壓縮包(例如res.zip,名字可以自己定義);

(5). 構建classes.dex和res.zip生成未簽名的APK;

(6). 生成有簽名的APK;

(7). 對簽名包進行zipalign優化;

 注意這裡的目錄跟上一篇的文章的目錄是有區別的,上一篇的內容是為了演示方便,才把生成的檔案都存放在桌面的ant檔案的gen目錄和bin目錄下,本篇預設路徑都是cd到工程目錄的根目錄下,所以生成的檔案也存放在工程目錄原有的gen資料夾和bin檔案下。


在工程開始之前,我們先要指定一些常量或者屬性以及做一些初始化操作

<!-- ANT環境變數 -->  
    <!--
	    <property environment="env" />
	    <property name="sdk.dir" value="${env.ANDROID_HOME}"/>  
	    <echo> ${sdk.dir} </echo>  
    -->
    
 <!-- 專案所在資料夾 -->  
 <property name="project-dir" value="/Users/zejian/Documents/eclipse-java-mars-1-macosx-cocoa-x86_64/workspace/Command4Ant" />  
 <!-- JAVA目錄(獲取作業系統環境變數JAVA_HOME的值) -->  
 <property name="java_home" value="/Library/Java/JavaVirtualMachines/jdk1.7.0_75.jdk/Contents/Home" />
 <!-- SDK目錄(獲取作業系統環境變數ANDROID_SDK_HOME的值) -->  
 <property name="sdk-folder" value="/Users/zejian/Documents/androidStudio/SDK" />  
 <!-- 指定平臺對應的android.jar -->
 <property name="android-jar" value="${sdk-folder}/platforms/android-22/android.jar" />
 <!-- SDK指定平臺目錄 -->  
 <property name="sdk-platform-folder" value="${sdk-folder}/platforms/android-22"/>  
 <!-- SDK中tools目錄 -->  
 <property name="sdk-tools" value="${sdk-folder}/tools" />  
 <!-- SDK中build_tools目錄 -->  
 <property name="build-tools" value="${sdk-folder}/build-tools/23.0.2" /> 
 <!-- SDK指定平臺中tools目錄 -->  
 <property name="sdk-platform-tools" value="${sdk-platform-folder}/tools" />  
  
 <!-- 使用到的命令(當前系統為mac) -->  
 <property name="aapt" value="${build-tools}/aapt" />  
 <property name="aidl" value="${build-tools}/aidl" />  
 <property name="dx" value="${build-tools}/dx" /> 
 <property name="zipalign" value="${build-tools}/zipalign" />  
 <property name="apkbuilder" value="${sdk-tools}/apkbuilder" />  
 <property name="jarsigner" value="${java_home}/bin/jarsigner" /> 
  
 <target name="init">  
   <echo>start initing ... </echo>  
    <delete>  
      <fileset dir="gen"></fileset>  
    </delete>  
    <mkdir dir="gen" />  
    <delete>  
      <fileset dir="bin/classes"></fileset>  
    </delete>  
    <mkdir dir="bin/classes" />  
    <echo>finish initing. </echo>  
 </target>  


這裡主要定義了android的sdk目錄,java的home目錄以及tools工具和build_tools工具,後初始化資料夾。對於environment="env"這個屬性常量,我很詫異,因為在我的mac電腦上,無論我怎麼測試都讀不到我定義的java和android環境變數,最終還是選擇了絕對路徑定義(如有知曉原因,請勞煩給我留言,謝謝!)。

1.生成用於應用的R.java

aapt package -f -m -J gen -S res -M AndroidManifest.xml  -I /Users/zejian/Documents/androidStudio/SDK/platforms/android-22/android.jar 
引數含義如下:

-f 如果編譯生成的檔案已經存在,強制覆蓋。

-m 使生成的包的目錄存放在-J引數指定的目錄

-J 指定生成的R.java 的輸出目錄路徑(存放在桌面的gen)

-S 指定res資料夾的路徑

-I 指定某個版本平臺的android.jar檔案的路徑(我使用的是API-22)

轉換成ant (注意依據當前專案的根目錄

        <echo>1.正在生成用於應用的R.java存放到gen(使用aapt) ... </echo>  
          <exec executable="${aapt}">  
              <arg value="package" />  
              <arg value="-m" />  
              <arg value="-J" />  
              <arg value="gen" />  
              <arg value="-S" />  
              <arg value="res" />  
              <arg value="-M" />  
              <arg value="AndroidManifest.xml" />  
              <arg value="-I" />  
              <arg value="${android-jar}" />  
              <arg value="--auto-add-overlay" /> <!-- 覆蓋資源 -->  
          </exec>  
  	<echo>步驟1已經完成... </echo> 
2.編譯所有java檔案為class檔案
javac -target 1.7 -bootclasspath /Users/zejian/Documents/androidStudio/SDK/platforms/android-22/android.jar -d bin src/com/example/command4ant/*.java gen/com/example/command4ant/R.java
含義如下:

-target <jdk版本>            生成特定 jdk 版本的類檔案

-bootclasspath <路徑>        覆蓋引導類檔案的位置

-d <目錄>                    指定存放生成的類檔案的位置

-sourcepath <路徑>           指定查詢輸入原始檔的位置

轉換成ant (注意依據當前專案的根目錄

 <echo>2.正在編譯所有java檔案為class檔案(包含src和gen目錄)... </echo>  
      <javac  target="1.7" destdir="bin/classes" bootclasspath="${android-jar}">  
          <src path="src" />  
          <src path="gen" />  
      </javac>  
 <echo>步驟2已經完成... </echo>
3. 打包class檔案和jar包為classes.dex
dx --dex --output=bin/classes.dex bin

引數含義如下:

--output=<要生成的classes.dex路徑>  <要處理的class檔案的路徑>

轉換成ant (注意依據當前專案的根目錄

       <echo>3.正在打包class檔案和jar包為classes.dex... </echo>  
          <exec executable="${dx}" failonerror="true">   
               <arg value="--dex" />   
               <arg value="--output=${project-dir}/bin/classes.dex" />   
               <arg path="${project-dir}/bin/classes" />  
          </exec>   
       <echo>步驟3已經完成... </echo>  
4. 打包assets和res資源為資源壓縮包(例如res.zip,名字可以自己定義)
aapt package -f -M AndroidManifest.xml -S res -I /Users/zejian/Documents/androidStudio/SDK/platforms/android-22/android.jar -A assets -F bin/res.zip  

引數含義:

-f 如果編譯生成的檔案已經存在,強制覆蓋。

-m 使生成的包的目錄存放在-J引數指定的目錄

-S 指定res資料夾的路徑

-I 指定某個版本平臺的android.jar檔案的路徑

-A 指定assert資料夾的路徑

-F 指定輸出檔案完整路徑

轉換成ant (注意依據當前專案的根目錄

<echo>4.正在打包assets和res資源為資源壓縮包res.zip...(include res, assets, AndroidManifest.xml)</echo>  
   <exec executable="${aapt}">  
     <arg value="package" />  
     <arg value="-f" />  
     <arg value="-M" />  
     <arg value="AndroidManifest.xml" />  
     <arg value="-S" />  
     <arg value="res" />  
     <arg value="-A" />  
     <arg value="assets" />  
     <arg value="-I" />  
     <arg value="${android-jar}" />  
     <arg value="-F" />  
     <arg value="bin/resources.ap_" />  
     <arg value="--auto-add-overlay" />  
  </exec>  
<echo>步驟4已經完成... </echo>  
5.構建classes.dexres.zip生成未簽名的APK
apkbuilder bin/unsigned_command4Ant.apk -v -u -z bin/res.zip -f bin/classes.dex 
引數含義:

第一個引數是存放打包後的檔案完整路徑

-v Verbose 顯示過程資訊

-u 建立一個無簽名的包

-z 指定apk資源路徑

-f 指定dex檔案路徑

轉換成ant (注意依據當前專案的根目錄

<echo>5.正在構建classes.dex和res.zip生成未簽名的APK(unsigned.apk)... </echo>  
   <exec executable="${apkbuilder}">  
       <arg value="${project-dir}/bin/unsigned.apk" />  
       <arg value="-u" />  
       <arg value="-z" />  
       <arg value="${project-dir}/bin/resources.ap_" />  
       <arg value="-f" />  
       <arg value="${project-dir}/bin/classes.dex" />  
   </exec>  
<echo>步驟5已經完成... </echo>  
6.生成有簽名的APK
jarsigner -verbose -keystore debug4zj -storepass debug4zj -keypass debug4zj -signedjar bin/signed_command4Ant.apk bin/unsigned_command4Ant.apk debug4zj  
引數含義:

-verbose  簽名/驗證時輸出詳細資訊

-keystore  金鑰庫路徑

-storepass  用於金鑰庫完整性的口令(密碼)

-keypass    專用金鑰的口令(密碼)

-signedjar   已簽名的 apk 檔案的名稱 (第一個apk是簽名之後的檔案, 第二個apk是需要簽名的檔案)

轉換成ant (注意依據當前專案的根目錄

<echo>6.正在生成有簽名的APK... </echo>  
  <exec executable="${jarsigner}">  
       <arg value="-keystore" />  
       <arg value="${project-dir}/debug4zj" />  
       <arg value="-storepass" />  
       <arg value="debug4zj" />  
       <arg value="-keypass" />  
       <arg value="debug4zj" />  
       <arg value="-signedjar" />  
       <arg value="${project-dir}/bin/signed.apk" />  
       <arg value="${project-dir}/bin/unsigned.apk" />  
       <arg value="debug4zj" />  
  </exec>  
<echo>步驟6已經完成... </echo>  
7. 對簽名包進行zipalign優化
zipalign -v 4 bin/signed.apk bin/zipalign_signed.apk  
引數含義:

-v 輸出詳細資訊

- 需要zipalign優化的apk  優化後的apk名稱以及存放位置

轉換成ant (注意依據當前專案的根目錄

 <echo>7.正在對簽名包進行zipalign優化... </echo>  
   <exec executable="${zipalign}">
       <arg value="-v" />
       <arg value="4" />
       <arg value="${project-dir}/bin/signed.apk" /> <!-- signed apk -->
       <arg value="${project-dir}/bin/zipalign_signed.apk" /> <!-- zipalign output -->
   </exec>
<echo>步驟7已經完成... </echo>  
到此打包流程的轉換成ant的build.xml就完成了,最後給出完成的build.xml檔案:
<?xml version="1.0" encoding="utf-8"?>  
<project default="main" basedir=".">  
    <!-- ANT環境變數 -->  
    <!--
	    <property environment="env" />
	    <property name="sdk.dir" value="${env.ANDROID_HOME}"/>  
	    <echo> ${sdk.dir} </echo>  
    -->
    
    <!-- 專案所在資料夾 -->  
    <property name="project-dir" value="/Users/zejian/Documents/eclipse-java-mars-1-macosx-cocoa-x86_64/workspace/Command4Ant" />  
  <!-- JAVA目錄(獲取作業系統環境變數JAVA_HOME的值) -->  
  <property name="java_home" value="/Library/Java/JavaVirtualMachines/jdk1.7.0_75.jdk/Contents/Home"/>
    <!-- SDK目錄(獲取作業系統環境變數ANDROID_SDK_HOME的值) -->  
    <property name="sdk-folder" value="/Users/zejian/Documents/androidStudio/SDK" />  
    <!-- 指定平臺對應的android.jar -->
    <property name="android-jar" value="${sdk-folder}/platforms/android-22/android.jar" />
    <!-- SDK指定平臺目錄 -->  
    <property name="sdk-platform-folder" value="${sdk-folder}/platforms/android-22"/>  
    <!-- SDK中tools目錄 -->  
    <property name="sdk-tools" value="${sdk-folder}/tools" />  
     <!-- SDK中build_tools目錄 -->  
    <property name="build-tools" value="${sdk-folder}/build-tools/23.0.2" /> 
    <!-- SDK指定平臺中tools目錄 -->  
    <property name="sdk-platform-tools" value="${sdk-platform-folder}/tools" />  
  
    <!-- 使用到的命令(當前系統為mac) -->  
    <property name="aapt" value="${build-tools}/aapt" />  
    <property name="aidl" value="${build-tools}/aidl" />  
    <property name="dx" value="${build-tools}/dx" /> 
    <property name="zipalign" value="${build-tools}/zipalign" />  
    <property name="apkbuilder" value="${sdk-tools}/apkbuilder" />  
    <property name="jarsigner" value="${java_home}/bin/jarsigner" />    

     <target name="init">  
      <echo>start initing ... </echo>  
        <delete>  
            <fileset dir="gen"></fileset>  
        </delete>  
          <mkdir dir="gen" />  
        <delete>  
            <fileset dir="bin/classes"></fileset>  
        </delete>  
        <mkdir dir="bin/classes" />  
      <echo>finish initing. </echo>  
    </target>  
      
    <target name="main" depends="init">  
     <echo>1.正在生成用於應用的R.java存放到gen(使用aapt) ... </echo>  
          <exec executable="${aapt}">  
              <arg value="package" />  
              <arg value="-m" />  
              <arg value="-J" />  
              <arg value="gen" />  
              <arg value="-S" />  
              <arg value="res" />  
              <arg value="-M" />  
              <arg value="AndroidManifest.xml" />  
              <arg value="-I" />  
              <arg value="${android-jar}" />  
              <arg value="--auto-add-overlay" /> <!-- 覆蓋資源 -->  
          </exec>  
    <echo>步驟1已經完成... </echo>  
    <echo>2.正在編譯所有java檔案為class檔案(包含src和gen目錄)... </echo>  
     <javac target="1.7" destdir="bin/classes" bootclasspath="${android-jar}">  
              <src path="src" />  
              <src path="gen" />  
       </javac>  
    <echo>步驟2已經完成... </echo>  
         
           
    <echo>3.正在打包class檔案和jar包為classes.dex... </echo>  
          <exec executable="${dx}" failonerror="true">   
               <arg value="--dex" />   
               <arg value="--output=${project-dir}/bin/classes.dex" />   
               <arg path="${project-dir}/bin/classes" />  
          </exec>   
            <echo>步驟3已經完成... </echo>  
           
   <echo>4.正在打包assets和res資源為資源壓縮包res.zip...(res, assets, AndroidManifest.xml)</echo> 
          <exec executable="${aapt}">  
               <arg value="package" />  
               <arg value="-f" />  
               <arg value="-M" />  
               <arg value="AndroidManifest.xml" />  
               <arg value="-S" />  
               <arg value="res" />  
               <arg value="-A" />  
               <arg value="assets" />  
               <arg value="-I" />  
               <arg value="${android-jar}" />  
               <arg value="-F" />  
               <arg value="bin/resources.ap_" />  
               <arg value="--auto-add-overlay" />  
          </exec>  
            <echo>步驟4已經完成... </echo>  
    <echo>5.正在構建classes.dex和res.zip生成未簽名的APK(unsigned.apk)...</echo>  
          <exec executable="${apkbuilder}">  
               <arg value="${project-dir}/bin/unsigned.apk" />  
               <arg value="-u" />  
               <arg value="-z" />  
               <arg value="${project-dir}/bin/resources.ap_" />  
               <arg value="-f" />  
               <arg value="${project-dir}/bin/classes.dex" />  
          </exec>  
    <echo>步驟5已經完成... </echo>  
    <echo>6.正在生成有簽名的APK... </echo>  
          <exec executable="${jarsigner}">  
               <arg value="-keystore" />  
               <arg value="${project-dir}/debug4zj" />  
               <arg value="-storepass" />  
               <arg value="debug4zj" />  
               <arg value="-keypass" />  
               <arg value="debug4zj" />  
               <arg value="-signedjar" />  
               <arg value="${project-dir}/bin/signed.apk" />  
               <arg value="${project-dir}/bin/unsigned.apk" />  
               <arg value="debug4zj" />  
          </exec>  
    <echo>步驟6已經完成... </echo>  
    <echo>7.正在對簽名包進行zipalign優化... </echo>  
          <exec executable="${zipalign}">
            <arg value="-v" />
            <arg value="4" />
            <arg value="${project-dir}/bin/signed.apk" /> <!-- signed apk -->
            <arg value="${project-dir}/bin/zipalign_signed.apk" /> <!-- zipalign output -->
          </exec>
    <echo>步驟7已經完成... </echo>  
    </target>  
    <target name="clean">  
    </target>  
</project>  
然後我們執行build.xml檔案,執行log如下:

打包結果,我們檢視一下專案的bin目錄:

從圖片中我們可以看出打包確實完成了,但細心的同學可能發現log裡面又這麼一個警告資訊:

其實有這個警告的話本身對簽名沒有影響,但是總感覺不太爽,要想去掉這個警告只要在簽名時加上如下程式碼即可:
<arg value="-tsa"/>
<arg value="https://timestamp.geotrust.com/tsa"/>
這就為該簽名包提供了時間戳的機構地址的認證連結,這樣就不會報錯啦。不過這個我在實際操作中發現,打包到簽名時,用的時間特別久,原因就是要去提供的地址驗證該時間戳的認證,所以我為了節省時間一般不加。完整程式碼如下:
      <echo>6.正在生成有簽名的APK... </echo>  
          <exec executable="${jarsigner}">  
               <arg value="-tsa"/>
               <arg value="https://timestamp.geotrust.com/tsa"/>
               <arg value="-keystore" />  
               <arg value="${project-dir}/debug4zj" />  
               <arg value="-storepass" />  
               <arg value="debug4zj" />  
               <arg value="-keypass" />  
               <arg value="debug4zj" />  
               <arg value="-signedjar" />  
               <arg value="${project-dir}/bin/signed.apk" />  
               <arg value="${project-dir}/bin/unsigned.apk" />  
               <arg value="debug4zj" />  
          </exec>  
      <echo>步驟6已經完成... </echo>
到此使用ant的build.xml構建自動化打包android apk 就全部分析完。下一篇我會繼續分析使用ant實現android的多渠道打包,歡迎繼續關注哈。