Gradle for Android 問題總結

Gradle是什么?

Gradle 是以Groovy為基礎,面向java應用,基于DSL語法的自動化構建工具。是google引入,替換ant和maven的新工具,其依賴兼容maven和ivy。

使用gradle的目的:
更容易重用資源和代碼;
可以更容易創建不同的版本的程序,多個類型的apk包;
更容易配置,擴展;
更好的IDE集成;

首先明確gradle跟maven一樣,也有一個配置文件,maven里面是叫pom.xml,而在gradle中是叫build.gradle。Android Studio中的android項目通常至少包含兩個build.gradle文件,一個是project范圍的,另一個是module范圍的,由于一個project可以有多個module,所以每個module下都會對應一個build.gradle。這么說有點抽象,看下面這個圖:


1. Project中build.gradle

project下的build.gradle是基于整個project的配置,主要配置gradle 版本及 全局依賴倉庫、庫或者其他全部參數。
android studio 現在重要倉庫采用jcenter(),之前版本放在mavenCentral。
另外有時還沒有加入jcenter()倉庫的第三方庫,也需要在這里配置他們的庫地址。
需要在這里配置,才能將第三方庫拉下來

buildscript {
   //構建過程依賴的倉庫
  repositories {
      jcenter()
  }
  
  //構建過程需要依賴的庫
  dependencies {
      //聲明的是gradle插件的版本
      classpath 'com.android.tools.build:gradle:2.0.0'

      // NOTE: Do not place your application dependencies here; they belong
      // in the individual module build.gradle files
  }
}

allprojects {
  //這里面配置整個項目依賴的倉庫,這樣每個module就不用配置倉庫了
  repositories {
      jcenter()

      maven {
          // LeanCloud 的包倉庫
          url "http://mvn.leancloud.cn/nexus/content/repositories/releases"
      }
  }
}

//配置全局變量
ext {
  // module依賴庫公共版本號
  SupportXVersion = '23.2.0'
  GsonVersion = '2.6.2'
  LeanCloudVersion = 'v3.13.4'
  JunitVersion = '4.12'
  
  compileSdkVersion = 22
  buildToolsVersion = "23.0.1"
  minSdkVersion = 10
  targetSdkVersion = 22
  versionCode = 34
  versionName = "v2.6.1"
}

注:大家可能很奇怪,為什么倉庫repositories需要聲明兩次,這其實是由于它們作用不同,buildscript中的倉庫是gradle腳本自身需要的資源,而allprojects下的倉庫是項目所有模塊需要的資源

2. module中build.gradle

//申明使用插件,表明要編譯的內容和產物,
//com.android.application 表明該module 為android 應用
//com.android.library 表明為library庫
//java 表名是java庫
apply plugin: 'com.android.application'

