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應用,對於我來說主要有以下兩方面考慮:
1、我們在發布App的時候,可能需要發送到十幾,甚至幾十個不同的分發渠道,比如360手機市場,百度,應用寶等等,我們可能需要對各個渠道的下載量,用戶存留和用戶使用情況等數據進行分析,比如使用百度移動統計,友盟統計等。為了實現統計功能,我們需要在配置文件中添加一個數據元,來標識我們的應用要發布到哪一個渠道上,因此,若使用傳統的方法,我們每發布一個渠道的版本,就需要修改清單文件中的數據元,然后再使用keystore進行簽名和打包。若只有一兩個分發渠道,工作量還是可以接受的,但是若我們的分發渠道打到幾十個的時候,我們如果再手動的進行修改然后簽名打包發布,那工作量就很可觀了。因此,為解決這種需求,我們采用Ant來實現對Android應用的自動打包。
2、我們做產品的時候,肯定需要經常打不同環境的包,比如開發環境,測試環境,生產環境,這個時候你怎么辦,如果用傳統方法,你打開發環境包你要把你的服務端IP和圖片服務器IP改成開發的,打包,然后打測試的包,你又要改成測試服務器IP和圖片服務器IP,這樣多麻煩,如果你把這服務端IP和圖片服務器IP,配置到一個xml文件里,用ant打包方式實現自動替換,多方便。
 
 
ant 自動打包APK一般有以下兩種方式:
1、使用原生Ant方式,就是把所有的環境變量和打包的起個步驟都配置到build.xml文件里,這樣可以實現,但是這樣的話也有不方便之處,你如果引用了第三方library(不是第三方jar包),配置起來可能就比較麻煩了,而且跨平台你可能就要修改一些配置了,比如windows下和linux下批處理文件不同等。所以我更推薦第二種方式,本文也主要介紹第二種方式。
2、使用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環境變量
1、在Ant官網(http://ant.apache.org/bindownload.cgi)下載最新Ant包,在http://sourceforge.net/projects/ant-contrib/files 下載Ant擴展包ant-contrib-1.0b3.jar(這個包就是用於循環編譯多個渠道包)。
2、將Ant包解壓到常用開發工具目錄(自行選擇,我的放在D:/Dev目錄下),然后將下載下來的Ant擴展包ant-contrilb拷貝到Ant安裝目錄下的lib文件夾中。
 
3、設置Ant環境變量:ANT_HOME,變量值指向ant目錄。
4、在環境變量Path里增加:%ANT_HOME%/bin;%ANT_HOME%/lib;
5、設置好了之后驗證一下。打開CMD 輸入ant -version命令出現下面反饋,說明ant 安裝成功
三、配置打包項目
我的項目文件目錄如下:
1、生成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>

 

 
2、在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>

 

 
四、打包
1、如果項目中沒有引入第三方工程library,那么經過以上環節,就把整個項目Ant打包配置好了,進入CMD,在項目目錄下使用ant deployrel命令,自動打生產環境的包,使用 ant deploytest,自動打測試環境的包。
2、如果項目中引入了第三方工程library,比如我的項目,引入三個第三方工程:
如果執行打包命令,那么會報錯,這是因為那個library 還不支持ant自動編譯,我們需要先讓它也支持(注意:第三方工程要設置為Lib:
project->properties->Android->Library->Is Library 這個勾選上)。
進入到library項目所在的目錄,輸入命令 android update lib-project -p ./  (注意是 lib-project);
執行完之后,你會發現第三方工程目錄下多了build.xml文件和local.properties文件。然后你在執行打包命令就可以成功打包了。
 
五:總結
1、build.xml和local.properties可以用命令生成,custom_rules.xml和ant.properties可以收藏起來,任何項目中都可以用。
2、ant腳本中還可以加入自動從SVN下載最新版本源碼和打包之后通過ftp自動上傳到服務器供下載,還可以加入定時打包功能。
3、一些異常情況的解決辦法:
 
異常一:
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
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM