windows下Android利用ant自動編譯、修改配置文件、批量多渠道,打包生成apk文件

原創文章,轉載請註明:http://www.cnblogs.com/ycxyyzw/p/4535459.html

android 程序打包成apk,若是在是命令行方式,通常都要通過以下步驟:

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
 
eclipase手動打包生成apk方式,只不過是eclipase代替咱們執行了以上命令而已。
 
eclipse用起來雖然方便,爲何要使用Ant批量打包Android應用,對於我來講主要有如下兩方面考慮:
一、咱們在發佈App的時候,可能須要發送到十幾,甚至幾十個不一樣的分發渠道,好比360手機市場,百度,應用寶等等,咱們可能須要對各個渠道的下載量,用戶存留和用戶使用狀況等數據進行分析,好比使用百度移動統計,友盟統計等。爲了實現統計功能,咱們須要在配置文件中添加一個數據元,來標識咱們的應用要發佈到哪個渠道上,所以,若使用傳統的方法,咱們每發佈一個渠道的版本,就須要修改清單文件中的數據元,而後再使用keystore進行簽名和打包。若只有一兩個分發渠道,工做量仍是能夠接受的,可是若咱們的分發渠道打到幾十個的時候,咱們若是再手動的進行修改而後簽名打包發佈,那工做量就很可觀了。所以,爲解決這種需求,咱們採用Ant來實現對Android應用的自動打包。
二、咱們作產品的時候,確定須要常常打不一樣環境的包,好比開發環境,測試環境,生產環境,這個時候你怎麼辦,若是用傳統方法,你打開發環境包你要把你的服務端IP和圖片服務器IP改爲開發的,打包,而後打測試的包,你又要改爲測試服務器IP和圖片服務器IP,這樣多麻煩,若是你把這服務端IP和圖片服務器IP,配置到一個xml文件裏,用ant打包方式實現自動替換,多方便。
 
 
ant 自動打包APK通常有如下兩種方式:
一、使用原生Ant方式,就是把全部的環境變量和打包的起個步驟都配置到build.xml文件裏,這樣能夠實現,可是這樣的話也有不方便之處,你若是引用了第三方library(不是第三方jar包),配置起來可能就比較麻煩了,並且跨平臺你可能就要修改一些配置了,好比windows下和linux下批處理文件不一樣等。因此我更推薦第二種方式,本文也主要介紹第二種方式。
二、使用Android SDK Ant方式,Android SDK中提供了包含以前寫過的操做的封裝,只須要使用一條命令android update project生成build.xml ,以後再修改配置文件支持不一樣特性便可,徹底不用寫ant代碼,這些都由Android SDK自動生成。下面我來詳細介紹下此種方式。
 
以咱們如今開發的產品爲例:
 
一:設置JAVA環境變量
這個我就不說啥了,作android開發的配置這個是基礎。
二:配置Android的SDK環境變量 
除了須要Java的環境變量,咱們還須要配置Android的sdk的位置,名字是ANDROID_HOME,值就是你的android的sdk的位置,好比個人,就以下所示:
 