//安卓構建過程需要配置的參數
android {
    //編譯SDK的版本
    compileSdkVersion COMPILE_SDK_VERSION as int
    //buildtool 的版本
    buildToolsVersion BUILD_TOOLS_VERSION
    
    /默認配置,會同時應用到debug和release版本上
    defaultConfig {
        //應用包名
        applicationId APPLICATION_ID
        //支持最小android sdk 版本
        minSdkVersion MIN_SDK_VERSION as int
        // 目標版本
        targetSdkVersion TARGET_SDK_VERSION as int
        //應用版本號
        versionCode VERSION_CODE as int
        //應用版本名稱
        versionName VERSION_NAME
        
        /// 配置生成的 BuildConfig 文件中的常量,代碼引用直接 
        buildConfigField "String", "LOG_TAG", LOG_TAG // 日志tag
        buildConfigField "String", "LOG_HTTP_TAG", LOG_TAG_HTTP // http日志tag
        buildConfigField "String", "LOG_WEB_TAG", LOG_TAG_WEB // web日志tag

      // 默認是UMENG_CHANNEL_VALUE為umeng
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng"]
        
      // dex突破65535的限制
        multiDexEnabled true
    }
    
    //java版本號
    compileOptions{
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
    
    //簽名
    signingConfigs {
        release {
            //簽名文件
            storeFile file(STORE_FILE)
            storePassword STORE_PASSWORD
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
        }
    }
    // 為了解決部分第三方庫重復打包了META-INF的問題
    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
    }
    
    //移除lint檢測的error
    lintOptions {
        abortOnError false
    }
    
    //編譯類型
    //其中debug, release是gradle默認自帶的兩個build type, 當然你可以定義其他類型。
    //可以針對不停編譯的版本中配置不同的參數,比如混淆、簽名等。preview
    buildTypes {
        debug {
            minifyEnabled false
            zipAlignEnabled false
            shrinkResources false
        }
        
         preview {
            debuggable false // 是否保留調試信息
            minifyEnabled true  //是否混淆
            zipAlignEnabled true // 包優化
            shrinkResources true // 移除不必要的資源

            // 簽名
            signingConfig signingConfigs.release
            // 代碼混淆規則文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        
        release {
            //加上后綴
            applicationIdSuffix ".release"
            minifyEnabled true //是否混淆
            zipAlignEnabled true // zip對齊優化
            shrinkResources true // 移除不必要的資源
            
            // 不顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"

            // 簽名
            signingConfig signingConfigs.release
            //混淆文件的位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    // 多渠道
    productFlavors {
        //可以設置不同渠道渠道號,應用名稱
        dev { // 開發
            buildConfigField "String", "CHANNEL_NUMBER", '"11111"'
        }
        '360' {
            buildConfigField "String", "CHANNEL_NUMBER", '"11112"'
        }
        GooglePlay {
            buildConfigField "String", "CHANNEL_NUMBER", "11113"'

    }
    // 多渠道批量替換
    productFlavors.all { flavor ->
         //批量修改Manifest占位符替換
        //在Manifest使用`${UMENG_CHANNEL_VALUE}`,`LEANCLOUD_CHANNEL_VALUE`,打包時將替換成渠道名,例如UMENG_CHANNEL_VALUE="dev";
        flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name, LEANCLOUD_CHANNEL_VALUE: name]
        // Project Properties->_myAPPBuildVersionName,用于程序集成下命令行修改
        if (project.hasProperty('_myAPPBuildVersionName')) {
            defaultConfig.versionName = _myAPPBuildVersionName
        }
    }
     
     //定義變量
     //gradle 可以用def定義一些值例如:def KeyPassword = "123123" 
     def releaseTime() {
         return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
     }

    
    // 批量打包
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                def fileName
                if (variant.buildType.name.equals('release')) {
                    // myAPP_v版本號_渠道名.apk
                    fileName = "myAPP_v${variant.versionName}_${variant.productFlavors[0].name}.apk"
                } else {
                    // myAPP_v版本號_渠道名_時間_編譯類型名.apk
                    fileName = "myAPP_v${variant.versionName}_${variant.productFlavors[0].name}_${releaseTime()}_${variant.buildType.name}.apk"
                }
                output.outputFile = new File(outputFile.parent + "/${variant.buildType.name}", fileName)
            }
        }
    }


}

//依賴第三方庫
dependencies {
   //編譯libs目錄下所以jar包
   //compile files('libs/xxx.jar')   導入一個特定jar包
    compile fileTree(dir: 'libs', include: ['*.jar'])//導入所有的jar包
    compile project(':core')
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
    compile 'com.android.support:recyclerview-v7:23.1.1'
    compile 'com.android.support:cardview-v7:23.1.1'
}

注意:

  • buildToolsVersion這個需要你本地安裝該版本才行,很多人導入新的第三方庫,失敗的原因之一是build version的版本不對,這個可以手動更改成你本地已有的版本或者打開 SDK Manager 去下載對應版本。
  • proguardFiles這部分有兩段,前一部分代表系統默認的android程序的混淆文件,該文件已經包含了基本的混淆聲明,免去了我們很多事,這個文件的目錄在 /tools/proguard/proguard-android.txt , 后一部分是我們項目里的自定義的混淆文件,目錄就在 app/proguard-rules.pro ,在這個文件里你可以聲明一些第三方依賴的一些混淆規則,最終混淆的結果是這兩部分文件共同作用的。
  • 一般重要的信息,例如簽名信息,可以直接將信息寫到gradle.properties,然后在然后在build.gradle中引用即可。
  • 多渠道的關鍵在于定義不同的product flavor。
    注意:這里的flavor名如果是數字開頭,必須用引號引起來。
  • buildTypes是指建構的類型,一般只用兩種默認類型 debug 和 release ,顧名思義 debug 用來配置開發過程中的一些內容;release 用來配置正式發布版本的內容。有時我們需要發布介于debug與release之間的preview 版本。

