Gradle技巧

Max OX用戶安裝配置gradle:

假設您下載好的 Gradle 文件在 /Users/UFreedom/gradle 目錄

  1. vim ~/.bash_profile
  2. 添加下面內容:export GRADLE_HOME = /Users/UFreedom/gradleexport export PATH=$PATH:$GRADLE_HOME/bin
  3. source ~/.brash_profile

簽名
開發App時經常遇到Release版和Debug版共存問題,由于默認的簽名不同,經常要卸載Debug版安裝Release版,非常麻煩。
有兩種方法可以避免這種情況:

  1. 使用同一個簽名 ;
  2. 使用不同包名

方法1
android {
buildTypes {
debug {signingConfig signingConfigs.myConfig}
release {signingConfig signingConfigs.myConfig}
}
}

方法2

android {
   buildTypes {
       debug {packageNameSuffix ".debug"}
   }
}

引用 aar

要輸出 aar 文件,必須將 Module 配置為 library,在 gradle 文件中如下:

  1. 輸出 aar : apply plugin: 'com.android.library'
  2. 輸出 apk :apply plugin: 'com.android.application'

一份 aar 文件其實就是一份 zip 包,和 jar 不同的是,它將一些資源文件、第三方庫文件、so 文件等等都打包在內,而代碼文件編譯后壓縮在在 classes.jar 中

如 aar的內容


Paste_Image.png

依賴方式1
導入方式,點擊new -module

Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png

把這個文件夾當做一個項目來依賴了

依賴方式2

首先需要將 aar 文件放入引用 Module 的 libs 目錄下,和一般的 jar 文件類似。然后在 gradle 配置文件中把 libs 目錄加入依賴:

repositories {
flatDir {
dirs 'libs'
}

最后
compile(name: 'mylib-debug', ext: 'aar')

依賴即可關聯完畢。構建一下工程,在 Module 的 build/intermediates/exploded-aar
目錄下,可以看到有一些臨時文件生成

aar里面可以直接引用到資源文件,string,drawable等等
且aar里面配置過的權限,直接引用后無需再在主工程里面配置了

buildTypes節點下使用buildConfigField。

下面是默認的buildTypes形式

buildTypes {
    release {
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.release
    }
}

但是這里其實默認還有一個debug type,只不過默認不顯示,顯示完整如下

buildTypes {
  release {
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.release
  }
  debug{
  }
}

默認的構建版本就這么兩種,其實我們還可以構建新的版本

如:

android {
    buildTypes {
        staging {
            applicationIdSuffix ".staging"
            versionNameSuffix "-staging"
            buildConfigField "String", "API_URL","http://staging.example.com/api"
         }
    }
}

我們定義了一個staging版本,該版本定義了一個新的application id,這讓其與debug和release版本的applicationID不同。假設你使用了默認的配置,那么applicationID將會是這樣的:

  1. Debug: com.package
  2. Release: com.package
  3. Staging: com.package.staging

還可以繼承版本,復寫其中的屬性

android {
       buildTypes {
           staging.initWith(buildTypes.debug) //繼承debug構建版本
           staging {
               applicationIdSuffix ".staging"
               versionNameSuffix "-staging"
               debuggable = false
           } 
        }
}

當我們打包編譯項目時,我們能不能這里就可以設置一些參數信息,直接可以作用于項目,從而在項目中,動態根據build.gradle中設置的信息,進行一些代碼層面的邏輯處理,比如在debug type下正常輸出日志信息,但是release type下,屏蔽日志輸出。那么就可以通過buildConfigField

//注意,里面一定要應用簽名
buildTypes { 
  release {
    buildConfigField "boolean", "LOG_DEBUG", "false"
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.release // ===========
  }
  debug{
    buildConfigField "boolean", "LOG_DEBUG", "true"  //=======
  }
}

因為我在項目中使用了開源庫 Logger 進行日志輸出,這個lib可以在Application的onCreate方法中進行開關設置,從而控制Log日志是否顯示在console,所以最終使用如下:

if(BuildConfig.LOG_DEBUG){
    Logger.init("AppPlusLog").setLogLevel(LogLevel.FULL);
}else{
    Logger.init("AppPlusLog").setLogLevel(LogLevel.None);
}

gradle 的多模塊構建

模塊耦合

即你可以在一個模塊中引用其他模塊的屬性,不建議你們這么做,完全可以在根目錄下的build文件中定義這些屬性。

Paste_Image.png

grade圖形化讓你運行模塊間的任務變得簡單,但是其沒有為所有模塊同時運行一個任務,所以如果你希望這么做,最快的方式是使用命令行(注意當前位置 ls下)。

聲明模塊
settings.gradle文件在根目錄(不管主項目app是否依賴某個庫,在項目下面都會被包含進來 )
include ':app', ':mylibrary', ':mylibrary2'

模塊在某個文件夾下面

project
├─── setting.gradle
├─── build.grade
├─── app
│    └─── build.gradle
└─── libraries
     ├─── library1
     │    └─── build.gradle
     └─── library2
          └─── build.gradle

則需要這么定義

include ':app', ':libraries:library1', ':libraries:library2'

app 想依賴某個庫

dependencies { compile project(':libraries:library1')}

gradle 構建生命周期

如果你有多個模塊,settings.gradle文件定義了這些模塊的位置。如果這些子目錄包含了其自己的build.gradle文件,gradle將會運行它們,并且將他們合并到構建任務中。這就解釋了為什么你需要申明在一個模塊中申明的依賴是相對于根目錄(指的是:libraries:library1這種)。

構建任務將所有的模塊聚合在一起的時候.你可以配置所有的模塊在根目錄下的build.gradle。
這讓你能夠簡單的瀏覽到整個項目的配置,但是這將會變得一團亂麻,特別是當你的模塊需要不同的插件的時候。
另外一種方式是將每個模塊的配置分隔開,這一策略保證了每個模塊之間的互不干擾。這也讓你跟蹤構建的改變變得容易,
因為你不需要指出哪個改變導致了哪個模塊出現錯誤等。

gradle的最大策略是混合。你可以在根目錄下定義一個build文件去定義所有模塊相同的熟悉,
然后在每個模塊中的build文件去配置只屬于該模塊的參數。
Android studio遵循了該原則,其創建了一個build.gradle文件在根目錄,
然后再每個模塊文件夾下創建了另外一個build文件。

groovy語法

在Java中,打印一天String應該是這樣的:

System.out.println("Hello, world!");
在Groovy中,你可以這么寫:

println 'Hello, world!'
你應該主要到幾點不同之處:

沒有了System.out
沒有了方括號
列結尾沒有了;

這個例子同樣使用了單引號,你可以使用雙引號或者單引號,但是他們有不同的用法。雙引號可以包含插入語句。插入是計算一個字符串包含placeholders的過程,并將placeholders的值替換,這些placeholder可以是變量甚至是方法。Placeholders必須包含一個方法或者變量,并且其被{}包圍,且其前面有$修飾。如果其只有一個單一的變量,可以只需要$。下面是一些基本的用法:

def name = 'Andy'
def greeting = "Hello, $name!"
def name_size "Your name is ${name.size()} characters long."

greeting應該是“ Hello,Andy”,并且 name_size 為 Your name is 4 characters long.

string的插入可以讓你更好的動態執行代碼。比如

 def method = 'toString'
 new Date()."$method"()

這在Java中看起來很奇怪,但是這在groovy里是合法的。

Classes和members
Groovy里面創建類和Java類似,舉個例子:

class MyGroovyClass {
       String greeting
       String getGreeting() {
           return 'Hello!'
        } 
}

注意到不論是類名還是成員變量都沒有修飾符。其默認的修飾符是類和方法為public,成員變量為private

當你想使用MyGroovyClass,你可以這樣實例化:

def instance = new MyGroovyClass()
instance.setGreeting 'Hello, Groovy!'
instance.getGreeting()   

當你想使用MyGroovyClass,你可以這樣實例化:

def instance = new MyGroovyClass()
instance.setGreeting 'Hello, Groovy!'
instance.getGreeting()   

你可以利用def去創建變量,一旦你為你的類創建了實例,你就可以操作其成員變量了。get/set方法groovy默認為你添加 。你甚至可以覆寫它。

如果你想直接使用一個成員變量,你可以這么干:

 println instance.getGreeting()
 println instance.greeting

而這二種方式都是可行的。

方法
和變量一樣,你不必定義為你的方法定義返回類型。舉個例子

java形式

public int square(int num) {
       return num * num;
} 
square(2);

groovy形式

 def square(def num) {
       num * num
 }
 square 4
 

沒有了返回類型,沒有了入參的定義。def代替了修飾符,方法體內沒有了return關鍵字。然而我還是建議你使用return關鍵字。當你調用該方法時,你不需要括號和分號。

更簡單的寫法

def square = { num ->
       num * num
}
square 8

groovy閉包

在grade中,我們經常使用閉包,例如Android代碼體和dependencies也是。

groovy集合

有二個重要的容器分別是lists和maps。
創建一個list很容易,我們不必初始化:
List list = [1, 2, 3, 4, 5]
為list迭代也很簡單,你可以使用each方法:

list.each() { element ->
       println element
}

你甚至可以使得你的代碼更加簡潔,使用it:

list.each() {
       println it // it是閉包中的概念
}

map和list差不多:

Map pizzaPrices = [margherita:10, pepperoni:12]
如果你想取出map中的元素,可以使用get方法:

pizzaPrices.get('pepperoni')
pizzaPrices['pepperoni']

同樣的groovy有更簡單的方式:

pizzaPrices.pepperoni

Build Variant

android gradle 插件,允許對最終的包以多個維度進行組合。
BuildVariant = BuildType x ProductFlavor

product flavors用來為一個app創建不同版本。典型的例子是,一個app有付費和免費版

buildTypes {
    debug {
    }
    release {
    }
}

productFlavors {
    pro {
    }

    fre {
    }
}
lintOptions {
    abortOnError false
}


這兩個維度的組合,會產生如下包:

proDebug
proRelease
freDebug
proRelease

當你添加了flavor dimensions,你就需要為每個flavor添加flavorDimension,否則會提示錯誤

多個flavors構建變體
在一些例子中,你可能需要創建一些product flavors的合并版本。舉個例子,client A和client B可能都想要一個free和paid的版本,而他們又都是基于一樣的代碼,但是有不一樣的顏色等。創建四個不同的flavors意味著有重復的配置。合并flavors最簡單的做法可能是使用flavor dimensions,就像這樣:

android {
       flavorDimensions "color", "price"
       productFlavors {
           red {
               flavorDimension "color"
           }
           blue {
               flavorDimension "color"
           }
           free {
               flavorDimension "price"
           }
           paid {
               flavorDimension "price"
           }
       }
}

即 2個Color(red blue)*2個Price(free paid)即 4種
redFree redPaid blueFree bluePaid

總的構建是2(Debug release)*4 = 8

blueFreeDebug and blueFreeRelease
bluePaidDebug and bluePaidRelease
redFreeDebug and redFreeRelease
redPaidDebug and redPaidRelease
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,937評論 6 342
  • 轉載注明出處:http://www.lxweimin.com/p/5255b100930e 0. 前言 完全由個人翻...
    王三的貓阿德閱讀 2,554評論 0 4
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,868評論 18 139
  • Gradle配置最佳實踐 本文會不定期更新,推薦watch下項目。如果喜歡請star,如果覺得有紕漏請提交issu...
    Solang閱讀 1,659評論 0 4
  • 有多久了,沒有再抬起頭,靜靜地看一看明燈樓宇之上的那一彎弦月,那是我在夜里常常會做的事。當瞳孔里落滿如同霧靄一...
    黑落白落閱讀 275評論 0 2