二:安裝ant並設置ant環境變量
一、在Ant官網(http://ant.apache.org/bindownload.cgi)下載最新Ant包,在http://sourceforge.net/projects/ant-contrib/files 下載Ant擴展包ant-contrib-1.0b3.jar(這個包就是用於循環編譯多個渠道包)。
二、將Ant包解壓到經常使用開發工具目錄(自行選擇,個人放在D:/Dev目錄下),而後將下載下來的Ant擴展包ant-contrilb拷貝到Ant安裝目錄下的lib文件夾中。
 
三、設置Ant環境變量:ANT_HOME,變量值指向ant目錄。
四、在環境變量Path裏增長:%ANT_HOME%/bin;%ANT_HOME%/lib;
五、設置好了以後驗證一下。打開CMD 輸入ant -version命令出現下面反饋,說明ant 安裝成功
3、配置打包項目
個人項目文件目錄以下:
一、生成build.xml文件
打開cmd並進入到epeiwang這個項目目錄下 使用android update project -n epeiwang -p . 命令(注意-n表示項目的名稱,-p參數後面有個點 表示當前目錄)。
 
執行這個命令後,會在項目中自動生成build.xml和local.properties文件。
 
build.xml文件內容以下,並注意紅色部門標識的代碼。這兩個文件是須要用戶本身建立的,並存放在當前項目目錄下。
 
<?xml version="1.0" encoding="UTF-8"?>
<project name="epeiwang" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<!-- 此文件須要咱們本身建立-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<!-- 此文件須要咱們本身建立-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<!-- 表示咱們引用了sdk的ant的build文件-->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

 

 
二、在epeiwangyxhd項目目錄下建立ant.properties和custom_rules.xml文件。ant.properties文件定義一些變量例如keystore密碼,apk存放目錄等;而custom_rules.xml這個文件就是用戶自定義的編譯規則文件。代碼分別以下:
 
A、ant.properties文件內容以下:
 
#keystore文件存放目錄
key.store=./epeiwang_keystore
#keystore別名
key.alias=epeiwang_keystore
#keystore密碼
key.store.password=xxxxxxx
#組織密碼
key.alias.password=xxxxxxxx
#若是尚未生成keystore證書,可使用下面命令在項目目錄下生成一個test.keystore證書文件
#generate test.keystore
#keytool -genkey -alias test.keystore -keyalg RSA -validity 20000 -keystore test.keystore
#apk.dir表示存放最終生成apk的目錄
apk.dir=./apk
#定義項目名稱
app.name=epeiwang
#渠道號,多個渠道號用逗號分隔,每一個渠道號不要使用違規字符例如/:等,由於渠道號會在打包的時候放在apk的文件名中,因此包含#違規字符將沒法生成最終的apk,哥就是被這個細節給坑了一個下午。這裏定義了兩個渠道號myapp-12345和BAI-3s322d
market_channels=epeiwang,baidu,91
#測試環境服務器配置
test.server.url=192.168.1.10/epeiwang
test.server.image.url=192.168.1.9
test.epeiwang.url=192.168.1.10
#生產環境服務器配置
rel.server.url=111.111.111.222/epeiwang
rel.server.image.url=111.111.111.229
rel.epeiwang.url=www.epeiwang.com
#測試環境標識 給apk命名的時候用
test.tag.name=test
#生產環境標識 給apk命名的時候用
release.tag.name=release

 

B、custom_rules.xml文件內容以下:
 
<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules" >
<!-- 引用ant-contlib這個擴展包,聲明一下 -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties" >
<classpath>
<pathelement location="${ant.ANT_HOME}/lib/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<!-- 定義一個時間變量,打完包後跟渠道號一塊兒命名apk -->
<tstamp>
<format
pattern="yyyyMMddhhmm"
property="pktime"
unit="hour" />
</tstamp>
<!-- 建立apk存放目錄 -->
<mkdir dir="${apk.dir}" >
</mkdir>
<!-- 替換參數 而後打包APK -->
<target name="replace_parameter" >
<!-- 替換服務器配置 -->
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!-- 這個是正則表達式匹配hostconfig中epeiwang_server的值 -->
<regexp pattern="epeiwang_server>(.*)&lt;/epeiwang_server" />
<substitution expression="epeiwang_server>${server_url}&lt;/epeiwang_server" />
<fileset
dir=""
includes="res/xml/hostconfig.xml" />
</replaceregexp>
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!-- 這個是正則表達式匹配hostconfig中epeiwang_img_server的值 -->
<regexp pattern="epeiwang_img_server>(.*)&lt;/epeiwang_img_server" />
<substitution expression="epeiwang_img_server>${server_image_url}&lt;/epeiwang_img_server" />
<fileset
dir=""
includes="res/xml/hostconfig.xml" />
</replaceregexp>
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!-- 這個是正則表達式匹配hostconfig中epeiwang_url的值 -->
<regexp pattern="epeiwang_url>(.*)&lt;/epeiwang_url" />
<substitution expression="epeiwang_url>${epeiwang_url}&lt;/epeiwang_url" />
<fileset
dir=""
includes="res/xml/hostconfig.xml" />
</replaceregexp>
</target>
<!-- 打包測試環境命令就用這個 -->
<target name="deploytest" >
<!-- 傳服務器配置參數到 replace_parameter這個打包target -->
<antcall target="replace_parameter" >
<param
name="server_url"
value="${test.server.url}" />
<param
name="server_image_url"
value="${test.server.image.url}" />
<param
name="epeiwang_url"
value="${test.epeiwang.url}" />
</antcall>
<!-- 執行循環打包target foreach_replacechannel -->
<antcall target="foreach_replacechannel" >
<!-- apk命名時候用到的參數 -->
<param
name="deploy_environment"
value="${test.tag.name}" />
</antcall>
</target>
<!-- 打包生產環境命令就用這個 -->
<target name="deployrel" >
<!-- 傳服務器配置參數到 replace_parameter這個打包target -->
<antcall target="replace_parameter" >
<param
name="server_url"
value="${rel.server.url}" />
<param
name="server_image_url"
value="${rel.server.image.url}" />
<param
name="epeiwang_url"
value="${rel.epeiwang.url}" />
</antcall>
<!-- 執行循環打包target foreach_replacechannel -->
<antcall target="foreach_replacechannel" >
<!-- apk命名時候用到的參數 -->
<param
name="deploy_environment"
value="${release.tag.name}" />
</antcall>
</target>
<!-- 循環打包的target -->
<target name="foreach_replacechannel" >
<!-- 開始循環打包,從market_channels參數中取出一個渠道號用channel標識,而後經過正則修改manifest文件 -->
<foreach
delimiter=","
list="${market_channels}"
param="channel"
target="modify_manifest" >
</foreach>
</target>
<target name="modify_manifest" >
<replaceregexp
byline="false"
encoding="UTF-8"
flags="g" >
<!--
這個是正則表達式匹配manifest中meta,我用的友盟的統計,我 AndroidManifest中的配置爲:
<meta-data android:value="360shichang" android:name="UMENG_CHANNEL"
-->
<regexp pattern="android:value=&quot;(.*)&quot; android:name=&quot;UMENG_CHANNEL&quot;" />
<substitution expression="android:value=&quot;${channel}&quot; android:name=&quot;UMENG_CHANNEL&quot;" />
<fileset
dir=""
includes="AndroidManifest.xml" />
</replaceregexp>
<!-- 這裏設置最終生成包的存放目錄以及apk的名稱,注意這裏是文件名稱,因此變量中不容許出現違規字符,不然將沒法生成最終的apk(會出現output is not valid 的錯誤) -->
<property
name="out.final.file"
location="${apk.dir}/${app.name}_${channel}_${deploy_environment}_${pktime}.apk" />
<antcall target="clean" />
<antcall target="release" />
</target>
</project>

 

個人服務器IP配置hostconfig.xml文件內容爲:
 
<?xml version="1.0" encoding="UTF-8"?>
<!-- 爲了ant打包時候正則匹配,請不要格式化該文件 -->
<hostconfig>
<epeiwang_server>1111.1111.1111.1/epeiwang</epeiwang_server>
<epeiwang_img_server>1111.1111.1111.1</epeiwang_img_server>
<epeiwang_url>www.epeiwang.com</epeiwang_url>
</hostconfig>

 

 
4、打包
一、若是項目中沒有引入第三方工程library,那麼通過以上環節,就把整個項目Ant打包配置好了,進入CMD,在項目目錄下使用ant deployrel命令,自動打生產環境的包,使用 ant deploytest,自動打測試環境的包。
二、若是項目中引入了第三方工程library,好比個人項目,引入三個第三方工程:
若是執行打包命令,那麼會報錯,這是由於那個library 還不支持ant自動編譯,咱們須要先讓它也支持(注意:第三方工程要設置爲Lib:
project->properties->Android->Library->Is Library 這個勾選上)。
進入到library項目所在的目錄,輸入命令 android update lib-project -p ./  (注意是 lib-project);
執行完以後,你會發現第三方工程目錄下多了build.xml文件和local.properties文件。而後你在執行打包命令就能夠成功打包了。
 
五:總結
一、build.xml和local.properties能夠用命令生成,custom_rules.xml和ant.properties能夠收藏起來,任何項目中均可以用。
二、ant腳本中還能夠加入自動從SVN下載最新版本源碼和打包以後經過ftp自動上傳到服務器供下載,還能夠加入定時打包功能。
三、一些異常狀況的解決辦法:
 
異常一:
BUILD FAILED
D:\Android\sdk\tools\ant\build.xml:601: The following error occurred while executing this line:
D:\Android\sdk\tools\ant\build.xml:653: The following error occurred while executing this line:
D:\Android\sdk\tools\ant\build.xml:698: null returned: 1
 
解決辦法:本身項目的build.xml文件中加入:
<property name="aapt.ignore.assets" value="!.svn:!.git:\x3Cdir\x3E_*:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~:crunch" />
 
異常二:
BUILD FAILED
D:\ProjectDemo\build.xml:83: Cannot find D:\ProjectDemo\android-sdk-windows\tools\ant\build.xml imported from D:\ProjectDemo\build.xml
 
解決辦法:修改local.projects,必須是雙斜槓
sdk.dir=D:\\android-sdk-windows
 
異常三:
 [aapt] D:\ProjectDemo\res\layout\activity_main.xml:2: error: Error: String types not allowed (at 'layout_width' with value 'match_parent').
     [aapt] D:\ProjectDemo\res\layout\activity_main.xml:2: error: Error: String types not allowed (at 'layout_height' with value 'match_parent').
 
BUILD FAILED
D:android-sdk-windows\tools\ant\build.xml:650: The following error occurred while executing this line:
D:android-sdk-windows\tools\ant\build.xml:691: null returned: 1
 
Total time: 1 second
 
解決辦法:當前Andorid版本不支持match_parent屬性值,match_parent是Android 8之後開始支持的屬性值,修改AndroidManifest中<uses-sdk android:minSdkVersion="8" />最少也要大於8。不過也能夠把match_parent改成FILL_PARENT
 

相關文章
相關標籤/搜索