3. Project中setting.gradle

這個文件是全局的項目配置文件,里面主要聲明Project中所包括的所有module,

//一個Project中所包括的所有module
include ':app', ':model',':lib', ':core'

4. Project中gradle.properties

gradle.properties為gradle的配置文件,里面可以定義一些常量供build.gradle使用,比如可以配置簽名相關信息如keystore位置,密碼,keyalias等,build.gradle就可以直接引用
gradle 中的一些配置參數建議寫到gradle.properties

//編譯版本信息
APPLICATION_ID = com.jin.myAPP
COMPILE_SDK_VERSION = 23
BUILD_TOOLS_VERSION = 23.0.1
MIN_SDK_VERSION = 15
TARGET_SDK_VERSION = 1
VERSION_CODE = 1
VERSION_NAME = 1.0.0.0

//keystore信息
STORE_FILE = ../app/mykey.keystore
STORE_PASSWORD = your password
KEY_ALIAS = your alias
KEY_PASSWORD = your password

5. ext配置全局參數

project的build.gradle中的ext可以為各位module進行全局配置參數,防止各個module之間的不統一,不可控。而且當我們升級sdk、build tool、target sdk等,幾個module都要更改,非常的麻煩。

ext {
   compileSdkVersion = 22
   buildToolsVersion = "23.0.1"
   minSdkVersion = 10
   targetSdkVersion = 22
   versionCode = 34
   versionName = "v2.6.1"
}

然后在各自module的build.gradle中引用:

android {

  compileSdkVersion rootProject.ext.compileSdkVersion

  buildToolsVersion rootProject.ext.buildToolsVersion

 defaultConfig {

    applicationId "com.xxx.xxx"

    minSdkVersion rootProject.ext.minSdkVersion

    targetSdkVersion rootProject.ext.targetSdkVersion

    versionCode rootProject.ext.versionCode

    versionName rootProject.ext.versionName
  }
}

6. resValue 定義資源。

例如resValue "string" 就是字符串資源,可以用R.String 來引用對應的字符串資源

android {
   defaultConfig {
       resValue "string", "build_time", buildTime()
       resValue "string", "build_host", hostName()
       resValue "string", "build_revision", revision()
    }
}

def buildTime() {
   return new Date().format("yyyy-MM-dd HH:mm:ss")
}

def hostName() {
   return System.getProperty("user.name") + "@" +InetAddress.localHost.hostName
 }

def revision() {
  def code = new ByteArrayOutputStream()
     exec {
        commandLine 'git', 'rev-parse', '--short', 'HEAD'
        standardOutput = code
      }
  return code.toString()
  }

上述代碼實現了動態的添加了3個字符串資源: build_time、build_host、build_revision, 然后在其他地方可像如引用字符串一樣使用如下:

// 在Activity里調用
getString(R.string.build_time) // 輸出2015-11-07 17:01
getString(R.string.build_host) // 輸出jay@deepin,這是我的電腦的用戶名和PC名
getString(R.string.build_revision) // 輸出3dd5823, 這是最后一次commit的sha值

7. PlaceHolder

manifest的一些值我們可以用PlaceHolder處理。例如

<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_VALUE}" />

在gradle中改成

 manifestPlaceholders = [UMENG_CHANNEL_VALUE: "360"]

可以放在defaultConfig中設置默認值,或者放在productFlavors中根據不同渠道修改成不同值。或者批量修改

  productFlavors.all { 
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
    }

8. 導入某個project

如果你的app是多模塊的,假設有兩個模塊app和lib,并且app模塊是依賴lib的,這時候我們就需要在app模塊的build.gradle中的dependencies結點下配置依賴:

compile project(':lib')

并且你需要在settings.gradle中把lib模塊包含進來:

include ':lib',':app'

此外,這種情況下lib模塊是作為庫存在的,因而它的build.gradle中的插件聲明通常應該是這樣的:

apply plugin: 'com.android.library'

而且,作為library的模塊lib的build.gradle文件的defaultConfig中是不允許聲明applicationId的,這點需要注意。

