欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android筆記之:App自動(dòng)化之使用Ant編譯項(xiàng)目多渠道打包的使用詳解

 更新時(shí)間:2013年04月28日 09:43:47   作者:  
本篇文章介紹了,Android筆記之:App自動(dòng)化之使用Ant編譯項(xiàng)目多渠道打包的使用詳解。需要的朋友參考下
隨著工程越來越復(fù)雜,項(xiàng)目越來越多,以及平臺(tái)的遷移(我最近就遷了2回),還有各大市場(chǎng)的發(fā)布,自動(dòng)化編譯android項(xiàng)目的需求越來越強(qiáng)烈,后面如果考慮做持續(xù)集成的話,會(huì)更加強(qiáng)烈。
    經(jīng)過不斷的嘗試,在ubuntu環(huán)境下,以花界為例,我將一步一步演示如何使用命令行,使用ant編譯android項(xiàng)目,打包多渠道APK。
    要點(diǎn):
    (1). 編譯android的命令使用
    (2). ant基本應(yīng)用
    (3). 多項(xiàng)目如何編譯(包含android library)
    (4). 如何多渠道打包
    ps:我將以最原始的方式來實(shí)現(xiàn),而不是使用android自帶的ant編譯方式,并盡量詳細(xì)解釋,這樣有益于我們徹底搞懂a(chǎn)ndroid打包的基本原理。

1. Android編譯打包的整體過程
    使用ant,ant的參考文檔:http://ant.apache.org/manual/index.html
    首先,假設(shè)現(xiàn)在已經(jīng)有這樣的一個(gè)項(xiàng)目(多工程的,簡(jiǎn)單的單工程就更簡(jiǎn)單了):

world
├── baseworld                                               //android library,基礎(chǔ)類庫,共享于其他主應(yīng)用
├── floworld                                                   //android project,花界應(yīng)用
├── healthworld                                             //android project,健康視線應(yīng)用
├── speciality                                                 //android project,其它應(yīng)用
├── starworld                                                 //android project,其它應(yīng)用
├── build.xml                                                 //ant編譯腳本,可用于整個(gè)項(xiàng)目的編譯,也可只編譯某個(gè)工程
├── code_checks.xml
├── kaiyuanxiangmu_world.keystore             //密鑰
└── README.md

    一個(gè)大的項(xiàng)目world,下面有1個(gè)基礎(chǔ)Android Library和4個(gè)Android Project。我們要做的就是編譯這4個(gè)人project成對(duì)應(yīng)的一系列各市場(chǎng)APK。
    那么我們?cè)趤砜纯碽aseworld和floworld的工程結(jié)構(gòu):
    Android Library,baseworld:

baseworld
├── assets                                                       //assets目錄,其中文件可能會(huì)被主應(yīng)用覆蓋
├── libs                                                           //存放第三方j(luò)ar庫
├── res                                                            //類庫資源,其中文件可能會(huì)被主應(yīng)用覆蓋
├── src                                                            //源碼,可直接供主應(yīng)用使用
├── AndroidManifest.xml
├── lint.xml
├── proguard.cfg
├── project.properties
└── README.md

    和Android Project,floworld:

floworld/
├── assets                                                       //assets目錄,主應(yīng)用優(yōu)先級(jí)高
├── build
├── data
├── libs                                                           //存放第三方j(luò)ar庫
├── res                                                            //主應(yīng)用資源,主應(yīng)用優(yōu)先級(jí)高
├── src                                                            //源碼,可直接供主應(yīng)用使用
├── AndroidManifest.xml
├── build.xml                                                   //ant編譯腳本,可用于整個(gè)項(xiàng)目的編譯,也可只編譯某個(gè)工程
├── default.properties
├── lint.xml
├── proguard.cfg
├── project.properties
└── README.md

    結(jié)構(gòu)已經(jīng)出來了,那么android打包主要是在做什么?
    說白了,先編譯java成class,再把class和jar轉(zhuǎn)化成dex,接著打包aaset和res等資源文件為res.zip(以res.zip示例),再把dex和res.zip合并為一個(gè)未簽名apk,再對(duì)它簽名,最終是一個(gè)帶簽名的apk文件。
    當(dāng)然這么說忽略了很多細(xì)節(jié)。
    下面我把這些步驟用一句話分別列舉如下,腦子里先有一個(gè)整體的流程,后續(xù)再結(jié)合ant詳細(xì)展開:
    (1). 生成用于主應(yīng)用的R.java;
    (2). 生成用于庫應(yīng)用的R.java(如果有庫應(yīng)用);
    (3). 編譯所有java文件為class文件;
    (4). 打包c(diǎn)lass文件和jar包為classes.dex;
    (5). 打包assets和res資源為資源壓縮包(如res.zip,名字可以自己定義);
    (6). 組合classes.dex和res.zip生成未簽名的APK;
    (7). 生成有簽名的APK;
    針對(duì)多項(xiàng)目同步發(fā)布和多渠道打包問題,我們需要額外增加三個(gè)處理:
    (1). 各個(gè)工程下建立一個(gè)build.xml,然后在整個(gè)項(xiàng)目的根目錄下建立一個(gè)build.xml,用于統(tǒng)一編譯各個(gè)工程的;
    (2). 各個(gè)工程的build.xml,通過傳入市場(chǎng)ID和應(yīng)用Version參數(shù)生成對(duì)應(yīng)的版本
    (3). 針對(duì)(1),(2)問題,建立一個(gè)批處理支持一鍵生成所有版本
    大概流程即是如此。

2. 建立各個(gè)工程的ant腳本文件build.xml(位置:floworld/build.xml)
    因?yàn)樾枰獎(jiǎng)?chuàng)建一些基本的文件目錄和清理上次生成的文件,所以我們簡(jiǎn)單的定義一下幾個(gè)目標(biāo)吧:init,main,clean。
    代碼模板如下:

復(fù)制代碼 代碼如下:

<project default="main" basedir=".">
     <!-- 初始化:創(chuàng)建目錄,清理目錄等 -->
     <target name="init">
           <echo>start initing ... </echo> 
           <!-- ... ... -->
           <echo>finish initing. </echo>
     </target>
     <!-- 打包過程,默認(rèn)值 -->
     <target name="main" depends="init">
     </target>
     <!-- 清理不需要的生成文件等-->
     <target name="clean">
     </target>
</project>

3. 初始化
    在正式打包之前,有必要說明一下可能需要用到的初始化變量和操作。
    前面已經(jīng)講述了打包的大概流程,現(xiàn)在,第一, 打包需要你使用哪個(gè)版本android.jar; 第二, 生成的R文件放到gen目錄下; 第三, 生成的classes文件放到bin目錄下; 第四, 生成的打包文件放到out目錄下; 第五, 生成的各市場(chǎng)版本放到build目錄下。目錄完全可以自定義。
    所以,如下的初始化必須先要做好,不然后面會(huì)提示找不到目錄:
復(fù)制代碼 代碼如下:

<project default="main" basedir=".">
    <!-- 這個(gè)是android.jar路徑,具體情況具體配置 -->
    <property name="android-jar" value="/usr/lib/android-sdk/platforms/android-10/android.jar" />
    <!-- 用于生成多渠道版本的APK文件名,提供了默認(rèn)值,后面會(huì)講到 -->
    <property name="apk-name" value="product" />
    <property name="apk-version" value="latest" />
    <property name="apk-market" value="dev" />
    <target name="init">
        <echo>start initing ... </echo>
        <mkdir dir="out" />
        <delete>
            <fileset dir="out"></fileset>
        </delete>
        <mkdir dir="gen" />
        <delete>
            <fileset dir="gen"></fileset>
        </delete>
        <mkdir dir="bin/classes" />
        <delete>
            <fileset dir="bin/classes"></fileset>
        </delete>
        <!-- ${apk-version}表示版本,后面會(huì)詳細(xì)講到 -->
        <mkdir dir="build/${apk-version}" />
        <echo>finish initing. </echo>
    </target>
     ... ...
</project>

4. 生成R.java
    Android Library和Android Project應(yīng)用的R.java是來自不同的package的。比如:
    (1). baseworld中導(dǎo)入的包是import com.tianxia.lib.baseworld.R;
    (2). floworld中導(dǎo)入的包是import com.tianxia.lib.baseworld.R;
    但是他們最終是調(diào)用統(tǒng)一的資源,所以這兩個(gè)R.java文件必須一致。
    下面是主應(yīng)用的R.java的生成腳本:
復(fù)制代碼 代碼如下:

<echo>generating R.java for project to dir gen (using aapt) ... </echo>
<exec executable="aapt">
    <arg value="package" /> <!-- package表示打包-->
    <arg value="-m" /> <!--m,J,gen表示創(chuàng)建包名的目錄和R.java到gen目錄下 -->
    <arg value="-J" />
    <arg value="gen" />
    <arg value="-M" /> <!-- M指定AndroidManifest.xml文件-->
    <arg value="AndroidManifest.xml" />
    <arg value="-S" /> <!-- S指定res目錄,生成對(duì)應(yīng)的ID,可多個(gè)-->
    <arg value="res" />
    <arg value="-S" />
    <arg value="../baseworld/res" /><!-- 注意點(diǎn):同時(shí)需要調(diào)用Library的res-->
    <arg value="-I" /> <!-- I指定android包的位置-->
    <arg value="${android-jar}" />
    <arg value="--auto-add-overlay" /> <!-- 這個(gè)重要,覆蓋資源,不然報(bào)錯(cuò)-->
</exec>

注意res和../baseworld/res兩個(gè)順序不能搞反,寫在前面具有高優(yōu)先級(jí),我們當(dāng)然優(yōu)先使用主應(yīng)用的資源了,這樣就能正確覆蓋庫應(yīng)用的資源,實(shí)現(xiàn)重寫。
    庫應(yīng)用的R.java的生成腳本差不多,區(qū)別是指定庫應(yīng)用的AndroidManifest.xml,以用于生成的是不同的包和目錄。
    另外,aapt的使用中特別說明了,為了庫應(yīng)用的資源更好的可重用,庫應(yīng)用生成的R.java字段不需要修飾為final,加上參數(shù)--non-constant-id即可。
復(fù)制代碼 代碼如下:

<echo>generating R.java for library to dir gen (using aapt) ... </echo>
<exec executable="aapt">
    <arg value="package" />
    <arg value="-m" />
    <arg value="--non-constant-id" /> <!-- 加了這個(gè)參數(shù)-->
    <arg value="--auto-add-overlay" />
    <arg value="-J" />
    <arg value="gen" />
    <arg value="-M" />
    <arg value="../baseworld/AndroidManifest.xml" /> <!-- 庫應(yīng)用的manifest-->
    <arg value="-S" />
    <arg value="res" />
    <arg value="-S" />
    <arg value="../baseworld/res" />
    <arg value="-I" />
    <arg value="${android-jar}" />
</exec>

這樣的話就可以生成2個(gè)正確的R.java文件了(如果你引用了兩個(gè)庫,則需要生成3個(gè)R.java,以此類推)。
    結(jié)果如下:
復(fù)制代碼 代碼如下:

gen
└── com
    └── tianxia
        ├── app
        │   └── floworld
        │       └── R.java
        └── lib
            └── baseworld
                └── R.java

