一、統一管理依賴版本
1.1 在根目錄下,新建config.gradle
檔案
ext {
android = [
compileSdkVersion: 23,
buildToolsVersion: "23.0.3",
applicationId: "com.example.lizejun.repogradle",
minSdkVersion: 14,
targetSdkVersion: 23,
versionCode: 1,
versionName: "1.0",
testInstrumentationRunner: "android.support.test.runner.AndroidJUnitRunner"
]
dependencies = [
"support-v4" : 'com.android.support:support-v4:23.2.0',
"support-v7" : 'com.android.support:appcompat-v7:23.2.0'
]
}
複製程式碼
android
用來管理SDK
版本、版本號等,dependencies
用來管理依賴庫的版本,它們都是一個陣列,用逗號來分割,陣列的每個元素都是key:value
的格式。
1.2 在根目錄下的build.gradle
,新增:
apply from: "config.gradle"
複製程式碼
1.3 在根目錄下的各個Module
或者Library
中的build.gradle
檔案中,引用對應的key
:
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
applicationId rootProject.ext.android.applicationId
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
}
}
dependencies {
compile rootProject.ext.dependencies["support-v7"]
}
複製程式碼
二、檢視依賴關係
2.1 工具檢視
依賴樹的檢視可以通過Android Studio
的外掛Gradle View
來檢視:
View -> Tool Windows -> Gradle View
,之後會在最下方生成一個視窗,我們通過這個視窗就可以看到對應專案的依賴關係:
2.2 命令檢視
除此之外,我們也可以使用以下的命令:
./gradlew -q app:dependencies
複製程式碼
同樣可以獲得類似的結果:
注意上圖,如果標記了(*)
,那麼表示這個依賴被忽略了,這是因為其他頂級依賴中也依賴了這個傳遞的依賴,Gradle
會自動分析下載最合適的依賴。
三、識別符號
由於多個頂級依賴當中,可能包含了相同的子依賴,但是它們的版本不同,這時候為了選擇合適的版本,那麼就需要使用一些必要的操作符來管理子依賴。
3.1 Transitive
預設為true
,表示gradle
自動新增子依賴項,形成一個多層樹形結構;設定為false
,則需要手動新增每個依賴項。
3.1.1 統一指定Transitive
configurations.all {
transitive = false
}
dependencies {
compile rootProject.ext.dependencies["support-v7"]
}
複製程式碼
最終得到的結果是,可以看到前面的子依賴項都沒有了:
3.1.2 單獨指定Transitive
dependencies {
compile ('com.android.support:appcompat-v7:23.2.0') {
transitive = false
}
}
複製程式碼
3.2 Force
用來表示強制設定某個模組的版本:
configurations.all {
resolutionStrategy {
force 'com.android.support:support-v4:23.1.0'
}
}
複製程式碼
之後列印,發現其依賴的包版本變成了23.1.0
:
3.3 exclude
該識別符號用來設定不編譯指定的模組
3.3.1 全域性配置某個模組
configurations {
all *.exclude group : 'com.android.support', module: 'support-v4'
}
複製程式碼
此時的依賴關係為:
當然,exclude
後的引數有group
和module
,可以分別單獨使用,會排除所有匹配項。
3.3.2 單獨給某個模組exclude
compile ('com.android.support:appcompat-v7:23.2.0') {
exclude group : 'com.android.support', module: 'support-v4'
}
複製程式碼
也會和上面獲得相同的結果
四、版本衝突
4.1 相同配置下的版本衝突
同一配置下,某個模組的不同版本同時被依賴時,預設使用最新版,Gradle
同步時不會報錯。
五、Gradle
詳解
基本配置:AS
中的Android
專案通常至少包含兩個build.gradle
,一個是Project
範圍的,另一個是Module
範圍的,由於一個Project
可以有多個Module
,所以每個Module
下都會對應一個build.gradle
。
5.1 Project
下的build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "config.gradle"
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
複製程式碼
buildscript
下的repositories
是gradle
指令碼自身需要的資源,allprojects
下的repositories
是專案所有模組需要的資源。
5.2 模組的build.gradle
//宣告外掛,表明這是一個Android程式;如果是庫,那麼應當是com.android.library
apply plugin: 'com.android.application'
//Android構建過程需要配置的引數
android {
//編譯版本
compileSdkVersion rootProject.ext.android.compileSdkVersion
//buildTool版本
buildToolsVersion rootProject.ext.android.buildToolsVersion
//預設配置,同時應用到debug和release版本上
defaultConfig {
applicationId rootProject.ext.android.applicationId
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
}
//配置debug和release版本的一些引數,例如混淆,簽名配置等
buildTypes {
//release版本
release {
minifyEnabled false //是否開啟混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //混淆檔案位置
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile rootProject.ext.dependencies["support-v7"]
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
}
複製程式碼
下面對Android
構建過程中需要配置的引數做一些解釋:
compileSdkVersion
:告訴gradle
用那個Android SDK
的版本編譯你的應用,修改它不會改變執行時的行為,因為它不會被包含進入最終的APK
中;因此,推薦使用最新的SDK
編譯;如果使用Suppport Library
,那麼compileSdkVersion
必須要大於等於它的大版本號。minSdkVersion
:應用最低可執行的要求;它必須要大於等於你所依賴的庫的minSdkVersion
;targetSdkVersion
:Android
提供向前相容的重要依據。(targetSdkVersion is the main way Android provides forward compatibility
) 因為隨著Android
系統的升級,某個api
或者模組的行為有可能發生改變,但是為了保證老APK
的行為和以前相容,只要APK
的targetSdkVersion
不變,那麼即使這個APK
安裝在新的Android
系統上,那麼行為還是保持老的系統上的行為。 系統在呼叫某個api
或者模組的時候,會先檢查呼叫的APK
的targetSdkVersion
,來決定執行什麼行為。
minSdkVersion
和targetSdkVersion
最終會被包含進入最終的APK
檔案中,如果你檢視生成的AndroidManifest.xml
,那麼會發現:
<uses-sdk android:targetSdkVersion="23" android:minSdkVersion="7" />
複製程式碼
所以,我們一般遵循的規則是:
minSdkVersion (lowest possible) <= targetSdkVersion == compileSdkVersion (latest SDK)
複製程式碼
5.3 gradle
相關檔案
gradle.properties
配置檔案,可以定義一些常量供build.gradle
使用,比如可以配置簽名相關資訊,例如keystore
位置、密碼、keyalias
等。settings.gradle
用來配置多模組的,如果你的專案有兩個模組Browser
和ScannerSDK
,那麼就需要:
include ':Browser'
include ':ScannerSDK'
project(':ScannerSDK').projectDir = new File(settingsDir, './ScannerSDK/')
複製程式碼
gradle
資料夾 裡面有兩個檔案,gradle-wrapper.jar
和gradle-wrapper.properties
,後者當中指定了gradle
的版本。
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
複製程式碼
gradlew
和gradlew.bat
分別是Linux
和windows
下的批處理檔案,它們的作用是根據gradle-wrapper.properties
檔案中的distributionUrl
下載對應的gradle
版本,這樣即使環境沒有安裝gradle
也可以編譯。
5.4 gradle
倉庫
gradle
有三種倉庫:maven/ivy/flat本地
。
maven{
url "..."
}
ivy{
url "..."
}
flatDir{
dirs 'xxx'
}
複製程式碼
有些倉庫取了別名:
repositories{
mavenCentral()
jcenter()
mavenLocal()
}
複製程式碼
5.5 gradle
任務
通過以下指令,可以看到支援的任務:
./gradlew tasks
複製程式碼
六、常見問題
6.1 匯入本地Jar
包
匯入單個jar
檔案:
compile files('libs/xxx.jar')
複製程式碼
匯入libs
的多個jar
檔案:
compile fileTree(dir: 'libs', include: ['*.jar'])
複製程式碼
6.2 匯入maven
庫
compile 'groupId:artifactId:version'
複製程式碼
6.3 匯入Project
在匯入之前,需要在settings.gradle
中把模組包含進來,例如前面的ScannerSDK
模組:
compile project(':ScannerSDK')
複製程式碼
6.4 宣告第三方maven
庫
如果專案中需要的一些庫檔案不再中央倉庫中,而是在某個特定地址裡,那麼就需要在Project
中的build.gradle
中的allprojects
結點下或者直接配到某個模組中:
allprojects {
repositories {
maven {
url '地址'
}
}
}
複製程式碼
6.5 依賴第三方aar
compile 'com.aaa.xxx:core:1.0.1@aar'
複製程式碼
6.6 將庫匯出為aar
首先,你的專案必須是一個庫專案,之後在build.gradle
中進行配置:
apply plugin : 'com.android.library'
複製程式碼
之後,進入到該專案中,執行gradle
命令:
./gradlew assembleRelease
複製程式碼
生成的aar
放在/build/output/aar
檔案當中
6.7 引用本地aar
首先,將aar
檔案拷貝到對應目錄下,然後在該模組的build.gradle
中宣告flat
倉庫:
repositories{
flatDir{
dirs '以build.gradle為根目錄的相對路徑'
}
}
複製程式碼
之後,在dependencies
結點下依賴該aar
模組:
dependencies{
compile (name:'xxx',ext:'aar')
}
複製程式碼
七、多版本打包
在此之前,我們先了解幾個基本的概念:
buildTypes
:構建型別,Android Studio
的Gradle
元件預設提供了debug
和release
兩個預設配置,這裡主要用於是否需要混淆,是否除錯。productFlavors
:產品渠道,在實際釋出中,根據不同渠道,可能需要使用不同的包名,甚至是不同的程式碼。buildVaiants
:每個buildTypes
和productFlavors
組成一個buildvariant
。
以上我們討論的buildTypes
和productFlavors
可以通過每個Module
中的build.gradle
的android
標籤來配置。
下面,我們先看一下不同的productFlavors
,分別用來支援讀取不同的檔案和替換不同的字串。
7.1 引用不同的程式碼
我們首先在app/src
目錄下新建兩個目錄,分別對應兩個Flavor
,再在其中建立相同名字的檔案Constant.java
,對裡面的某個常量賦予不同的值。
constantFlavor1
:
package com.example.lizejun.repogradle;
public class Constant {
public static final String NAME = "flavor1";
}
複製程式碼
constantFlavor2
:
package com.example.lizejun.repogradle;
public class Constant {
public static final String NAME = "flavor2";
}
複製程式碼
我們的app
下的build.gradle
中的android
標籤下新增如下幾行程式碼,讓兩個Flavor
分別引用不同的Constant
檔案:
sourceSets {
constantFlavor1 {
java.srcDirs = ['src/constantFlavor1', 'src/constantFlavor1/java', 'src/constantFlavor1/java/']
}
constantFlavor2 {
java.srcDirs = ['src/constantFlavor2', 'src/constantFlavor2/java', 'src/constantFlavor2/java/']
}
}
productFlavors {
constantFlavor1 {}
constantFlavor2 {}
}
複製程式碼
之後我們進行打包,可以得到以下不同安裝包,這兩個apk
如果在其中引用的了NAME
,那麼它會得到不同的值:
7.2 自定義buildConfig
類
如果我們只需要定義一些簡單的值,那麼我們可以用buildConfig
類:
productFlavors {
constantFlavor1 {
buildConfigField "boolean", "BOOLEAN_VALUE", "true"
}
constantFlavor2 {
buildConfigField "boolean", "BOOLEAN_VALUE", "false"
}
}
複製程式碼
7.3 佔位符
productFlavors {
constantFlavor1 {
buildConfigField "boolean", "BOOLEAN_VALUE", "true"
manifestPlaceholders = [label:"constantFlavor1"]
}
constantFlavor2 {
buildConfigField "boolean", "BOOLEAN_VALUE", "false"
manifestPlaceholders = [label:"constantFlavor2"]
}
}
複製程式碼
之後,我們再在AndroidManifest.xml
中引用它:
android:label="${label}"
複製程式碼
7.4 簽名配置
首先是在android
標籤下,我們使用signingConfigs
來配置不同的簽名型別
signingConfigs {
eng {
keyAlias 'androiddebugkey'
keyPassword 'android'
storeFile file('debug.keystore')
storePassword 'android'
}
prd {
keyAlias 'androiddebugkey'
keyPassword 'android'
storeFile file('debug.keystore')
storePassword 'android'
}
}
複製程式碼
之後,再在buildTypes
的各個分支中引用對應的簽名配置:
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.eng
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.prd
}
}
複製程式碼
7.5 依賴
有時候,我們需要在不同的buildTypes
下,引用不同的依賴,例如記憶體洩露的檢測工具,我們希望在debug
版本時檢查記憶體洩露,並在發生時在桌面上生成圖示,但是在release
版本上我們並不希望這麼做,這時候我們可以這麼寫:
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
複製程式碼
這樣,release
版本就不會在桌面生成記憶體洩露的圖示。
更多文章,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:www.jianshu.com/p/fd82d1899…
- 個人主頁:lizejun.cn
- 個人知識總結目錄:lizejun.cn/categories/