9. 引用本地aar:

  • 首先將你的庫通過android studio 運行打包成aar文件。運行后在/build/output/aar文件夾中。
  • 首先將aar文件放到模塊的libs目錄下,然后在該模塊的build.gradle中聲明flat倉庫:
repositories{
     flatDir {
        dirs 'libs'
    }
}
  • 最后在dependencies結點下依賴該aar模塊:
dependencies{
    compile (name:'xxx',ext:'aar')
}

10. BuildConfig

在build.gradle中配置buildConfigField參數,編譯后會在..\app\build\generated\source\buildConfig文件夾下會自動生成對應版本對應module的BuildConfig.java。BuildConfig就會包含對應版本的配置信息。程序中可以直接引用這些數據。例如BuildConfig.DEBUG。

public final class BuildConfig {
 public static final boolean DEBUG = Boolean.parseBoolean("true");
 public static final String BUILD_TYPE = "debug";
 public static final String FLAVOR = "360";
 public static final int VERSION_CODE = 45;
 public static final String VERSION_NAME = "3.2.0.0";
 // Fields from build type: debug
 public static final String HOST_IMG_SERVER = "img";
 public static final String HOST_SERVER = "test";
 // Fields from product flavor: 360
 public static final String CHANNEL_NUMBER = "232100";
}

11. module 調整目錄結構sourceSets

默認情況下,java文件和resource文件分別在src/main/java和src/main/res目錄下,在build.gradle文件,andorid{}里面添加下面的代碼,便可以將java文件和resource文件放到src/java和src/resources目錄下。

sourceSets {
   main {
      java {
          srcDir 'src/java'
      }
      resources {
        srcDir 'src/resources'
     }
   }
}

更簡便的寫法是:

sourceSets {
   min.java.srcDirs = ['src/java']
   min.resources.srcDirs = ['src/resources']
}

12. Gradle常用命令

上面大家接觸了一些命令如 ./gradlew -v ./gradlew clean ./gradlew build, 這里注意是./gradlew, ./代表當前目錄,gradlew代表 gradle wrapper,意思是gradle的一層包裝,大家可以理解為在這個項目本地就封裝了gradle,即gradle wrapper, myAPP/gradle/wrapper/gralde-wrapper.properties**文件中聲明了它指向的目錄和版本。只要下載成功即可用grdlew wrapper的命令代替全局的gradle命令。

理解了gradle wrapper的概念,下面一些常用命令也就容易理解了。

  • ./gradlew 下載更新gradle
  • ./gradlew -v 版本號
  • ./gradlew assemble 構建項目輸出
  • ./gradlew check 運行檢測和測試任務
  • ./gradlew clean 清除9GAG/app目錄下的build文件夾
  • ./gradlew build 運行check和assemble,檢查依賴并編譯打包
    這里注意的是 ./gradlew build 命令把debug、release環境的包都打出來,如果正式發布只需要打Release的包,該怎么辦呢,下面介紹一個很有用的命令 assemble<build type="" name="">, 如</build>
  • ./gradlew assembleDebug 編譯并打Debug包
  • ./gradlew assembleRelease 編譯并打Release的包所有渠道的
  • ./gradlew assembleWandoujiaRelease 編譯并打包豌豆莢的Release版本
  • ./gradlew assembleWandoujia 編譯并打包豌豆莢的所有版本
  • ./gradlew installRelease Release模式打包并安裝
  • ./gradlew uninstallRelease 卸載Release模式包
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,807評論 18 139
  • 轉至:http://blog.csdn.net/heqiangflytosky/article/details/5...
    kkgo閱讀 2,911評論 0 1
  • 本文原作者為:kale2010 .blog地址:http://www.cnblogs.com/tianzhijie...
    NoValue閱讀 3,582評論 0 11
  • 轉載注明出處:http://www.lxweimin.com/p/5255b100930e 0. 前言 完全由個人翻...
    王三的貓阿德閱讀 2,538評論 0 4
  • 上周末看了電視節目[歡樂喜劇人] 。賈玲演了個節目:先是老板把她炒了,接著回家尋求老公安慰,發現老公有外遇;傷心欲...
    stillwalking閱讀 327評論 1 1