5. 編譯java文件為class文件
    使用javac命令把src目錄,baseworld/src目錄,gen/*/R.java這些java編譯成class文件:
    命令原型是:
復(fù)制代碼 代碼如下:

//示例
javac -bootclasspath <android.jar> -s <src> -s <src> -s <gen> -d bin/classes *.jar

轉(zhuǎn)化成ant腳本為:
復(fù)制代碼 代碼如下:

<!-- 第三方j(luò)ar包需要引用,用于輔助編譯 -->
<path id="project.libs">
    <fileset dir="libs">
        <include name="*.jar" />
    </fileset>
</path>
<echo>compiling java files to class files (include R.java, library and the third-party jars) ... </echo>
<!-- 生成的class文件全部保存到bin/classes目錄下 -->
<javac destdir="bin/classes" bootclasspath="${android-jar}">
    <src path="../baseworld/src" />
    <src path="src" />
    <src path="gen" />
    <classpath refid="project.libs" />
</javac>

6. 打包c(diǎn)lass文件為classes.dex
    這步簡(jiǎn)單,用dx命令把上步生成的classes和第三方j(luò)ar包打包成一個(gè)classes.dex。
    命令原型是:
復(fù)制代碼 代碼如下:

//示例
//后面可以接任意個(gè)第三方j(luò)ar路徑
dx --dex --output=out/classes.dex bin/classes libs/1.jar libs/2.jar

轉(zhuǎn)化成ant腳本為:
復(fù)制代碼 代碼如下:

<echo>packaging class files (include the third-party jars) to calsses.dex ... </echo>
<exec executable="dx">
    <arg value="--dex" />
    <arg value="--output=out/classes.dex" /><!-- 輸出 -->
    <arg value="bin/classes" /> <!-- classes文件位置 -->
    <arg value="libs" /> <!-- 把libs下所有jar打包 -->
</exec>

7. 打包res,assets為資源壓縮包(暫且命名為res.zip)
    還是使用aapt命令,如生成R.java最大的不同是參數(shù)-F,意思是生成res.zip文件。
    命令原型和ant腳本差不多:
復(fù)制代碼 代碼如下:

<echo>packaging resource (include res, assets, AndroidManifest.xml, etc.) to res.zip ... </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="-S" />
    <arg value="../baseworld/res" />
    <arg value="-A" /> <!-- 與R.java不同,需要asset目錄也打包 -->
    <arg value="assets" />
    <arg value="-I" />
    <arg value="${android-jar}" />
    <arg value="-F" /> <!-- 輸出資源壓縮包 -->
    <arg value="out/res.zip" />
    <arg value="--auto-add-overlay" />
</exec>

8. 使用apkbuilder命令組合classes.dex,res.zip和AndroidManifest.xml為未簽名的apk
    apkbuilder命令能把class類,資源等文件打包成一個(gè)未簽名的apk,原型命令和ant腳本類似:
復(fù)制代碼 代碼如下:

<echo>building unsigned.apk ... </echo>
<exec executable="apkbuilder">
    <arg value="out/unsigned.apk" /> <!-- 輸出 -->
    <arg value="-u" /> <!-- u指創(chuàng)建未簽名的包-->
    <arg value="-z" /> <!-- 資源壓縮包 -->
    <arg value="out/res.zip" />
    <arg value="-f" /> <!-- dex文件 -->
    <arg value="out/classes.dex" />
</exec>

  這個(gè)命令比較簡(jiǎn)單。

9. 簽名未簽名的apk
    使用jarsigner命令對(duì)上步中產(chǎn)生的apk簽名。這是個(gè)傳統(tǒng)的java命令,非android專用。
    原型命令和ant腳本差不多:

復(fù)制代碼 代碼如下:

<!-- 生成apk文件到build目錄下 -->
<!-- 其中${apk-version/name/market}用戶多渠道打包,后面會(huì)講到 -->
<echo>signing the unsigned apk to final product apk ... </echo>
<exec executable="jarsigner">
    <arg value="-keystore" />
    <arg value="../xxx.keystore" />
    <arg value="-storepass" />
    <arg value="xxx" />  <-- 驗(yàn)證密鑰完整性的口令,創(chuàng)建時(shí)建立的 -->
    <arg value="-keypass" />
    <arg value="xxx" /> <-- 專用密鑰的口令,就是key密碼 -->
    <arg value="-signedjar" />
    <arg value="build/${apk-version}/${apk-name}_${apk-version}_${apk-market}.apk" /> <!-- 輸出 -->
    <arg value="out/unsigned.apk" /> <!-- 未簽名的apk -->
    <arg value="xxx" /> <!-- 別名,創(chuàng)建時(shí)建立的 -->
</exec>

至此,完整具有打包功能了,最后的build.xml為:
復(fù)制代碼 代碼如下:

<project default="main" basedir=".">

    <property name="apk-name" value="product" />
    <property name="apk-version" value="latest" />
    <property name="apk-market" value="dev" />

    <property name="android-jar" value="/usr/lib/android-sdk/platforms/android-10/android.jar" />

    <target name="init">
        <echo>start initing ... </echo>

        <mkdir dir="out" />
        <delete>
            <fileset dir="out"></fileset>
        </delete>

        <mkdir dir="gen" />
        <delete>
            <fileset dir="gen"></fileset>
        </delete>

        <mkdir dir="bin/classes" />
        <delete>
            <fileset dir="bin/classes"></fileset>
        </delete>

        <mkdir dir="build/${apk-version}" />

        <echo>finish initing. </echo>
    </target>

    <target name="main" depends="init">
        <echo>generating R.java for project to dir gen (using aapt) ... </echo>
        <exec executable="aapt">
            <arg value="package" />
            <arg value="-m" />
            <arg value="-J" />
            <arg value="gen" />
            <arg value="-M" />
            <arg value="AndroidManifest.xml" />
            <arg value="-S" />
            <arg value="res" />
            <arg value="-S" />
            <arg value="../baseworld/res" />
            <arg value="-I" />
            <arg value="${android-jar}" />
            <arg value="--auto-add-overlay" />
        </exec>

        <echo>generating R.java for library to dir gen (using aapt) ... </echo>
        <exec executable="aapt">
            <arg value="package" />
            <arg value="-m" />
            <arg value="--non-constant-id" />
            <arg value="--auto-add-overlay" />
            <arg value="-J" />
            <arg value="gen" />
            <arg value="-M" />
            <arg value="../baseworld/AndroidManifest.xml" />
            <arg value="-S" />
            <arg value="res" />
            <arg value="-S" />
            <arg value="../baseworld/res" />
            <arg value="-I" />
            <arg value="${android-jar}" />
        </exec>

        <path id="project.libs">
            <fileset dir="libs">
                <include name="*.jar" />
            </fileset>
        </path>
        <echo>compiling java files to class files (include R.java, library and the third-party jars) ... </echo>
        <javac destdir="bin/classes" bootclasspath="${android-jar}">
            <src path="../baseworld/src" />
            <src path="src" />
            <src path="gen" />
            <classpath refid="project.libs" />
        </javac>

        <echo>packaging class files (include the third-party jars) to calsses.dex ... </echo>
        <exec executable="dx">
            <arg value="--dex" />
            <arg value="--output=out/classes.dex" />
            <arg value="bin/classes" />
            <arg value="libs" />
        </exec>

        <echo>packaging resource (include res, assets, AndroidManifest.xml, etc.) to res.zip ... </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="-S" />
            <arg value="../baseworld/res" />
            <arg value="-A" />
            <arg value="assets" />
            <arg value="-I" />
            <arg value="${android-jar}" />
            <arg value="-F" />
            <arg value="out/res.zip" />
            <arg value="--auto-add-overlay" />
        </exec>

        <echo>building unsigned.apk ... </echo>
        <exec executable="apkbuilder">
            <arg value="out/unsigned.apk" />
            <arg value="-u" />
            <arg value="-z" />
            <arg value="out/res.zip" />
            <arg value="-f" />
            <arg value="out/classes.dex" />
        </exec>

        <echo>signing the unsigned apk to final product apk ... </echo>
        <exec executable="jarsigner">
            <arg value="-keystore" />
            <arg value="xxx.keystore" />
            <arg value="-storepass" />
            <arg value="xxxx" />
            <arg value="-keypass" />
            <arg value="xxx" />
            <arg value="-signedjar" />
            <arg value="build/${apk-version}/${apk-name}_${apk-version}_${apk-market}.apk" />
            <arg value="out/unsigned.apk" />
            <arg value="xxx" />
        </exec>

        <echo>done.</echo>
    </target>
</project>

在工程目錄下運(yùn)行ant:
復(fù)制代碼 代碼如下:

$ant
Buildfile: build.xml

init:
     [echo] start initing ... 
    [mkdir] Created dir: /home/openproject/world/floworld/build/latest
     [echo] finish initing. 

main:
     [echo] generating R.java for project to dir gen (using aapt) ... 
     [echo] generating R.java for library to dir gen (using aapt) ... 
     [echo] compiling java files to class files (include R.java, library and the third-party jars) ... 
    [javac] Compiling 75 source files to /home/openproject/world/floworld/bin/classes
    [javac] 注意:某些輸入文件使用或覆蓋了已過時(shí)的 API。
    [javac] 注意:要了解詳細(xì)信息,請(qǐng)使用 -Xlint:deprecation 重新編譯。
     [echo] packaging class files (include the third-party jars) to calsses.dex ... 
     [echo] packaging resource (include res, assets, AndroidManifest.xml, etc.) to res.zip ... 
     [echo] building unsigned.apk ... 
     [exec] 
     [exec] THIS TOOL IS DEPRECATED. See --help for more information.
     [exec] 
     [echo] signing the unsigned apk to final product apk ... 
     [echo] done.

BUILD SUCCESSFUL
Total time: 28 seconds

  成功的在build/latest目錄下生成一個(gè)product_latest_dev.apk,這就是默認(rèn)的生成的最終的APK,可以導(dǎo)入到手機(jī)上運(yùn)行。

10. 多渠道打包
    目前主流的多渠道打包方法是在AndroidManifest.xml中的Application下添加一個(gè)渠道元數(shù)據(jù)節(jié)點(diǎn)。
    比如,我使用的是友盟統(tǒng)計(jì),它配置AndroidManifest.XML添加下面代碼:

復(fù)制代碼 代碼如下:

<application ……>
    <meta-data android:value="Channel ID" android:name="UMENG_CHANNEL"/>
    <activity ……/>
</application>

通過修改不同的Channel ID值,標(biāo)識(shí)不同的渠道,有米廣告提供了一個(gè)不錯(cuò)的渠道列表:http://wiki.youmi.net/PromotionChannelIDs.
    實(shí)現(xiàn)多渠道自動(dòng)打包,就是實(shí)現(xiàn)自動(dòng)化過程中替換Channel ID,然后編譯打包。
    這個(gè)替換需要用到正則表達(dá)式實(shí)現(xiàn)。
    ant中提供的replace方法,功能太簡(jiǎn)單了,replaceregrex又需要添加另外的jar包,而且我們后面我們實(shí)現(xiàn)ant傳參需要寫另外的linux shell腳本,所以我干脆使用我熟悉的sed-i命令來實(shí)現(xiàn)替換。
    替換命令:
復(fù)制代碼 代碼如下:

#-i 表示直接修改文件
#$market是Channel ID, 后面會(huì)講到,是來自循環(huán)一個(gè)數(shù)組
#\1,\3分別表示前面的第1,3個(gè)括號(hào)的內(nèi)容,這樣寫很簡(jiǎn)潔
sed -i "s/\(android:value=\)\"\(.*\)\"\( android:name=\"UMENG_CHANNEL\"\)/\1\"$market\"\3/g" AndroidManifest.xml

 渠道修改的問題解決了。
    還記得前面定義的${apk-version},${apk-name},${apk-market}嗎?
    ant提供了額外的參數(shù)形式可以修改build.xml中定義的屬性的值:ant -Dapk-version=1.0,則會(huì)修改${apk-version}值為1.0,而不是latest了,其他屬性類似。
    所以,在工程下面這條命令會(huì)生成:
復(fù)制代碼 代碼如下:

#結(jié)合前面講打build.xml
#會(huì)在build/1.0/目錄下生成floworld_1.0_appchina.apk
ant -Dapk-name=floworld -Dapk-version=1.0 -Dapk-market=appchina

 命令問題通過ant的參數(shù)傳值也解決了。
    現(xiàn)在需要的是批量生產(chǎn)N個(gè)市場(chǎng)的版本,既替換AndroidManifest.xml,又生成對(duì)應(yīng)的apk文件,我結(jié)合上面說的亮點(diǎn),寫了一個(gè)shell腳本(位置:world/floworld/build.sh):
復(fù)制代碼 代碼如下:

#定義市場(chǎng)列表,以空格分割
markets="dev appchina gfan"
#循環(huán)市場(chǎng)列表,分別傳值給各個(gè)腳本
for market in $markets
do
    echo packaging floworld_1.0_$market.apk ...
    #替換AndroidManifest.xml中Channel值(針對(duì)友盟,其他同理)
    sed -i "s/\(android:value=\)\"\(.*\)\"\( android:name=\"UMENG_CHANNEL\"\)/\1\"$market\"\3/g" AndroidManifest.xml
    #編譯對(duì)應(yīng)的版本
    ant -Dapk-name=floworld -Dapk-version=1.0 -Dapk-market=$market
done

好的,在工程目錄下執(zhí)行build.sh:
復(fù)制代碼 代碼如下:

# ./build.sh 
packaging floworld_1.0_dev.apk ...
Buildfile: build.xml
... ...
packaging floworld_1.0_appchina.apk ...
Buildfile: build.xml
... ...
packaging floworld_1.0_gfan.apk ...
Buildfile: build.xml
... ...

在build下生成了對(duì)應(yīng)的apk文件:
復(fù)制代碼 代碼如下:

build
├── 1.0
│   ├── floworld_1.0_appchina.apk
│   ├── floworld_1.0_dev.apk
│   └── floworld_1.0_gfan.apk
└── README.md


 成功生成!

11. 工程腳本的執(zhí)行目錄問題
    上面的腳本執(zhí)行之后的確很cool,但是有一個(gè)問題,我必須在build.sh目錄下執(zhí)行,才能正確編譯,這個(gè)和build.xml中定義的相對(duì)路徑有關(guān)。
    我們必須在任何目錄執(zhí)行工程目錄下的build.sh都不能出錯(cuò),改進(jìn)build.sh為如下:

復(fù)制代碼 代碼如下:

#!/bin/bash
#添加如下兩行簡(jiǎn)單的代碼
#1. 獲取build.sh文件所在的目錄
#2. 進(jìn)入該build.sh所在目錄,這樣執(zhí)行起來就沒有問題了
basedir=$(cd "$(dirname "$0")";pwd)
cd $basedir

markets="dev appchina gfan"
for market in $markets
do
    echo packaging floworld_1.0_$market.apk ...
    sed -i "s/\(android:value=\)\"\(.*\)\"\( android:name=\"UMENG_CHANNEL\"\)/\1\"$market\"\3/g" AndroidManifest.xml
    ant -Dapk-name=floworld -Dapk-version=1.0 -Dapk-market=$market
done

  現(xiàn)在你在項(xiàng)目根目錄下執(zhí)行也沒有問題:./floworld/build.sh,不會(huì)出現(xiàn)路徑不對(duì),找不到文件的錯(cuò)誤了。

12. 建立整個(gè)項(xiàng)目的自動(dòng)化編譯腳本(位置:world/build.sh)
   單個(gè)工程的自動(dòng)化打包沒有問題了,但是一個(gè)項(xiàng)目下有N個(gè)工程,他們往往需要同步發(fā)布(或者daily build也需要同步編譯),所以有必要建立一個(gè)項(xiàng)目級(jí)別的編譯腳本:
   build.sh(項(xiàng)目根目錄下,位置:/world/build.sh)
   最簡(jiǎn)單的傻瓜式的做法就是,遍歷項(xiàng)目下的工程目錄,如果包含工程編譯的build.sh,則編譯該工程.
   shell腳本如下:

復(fù)制代碼 代碼如下:

#!/bin/bash
#確保進(jìn)入項(xiàng)目跟目錄
basedir=$(cd "$(dirname "$0")";pwd)
cd $basedir
#遍歷項(xiàng)目下各工程目錄
for file in ./*
do
if test -d $file
then
    #進(jìn)入工程目錄
    cd $basedir/$file
    #查找該工程目錄下是否存在編譯腳本build.sh
    if test -f build.sh
    then
        echo found build.sh in project $file.
        echo start building project $file ...
        ./build.sh
    fi
    #重要,退出工程目錄到項(xiàng)目根目錄下
    cd $basedir
fi
done

執(zhí)行該腳本:
復(fù)制代碼 代碼如下:

# ./build.sh
found build.sh in project ./floworld.
start building project ./floworld ...
packaging floworld_1.0_dev.apk ...
Buildfile: build.xml
...
...

found build.sh in project ./healthworld.
start building project ./healthworld ...
Buildfile: build.xml
...

 成功自動(dòng)尋找,并編譯打包。

13. 其他細(xì)節(jié)
    為了盡量詳細(xì),我一再解說,但是還有一些細(xì)節(jié)未包括其中,如編譯后清理clean目標(biāo),apk對(duì)齊優(yōu)化,java代碼混淆等,請(qǐng)參考其他資料,在此省略。
    另外,我反編譯生成的apk,查看Androidmanifest.xml均正確對(duì)應(yīng),驗(yàn)證通過。

14. 小結(jié)
    自動(dòng)化編譯多渠道打包這個(gè)功能是Android產(chǎn)品發(fā)布的重要環(huán)節(jié),能大大節(jié)省人力和出錯(cuò)的概率。

相關(guān)文章

最新評(píng)論