<div class="span9"> <div class="content"><header class="page-header"> <div class="icon"></div> <time datetime="2013-05-19T00:00:00.000Z"><a href="/2013/05/19/android4gradle/">May 19 2013</a></time> <h1 class="title">用Gradle 構建你的android程序</h1> </header> <div id="post" class="entry"> <h2 id="menuIndex0">前言</h2> <p>android gradle 的插件終於把混淆代碼的task集成進去了,加上最近,android studio 用的是gradle 來構建項目, 下定決心把android gralde 構建項目的用戶指南所有看完, 讓不會用gradle 的人也用gradle構建android項目,讓打包(注意,打包和構建是兩碼事)多版本android再也不痛苦。最後,題外話:珍惜生命,遠離ant.... <a name="more"></a></p> <h2 id="menuIndex1">Gradle build android 歷史</h2> <p><a href="http://tools.android.com">Android Tools 主頁</a> ,大概是今年2月份發佈 adt21.1 的時候,突然在主頁發現了<a href="http://tools.android.com/tech-docs/new-build-system">New Build System</a> 原來是能夠用gradle 來構建android項目,至於<a href="http://en.wikipedia.org/wiki/Gradle">gradle</a>是什麼(既然點擊進來看了應該都知道了吧。) 。而後,又看了一下<a href="http://tools.android.com/tech-docs/new-build-system/roadmap">RoadMap</a> 那時候,還並不支持Proguard 打包,因而就沒看了。。。</p> <p>最近,android studio 發佈,終於gradle 0.4 也跟着出來了,因而,先把gradle 學了一遍,而後把<a href="http://tools.android.com/tech-docs/new-build-system/user-guide">Gradle Plugin User Guide</a>也認真閱讀了一下,根據個人我的體驗,若是你對gradle 毫無瞭解就去看<a href="http://tools.android.com/tech-docs/new-build-system/user-guide">Gradle Plugin User Guide</a> 可能不少地方都一頭霧水,可是並不妨礙你用gradle 打包android 應用,只是,出現問題,你就可能很頭疼。不過,本篇博文就是讓不會gradle 也能用上 gradle 打包android 程序,由於,我也不懂gradle,因此,我把我碰到的問題的解決方案都一一列出。</p> <p>順便貼上官方爲何使用gradle 的理由</p> <ul> <li>Domain Specific Language (DSL) to describe and manipulate the build logic </li> <li>Build files are Groovy based and allow mixing of declarative elements through the DSL and using code to manipulate the DSL elements to provide custom logic. </li> <li>Built-in dependency management through Maven and/or Ivy. </li> <li>Very flexible. Allows using best practices but doesn’t force its own way of doing things. </li> <li>Plugins can expose their own DSL and their own API for build files to use. </li> <li>Good Tooling API allowing IDE integration </li> </ul> html
<h2 id="menuIndex3">Gradle 基本概念</h2> <p>首先咱們學習幾個gradle 的腳本語法,掌握了這幾個語法,你就能很是簡單的用gradle構建打包android項目了。首先,咱們來看下一個最簡單android <code>build.gradle</code>。</p>
<figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>java
<table><tbody> <tr> <td class="gutter"> <pre>1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17</pre> </td>android
<td class="code"> <pre>
buildscript <span class="cell">{git
repositories { mavenCentral() }</span> dependencies <span class="cell">{ classpath <span class="string">'com.android.tools.build:gradle:0.4'</span> }</span> } apply plugin: <span class="string">'android'</span> android <span class="cell">{ compileSdkVersion <span class="number">17</span> }</span></pre> </td> </tr> </tbody></table>
</figure>github
<p><strong>英語的介紹都來自與 gradle官方文檔, 主要後邊的中文不是翻譯,是補充介紹。。</strong></p> <p><code>buildscript{}</code></p> <blockquote> <p>Configures the build script classpath for this project. 說白了就是設置腳本的運行環境</p> </blockquote> <p><code>repositories{}</code></p> <blockquote> <p>Returns a handler to create repositories which are used for retrieving dependencies and uploading artifacts produced by the project. 大意就是支持java 依賴庫管理(maven/ivy),用於項目的依賴。這也是gradle 強力的地方。。。 </p> </blockquote> <p><code>dependencies{}</code></p> <blockquote> <p>The dependency handler of this project. The returned dependency handler instance can be used for adding new dependencies. For accessing already declared dependencies, the configurations can be used. 依賴包的定義。支持maven/ivy,遠程,本地庫,也支持單文件,若是前面定義了<code>repositories{}</code>maven 庫,使用maven的依賴(我沒接觸過ivy。。)的時候只須要按照用相似於<code>com.android.tools.build:gradle:0.4</code>,gradle 就會自動的往遠程庫下載相應的依賴。</p> </blockquote> <p><code>apply plugin:</code></p> <blockquote> <p>聲明構建的項目類型,這裏固然是android了。。。</p> </blockquote> <p><code>android{}</code></p> <blockquote> <p>設置編譯android項目的參數,接下來,咱們的構建android項目的全部配置都在這裏完成。</p> </blockquote> <h2 id="menuIndex4">構建一個Gradle android項目</h2> <p>首先,你要安裝<a href="http://www.gradle.org/downloads">Gradle 1.6</a> 而且,寫進系統的環境變量裏面,全部的命令都是默認你已經配好了gradle 的環境。並且,已經已經升級了android sdk 22</p> <p>要用gradle構建你的有兩種方式:(<strong>build.gradle 放到項目目錄下</strong>)</p> <ol> <li>利用adt 22導出 build.gradle. </li> <li>複製別人寫好的build.gradle 文件. </li> <li>根據gradle 規則,手寫android 的build.gradle 文件。 </li> </ol> <p>我的推薦1,2 方法。。。。</p> <p>一個android build.gradle 最基本基本文件</p>
<figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>shell
<table><tbody> <tr> <td class="gutter"> <pre>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</pre> </td>app
<td class="code"> <pre>buildscript { repositories { mavenCentral() } dependencies { classpath <span class="comment">'com.android.tools.build:gradle:0.4'</span> }
}maven
apply plugin: <span class="comment">'android'</span>ide
dependencies { }post
android {
compileSdkVersion <span class="number">17</span> buildToolsVersion <span class="string">"17"</span> defaultConfig { minSdkVersion <span class="number">8</span> targetSdkVersion <span class="number">17</span> } sourceSets { main { manifest.srcFile <span class="comment">'AndroidManifest.xml'</span> java.srcDirs = [<span class="comment">'src']</span> resources.srcDirs = [<span class="comment">'src']</span> aidl.srcDirs = [<span class="comment">'src']</span> renderscript.srcDirs = [<span class="comment">'src']</span> res.srcDirs = [<span class="comment">'res']</span> assets.srcDirs = [<span class="comment">'assets']</span> } instrumentTest.setRoot(<span class="comment">'tests')</span> }
}</pre> </td> </tr> </tbody></table>
</figure>
<p>接着在命令行cd 到項目目錄下</p> <blockquote> <p>例如: cd e:\workplace\andoridGradle</p> </blockquote> <p>若是你是第一次使用gradle 構建android項目建議你先使用<code>gradle clean</code> 把android gradle 插件,還有相關依賴包下載下來而且對環境進行初始化,若是出錯了,通常多是下載超時,試多幾回便可,最後你會看到以下提示:<code>BUILD SUCCESSFUL</code></p> <p>The TaskContainer.add() method has been deprecated and is scheduled to be remove d in Gradle 2.0. Please use the create() method instead.</p> <p>:clean UP-TO-DATE</p> <p>BUILD SUCCESSFUL</p> <p>Total time: 7.847 secs</p> <p>完成以上的步驟,就能夠正式使用gralde 構建你的android項目了。</p> <p>而後使用<code>gradle build</code> 就完成了android 項目的構建了。若是,你是照着以上步驟走的話,你將會想項目目錄裏面看到一個build 的目錄,裏面就是用gradle 構建android項目的所有例如了,結構目錄看附錄。</p> <p>最終打包的apk 就在build/apk 目錄下了。而後,你會發現,兩個apk 一個是 <em>[項目名]-debug-unaligned </em>[項目名]-release-unsigned</p> <p>若是以上內容你都掌握的話,接下來就將詳細說說如何利用gralde 打包android apk。</p> <h2 id="menuIndex5">Gralde 打包參數詳解</h2> <p>上面說了一大堆東西,其實並不吸引人去使用gradle,若是隻是構建項目的話,adt不是更合適嗎?若是,你看完如下內容仍是這麼以爲的話,你就不必折騰gradle了。。。。。。</p> <h3 id="menuIndex6">打簽名包</h3> <p>看附錄 默認輸出 <em>release</em> apk 是沒有簽名的,那麼咱們須要簽名的很簡單,只須要在android{}裏面補充加上加上便可。完整<a href="https://gist.github.com/youxiachai/5608223">build.gradle 請點擊個人gist</a></p>
<figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>
<table><tbody> <tr> <td class="gutter"> <pre>1
2 3 4 5 6 7 8 9 10 11 12 13 14 15</pre> </td>
<td class="code"> <pre>signingConfigs <span class="cell">{
myConfig{ storeFile file("gradle.keystore") storePassword "gradle" keyAlias "gradle" keyPassword "gradle" }</span> }
buildTypes<span class="cell">{ release { signingConfig signingConfigs.myConfig }</span> } </pre> </td> </tr> </tbody></table>
</figure>而後,運行<code>gradle clean</code> <code>gradle build</code> ,此次在build/apk 你看到了多了一個[項目名]-release-unaligned, 從字面上面我就能夠知道,這個只是沒有進行zipAlign 優化的版本而已。而[項目名]-release 就是咱們簽名,而且zipAlign 的apk包了. ###打混淆包### 只須要在原來的基礎上加上,完整的<a href="https://gist.github.com/youxiachai/5608223">proguad.gradle 代碼</a> <figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>
<table><tbody> <tr> <td class="gutter"> <pre>1
2 3 4 5 6 7 8</pre> </td>
<td class="code"> <pre>buildTypes{
release { signingConfig signingConfigs.myConfig runProguard <span class="literal">true</span> proguardFile <span class="comment">'proguard-android.txt'</span> } }</pre> </td> </tr> </tbody></table>
</figure>
<p><code>gradle clean</code></p> <p><code>gradle build</code></p> <h3 id="menuIndex7">打多渠道包(Product Flavor)</h3> <p>如今來解釋一下上一節的問題,<strong>apk目錄下的兩個apk 的含義</strong></p> <p><strong>爲何產生了兩個apk?</strong></p> <p>默認的android gralde 插件定義了兩種apk 的類型<strong>debug</strong>, <strong>release</strong>,這兩種類型的詳細對比看附錄。</p> <p>這個是android gralde 插件 <code>buildTypes{}</code> 方法產生的,默認配置好了兩個默認模板,固然你也能夠修改,前面咱們就是在修改默認的release 的配置,讓輸出release類型的的apk,具備簽名和混淆。</p> <p>對於多渠道包,android 插件提供了一個名爲<code>Product Flavor{}</code> 的配置,用於進行多渠道打包。</p> <p>例如,個人android應用有海外版,和國內版本,並且這兩個版本的包名是不同的!!(我就舉兩個市場的例子安裝這個思路,你要打包100個不一樣的市場只是幾行代碼的事情。)。</p> <p>你只須要在<code>android{}</code> 補充上</p>
<figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>
<table><tbody> <tr> <td class="gutter"> <pre>1
2 3 4 5 6 7 8</pre> </td>
<td class="code"> <pre>productFlavors { playstore { packageName=<span class="comment">'com.youxiachai.androidgradle.playstore'</span> } hiapk { packageName=<span class="comment">'com.youxiachai.androidgradle.amazonappstore'</span> }
}</pre> </td> </tr> </tbody></table>
</figure>
<p>而後<code>gradle clean</code>,<code>gradle build</code>,在build/apk 下面你會看到一堆的包,命名格式[項目名]-[渠道名]-release</p> <p><strong>僅此而已?</strong></p> <p><code>Product Flavor{}</code> 不僅是能改包名那麼簡單,還可以對編譯的源碼目錄進行切換。</p> <p>什麼意思? 不知道各位有沒有用過友盟作用戶統計,若是,你用的是分發渠道分析,你須要修改AndroidManifest.xml 添加上 <code><meta-data android:value="hiapk" android:name="UMENG_CHANNEL"/></code></p> <p>若是,你不少渠道,,而後你就會很痛苦,如今用gradle 就很是舒服,你只須要在<code>android.sourceSets</code>指定咱們的渠道名就行,android gradle 插件,會自動打包!!!例如</p>
<figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>
<table><tbody> <tr> <td class="gutter"> <pre>1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21</pre> </td>
<td class="code"> <pre>sourceSets { main { manifest.srcFile <span class="comment">'AndroidManifest.xml'</span> java.srcDirs = [<span class="comment">'src']</span> resources.srcDirs = [<span class="comment">'src']</span> aidl.srcDirs = [<span class="comment">'src']</span> renderscript.srcDirs = [<span class="comment">'src']</span> res.srcDirs = [<span class="comment">'res']</span> assets.srcDirs = [<span class="comment">'assets']</span> } hiapk { manifest.srcFile <span class="comment">'hiapk/AndroidManifest.xml'</span> } playstore { manifest.srcFile <span class="comment">'hiapk/AndroidManifest.xml'</span> } instrumentTest.setRoot(<span class="comment">'tests')</span>
}</pre> </td> </tr> </tbody></table>
</figure>而後運行<code>gradle clean</code>,<code>gradle build</code>,省下的時間去喝杯咖啡,睡個覺什麼的都好。。。 ###外部依賴### android gradle 對於外部jar 包的應用支持maven/ivy 管理的包,也支持指定具體文件,前面已經在上文說過。上面演示的完整 build.gradle gist 裏面也有寫。你須要加上以下代碼便可: <figure class="highlight lang-groovy"><figcaption><span>build.gradle </span></figcaption>
<table><tbody> <tr> <td class="gutter"> <pre>1
2 3</pre> </td>
<td class="code"> <pre><span class="title">dependencies</span> { <span class="title">compile</span> files(<span class="string">'libs/android-support-v4.jar'</span>)
}</pre> </td> </tr> </tbody></table>
</figure>
<h2 id="menuIndex8">結語</h2> <p>至此,對於用android gradle 構建android應用程序,打包android 程序,所須要的全部知識,在以上已經說明,只要你是認真看上面文章的,對於,如何打依賴於android library project 的包,能夠看附錄提供的那個德國人寫的例子,而對於<code>build.gradle</code> 裏面的代碼你須要把<code>0.2</code>, 改成<code>0.4</code>便可。至於用gradle 運行android test case部分的教程,我的感受寫了也白寫(我寫過關於andorid 測試相關的文章,也錄製過視頻,因此有這個感受。),估計不會有人關注,因此,若是你對用gradle 進行android test的話,能夠看附錄裏面提供的官方gradle手冊。</p> <h2 id="menuIndex9">擴展閱讀</h2> <p>對於這部份內容,你讀與不讀,並不影響你使用gradle 打包android 項目。至於讀了的好處就是你可以更好的使用gradle。。</p> <ul> <li> <p>完整的<a href="http://tools.android.com/tech-docs/new-build-system/user-guide">Gradle Plugin User Guide</a> 其中裏面有個錯誤是<code>compile files('libs/android-support-v4.jar')</code> 不是<code>compile file('libs/android-support-v4.jar')</code> 教程是基於android gradle0.3 ,在0.4中只是多了<strong>混淆打包,這塊已經在文中補充了。</strong></p> </li> <li> <p>一個德國人寫的<a href="https://github.com/Goddchen/Android-Gradle-Examples">Android-Gradle-Examples</a></p> </li> <li> <p><a href="http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html"><code>dependencies{}</code></a> 更多的介紹。</p> </li> <li> <p><strong>debug</strong>, <strong>release</strong>,這兩種類型的默認配置以下:</p> <table style="border-bottom-color: rgb(136,136,136); border-right-width: 1px; border-top-color: rgb(136,136,136); border-collapse: collapse; border-top-width: 1px; border-bottom-width: 1px; border-right-color: rgb(136,136,136); border-left-color: rgb(136,136,136); border-left-width: 1px" border="1" cellspacing="0" bordercolor="#080808"><tbody> <tr> <td style="width: 198px; height: 19px">Property name</td> <td style="width: 195px; height: 19px">Default values for debug</td> <td style="width: 241px; height: 19px">Default values for release / other</td> </tr> <tr> <td style="width: 198px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>debuggable</b></font></td> <td style="width: 195px; height: 20px">true</td> <td style="width: 241px; height: 20px">false</td> </tr> <tr> <td style="width: 198px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>jniDebugBuild</b></font></td> <td style="width: 195px; height: 20px">false</td> <td style="width: 241px; height: 20px">false</td> </tr> <tr> <td style="width: 198px; height: 19px"> <b><font color="#38761d" face="courier new, monospace">renderscriptDebugBuild</font></b></td> <td style="width: 195px; height: 19px">false</td> <td style="width: 241px; height: 19px">false</td> </tr> <tr> <td style="width: 198px; height: 20px"> <b><font color="#38761d" face="courier new, monospace">renderscriptOptimLevel</font></b></td> <td style="width: 195px; height: 20px">3</td> <td style="width: 241px; height: 20px">3</td> </tr> <tr> <td style="width: 198px; height: 20px"> <b><font color="#38761d" face="courier new, monospace">packageNameSuffix</font></b></td> <td style="width: 195px; height: 20px">null</td> <td style="width: 241px; height: 20px">null</td> </tr> <tr> <td style="width: 198px; height: 20px"> <b><font color="#38761d" face="courier new, monospace">versionNameSuffix</font></b></td> <td style="width: 195px; height: 20px">null</td> <td style="width: 241px; height: 20px">null</td> </tr> <tr> <td style="width: 198px; height: 20px"> <b><font color="#38761d" face="courier new, monospace">signingConfig</font></b></td> <td style="width: 195px; height: 20px">android.signingConfigs.debug</td> <td style="width: 241px; height: 20px">null</td> </tr> <tr> <td style="width: 198px; height: 20px"> <b><font color="#38761d" face="courier new, monospace">zipAlign</font></b></td> <td style="width: 195px; height: 20px">false</td> <td style="width: 241px; height: 20px">true</td> </tr> </tbody></table> </li> </ul> <ul> <li> <p><strong>defaultConfig {}</strong> 配置參數列表</p> <table style="border-bottom-color: rgb(136,136,136); border-right-width: 1px; border-top-color: rgb(136,136,136); border-collapse: collapse; border-top-width: 1px; border-bottom-width: 1px; border-right-color: rgb(136,136,136); border-left-color: rgb(136,136,136); border-left-width: 1px" border="1" cellspacing="0" bordercolor="#080808"><tbody> <tr> <td style="width: 208px; height: 19px">Property Name</td> <td style="width: 168px; height: 19px">Default value in DSL object</td> <td style="width: 251px; height: 19px">Default value</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>versionCode</b></font></td> <td style="width: 168px; height: 20px">-1</td> <td style="width: 251px; height: 20px">value from manifest if present</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>versionName</b></font></td> <td style="width: 168px; height: 20px">null</td> <td style="width: 251px; height: 20px">value from manifest if present</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>minSdkVersion</b></font></td> <td style="width: 168px; height: 20px">-1</td> <td style="width: 251px; height: 20px">value from manifest if present</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>targetSdkVersion</b></font></td> <td style="width: 168px; height: 20px">-1</td> <td style="width: 251px; height: 20px">value from manifest if present</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>packageName</b></font></td> <td style="width: 168px; height: 20px">null</td> <td style="width: 251px; height: 20px">value from manifest if present</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>testPackageName</b></font></td> <td style="width: 168px; height: 20px">null</td> <td style="width: 251px; height: 20px">app package name + 「.test」</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>testInstrumentationRunner</b></font></td> <td style="width: 168px; height: 20px">null</td> <td style="width: 251px; height: 20px">android.test.InstrumentationTestRunner</td> </tr> <tr> <td style="width: 208px; height: 19px"> <font color="#38761d" face="courier new, monospace"><b>signingConfig</b></font></td> <td style="width: 168px; height: 19px">null</td> <td style="width: 251px; height: 19px">null</td> </tr> <tr> <td style="width: 208px; height: 20px"> <font color="#38761d" face="courier new, monospace"><b>runProguard</b></font></td> <td style="width: 168px; height: 20px">false</td> <td style="width: 251px; height: 20px">false</td> </tr> <tr> <td style="width: 208px; height: 19px"> <font color="#38761d" face="courier new, monospace"><b>proguardFile</b></font></td> <td style="width: 168px; height: 19px">  'proguard-android.txt' or 'proguard-android-optimize.txt'</td> <td style="width: 251px; height: 19px">  'proguard-android.txt' or 'proguard-android-optimize.txt'</td> </tr> </tbody></table> </li> <li> <p>build 結構目錄</p>
<figure class="highlight lang-shell"><figcaption><span>tree </span></figcaption>
<table><tbody> <tr> <td class="gutter"> <pre>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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90</pre> </td>
<td class="code"> <pre>build/
├── apk ├── assets │ ├── debug │ └── <span class="keyword">release</span> ├── classes │ ├── debug │ │ └── com │ │ └── example │ │ └── gradle │ └── <span class="keyword">release</span> │ └── com │ └── example │ └── gradle ├── dependency-cache │ ├── debug │ └── <span class="keyword">release</span> ├── incremental │ ├── aidl │ │ ├── debug │ │ └── <span class="keyword">release</span> │ ├── dex │ │ ├── debug │ │ └── <span class="keyword">release</span> │ ├── mergeAssets │ │ ├── debug │ │ └── <span class="keyword">release</span> │ └── mergeResources │ ├── debug │ └── <span class="keyword">release</span> ├── libs ├── manifests │ ├── debug │ └── <span class="keyword">release</span> ├── res │ ├── <span class="keyword">all</span> │ │ ├── debug │ │ │ ├── drawable-hdpi │ │ │ ├── drawable-mdpi │ │ │ ├── drawable-xhdpi │ │ │ ├── drawable-xxhdpi │ │ │ ├── layout │ │ │ ├── menu │ │ │ ├── values │ │ │ ├── values-sw720dp-land │ │ │ ├── values-v11 │ │ │ └── values-v14 │ │ └── <span class="keyword">release</span> │ │ ├── drawable-hdpi │ │ ├── drawable-mdpi │ │ ├── drawable-xhdpi │ │ ├── drawable-xxhdpi │ │ ├── layout │ │ ├── menu │ │ ├── values │ │ ├── values-sw720dp-land │ │ ├── values-v11 │ │ └── values-v14 │ └── rs │ ├── debug │ └── <span class="keyword">release</span> ├── source │ ├── aidl │ │ ├── debug │ │ └── <span class="keyword">release</span> │ ├── buildConfig │ │ ├── debug │ │ │ └── com │ │ │ └── example │ │ │ └── gradle │ │ └── <span class="keyword">release</span> │ │ └── com │ │ └── example │ │ └── gradle │ ├── r │ │ ├── debug │ │ │ └── com │ │ │ └── example │ │ │ └── gradle │ │ └── <span class="keyword">release</span> │ │ └── com │ │ └── example │ │ └── gradle │ └── rs │ ├── debug │ └── <span class="keyword">release</span> └── symbols ├── debug └── <span class="keyword">release</span> <span class="number">88</span> directories</pre> </td> </tr> </tbody></table>
</figure></li> </ul>
<h2 id="menuIndex10">最後的吐槽</h2> <p>吐槽一下。。。用ant腳本的(也許你沒有接觸過。。)。在之前你用ant 腳本打包apk的時候須要打包不一樣包名,你須要用ant 讀取<code>AndroidManifest.xml</code> 而後又正則匹配替換裏面packagename 參數。。雖然描述得過程很簡單,你真去寫的時候你就蛋疼了(對於一個ant外行人來講,我的感受ant的學習曲線太陡峭了,若是是兩年前的我,可能還寫得出這樣的ant腳本(當年費了很大的功夫學習了一個多星期),不過,由於不多用到(後來知道maven了。。果斷放棄了ant,爲何不在android使用maven? 由於,android 的maven 插件式非官方的,並且如今看來maven 的xml實在很複雜,看起來就頭疼))*</p> </div> <p></p>
</div>
<p></p> </div>