Android-Gradle閱讀筆記
Gradle(2012) 是什麼?
類似Ant(2000)和Maven(2004)概念的專案自動化建構工具。
Ant
Apache Ant是一個java庫,主要用來構建Java程式。(C、C++、Java專案、Android專案)
主要功能:描述互相依賴, 提供了一個內建的編譯,安裝,測試和執行任務(target相當於gradle的task)。
Java專案的編譯規則:
ADT
\ADT\adt-bundle-windows-x86_64-20140702\sdk\tools\ant
Build.xml
Maven
第一:ant指令碼是可以直接執行在maven中的。maven和ant最大的差別就是在於maven的編譯以及所有的指令碼都有一個基礎,就是POM(project object model)。這個模型定義了專案的方方面面,然後各式各樣的指令碼在這個模型上工作,而ant完全是自己定義,顯然maven更勝一籌。
第二:Maven對所依賴的包有明確的定義,如使用哪個包,版本是多少,一目瞭然。而ant則通常是簡單的inclde 所有的jar。導致的最終結果就是,你根本無法確定JBoss中的lib下的common-logging 是哪個版本的,唯一的方法就是開啟 META-INF 目錄下MANIFEST.MF。估計JBoss遲早會轉向Maven的。
第三:Maven是基於中央倉庫的編譯,即把編譯所需要的資源放在一箇中央倉庫裡,如jar,tld,pom,等。當編譯的時候,maven會自動在倉庫中找到相應的包,如果本地倉庫沒有,則從設定好的遠端倉庫中下載到本地。這一切都是自動的,而ant需要自己定義了。這個好處導致的結果就是,用maven編譯的專案在釋出的時候只需要釋出原始碼,小得很,而反之,ant的釋出則要把所有的包一起釋出,顯然maven又勝了一籌。
第四:maven有大量的重用指令碼可以利用,如生成網站,生成javadoc,sourcecode reference,等。而ant都需要自己去寫。試試 maven site 的效果。
第五:maven目前不足的地方就是沒有象ant那樣成熟的GUI介面,不過mavengui正在努力中。目前使用maven最好的方法還是命令列,又快又方便。
Gradle
Gradle結合了前兩者的優點,在此基礎之上做了很多改進。
Gradle不用XML,它使用基於Groovy的專門的DSL, Gradle構建指令碼變得比用Ant和Maven寫的要簡潔清晰,功能更強大,可以直接呼叫javase程式碼。
ANT、Gradle都可以單獨安裝,ANT通過命令列+build.xml執行,Gradle通過命令列+build.gradle執行
Gradle Wrapper
Wrapper,是Gradle的下載器,便於在團隊開發過程中統一Gradle構建的版本,這樣大家都可以使用統一的Gradle版本進行構建,避免因為版本不同帶來不必要的問題。
Gradle日誌
日誌級別
級別 | 用於 |
---|---|
ERROR | 錯誤訊息 |
QUIET | 重要訊息 |
WARNING | 警告訊息 |
LIFECYCLE | 進度訊息 |
INFO | 資訊訊息 |
DEBUG | 除錯資訊 |
Gradle命令列
操作 | 命令 |
---|---|
幫助 | gradle –? 或者 gradle –h |
檢視所有可執行的Tasks | gradle tasks |
檢視每個Task描述資訊 | gradle help –task : xxmodule:xxxxtask |
強制重新整理依賴(版本庫的version與snapshot版本變動後需要手動重新整理) | gradle –refresh-dependencies assemble |
補充:SNAPSHOT
Maven中的SNAPSHOT版本(快照版本)
快照版本和正式版本的主要區別在於,本地獲取這些依賴的機制有所不同。依賴正式版本,構建的會先在本次倉庫中查詢是否已經有了這個依賴庫,如果沒有的話才會去遠端倉庫中去拉取,不會拉取修改過已存在的同版本庫。
.
開發的時候,需要SNAPSHOT版本(快照版本),在構建時去檢視是否有同版本修改過的最新包,有則下載。在配置Maven的Repository可以配置查詢的頻率,頻率共有四種,分別是always、daily、interval、never。
在Gradle,可以設定本地快取的更新策略。
// check for updates every build
resolutionStrategy.cacheChangingModulesFor 0,’seconds’
Task
Groovy閉包≈Action
Groovy是基於JVM虛擬機器的一種動態語言,語法與Java相似,完全相容Java,增加了動態型別和靈活特性(支援閉包、支援DSL)。
閉包、FP函數語言程式設計、lambda表示式
閉包是Groovy的一個非常重要的特性,可以說它是DSL的基礎。
閉包(Closure)
維基百科:
1)閉包是引用了自由變數的函式。
2)由函式與其相關的引用環境組合而成的實體。
「函式」和「函式內部能訪問到的變數」(也叫環境)的總和,就是一個閉包。
在一些語言中,在函式中可以(巢狀)定義另一個函式時,如果內部的函式引用了外部的函式的變數,則可能產生閉包。執行時,一旦外部的 函式被執行,一個閉包就形成了,閉包中包含了內部函式的程式碼,以及所需外部函式中的變數的引用。其中所引用的變數稱作上值(upvalue)。
閉包的作用
閉包常常用來「間接訪問一個變數」。換句話說,「隱藏一個變數」。
Groovy中的閉包(Closures):
閉包在groovy中是一個處於程式碼上下文中的開放的,匿名程式碼塊。它可以訪問到其外部的變數或方法。
閉包也是物件
閉包在groovy中是groovy.lang.Closure類的例項,這使得閉包可以賦值給變數或欄位。
Groovy中的委託策略(略)
lambda表示式
——java1.8支援了lambda表示式
lambda表示式與閉包的關係: |
---|
lambda表示式大量用到了閉包和函式回撥 |
lambda表示式說到底只是一個函式表示式的表現形式而已 |
準確的說lambda表示式與閉包沒有直接的聯絡 |
如果支援函式表示式而不支援閉包,相當於買櫝還珠 |
函式程式設計
函式風格的程式設計特點: |
---|
1.第一等公民是函式 |
2.帶有閉包的Lambdas/Anonymous函式 |
3.不變性,大部分無態處理,沒有狀態和變數 |
4.高併發 |
5.無副作用的呼叫 |
6.通過tail call實現遞迴的效能優化。 |
7.模式匹配(Haskell, Erlang) |
8.懶賦值(Miranda, Haskell) |
9.Homoiconicity(類似LISP) |
SQL是非常類似FP,它能滲透到業務中,它使用一致的資料結構(資料表結構Schema),一些基本函式能組合成很多查詢語句,它是declarative宣告式的, 也就是說,寫出的SQL是告訴資料庫我需要什麼,資料庫就為你返回,而不必指定資料庫如何具體去查詢。
Haskell 是純函數語言程式設計語言,研究函數語言程式設計必修之路
Gradle groovy解讀
Gradle Android 配置集錦
android {
// SourceSet——原始碼集合——源集
sourceSets{
release{
// java 指定程式碼檔案
// res 指定資原始檔
// java.srcDirs = xxxx
// res.srcDirs = yyyy
}
debug{
}
}
compileSdkVersion 23 // 配置SDK的API Level,對應的是Android 6.0 SDK
buildToolsVersion '23.0.3' //Android構建工具的版本(是一個工具包,包括appt、dex等工具)
// defaultConfig是預設配置,它是一個ProductFlavor。ProductFlavor允許我們根據不同的情況同時生成多個不同的APK包。
defaultConfig{
// applicationId "com.tongcheng.android" 包名
// minSdkVersion rootProject.ext.minSdkVersion App最低支援的Android作業系統版本
// targetSdkVersion rootProject.ext.targetSdkVersion
// versionCode Integer.valueOf(appVersionCode) App內部版本號,用於版本的升級AA.BB.CC(BB為版本迭代,CC為bug修復版本)
// versionName appVersionName App版本名稱
// multiDexEnabled true 配置BuildType是否啟用自動拆分多個Dex的功能。解決65535問題
// 如果啟動期間需要的任何類未在主 DEX 檔案中提供,那麼您的應用將崩潰並出現錯誤 java.lang.NoClassDefFoundError。
// 如果類在 multiDexKeepFile 或 multiDexKeepProguard 檔案中匹配,則該類會新增至主 DEX 檔案。
// multiDexKeepProguard file("keep_in_main_dex.txt")
// resConfigs "zh-rCN" 只有中文資源
// ndk{
// abiFilters "armeabi"
// }
// signingConfig 配置簽名信息,對生成的App簽名
// proguardFile 配置App ProGuard混淆所使用的ProGuard配置檔案。
}
// buildTypes是一個NamedDomainObjectContainer型別,是一個域物件(與SourceSet一樣)。
buildTypes{
release{
// 配置App ProGuard混淆所使用的ProGuard配置檔案。
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard-im.pro', 'rn-proguard-rules.pro'
// proguardFiles:同事配置多個混淆檔案
// debuggable false 是否生成一個可供除錯的apk
// jniDebuggable false 類上
// minifyEnabled true 是否啟用Proguard混淆
// Android SDK提供了兩個Proguard配置檔案,proguard-android.txt和proguard-android-optimize.txt,一個是沒有優化的,另一個是優化的。
// 構建時,打包前,會檢測所有資源,如果沒有被引用,這些資源就不會被打包到apk包中,不管自己的還是第三方的都會被處理
// shrinkResources true 是否自動清理未使用的資源,預設為false
// zipAlignEnabled true zipalign優化:是一個整理優化APK檔案的工具,客提高系統和應用的執行效率,更快地讀寫apk中的資源,降低記憶體的使用。
// 修改生成的apk檔名
// applicationVariants.all { variant ->
// variant.outputs.each { output ->
// def outputFile = output.outputFile
// if (outputFile != null && outputFile.name.endsWith('.apk')) {
// // 輸出apk名稱為AppName_v1.0_2015-01-15_wandoujia.apk
// def apkFile = "AppName_v${defaultConfig.versionName}_${buildTime()}" +
// "_${variant.productFlavors[0].name}.apk"
// output.outputFile = new File(outputFile.parent, apkFile)
// }
// }
// }
}
debug{
// Debug模式的簽名使用的就是SDK自動生成的debug證書(.andriod/debug.keystore)
}
}
// Android Gradle任務
// assemble、check、build、connectedCheck、deviceCheck、lint、install、uninstall、gigningReport、androidDependencies等任
signingConfigs {
key_config {
// keyAlias '17ukeystore'
// keyPassword '17ukeystore'
// storeFile file('/Users/android/share_root/etongAndroid.keystore')
// storePassword '17ukeystore'
// v2SigningEnabled false
}
debug {
storeFile file('debug.keystore')
}
}
flavorDimensions 'channel','pay'
productFlavors{
google{
// 動態配置AndroidManifest檔案
// 在構建過程中,動態修改AndroidManifest檔案中的內容(友盟統計等)
// 可以使用manifestPlaceholder、Manifest佔位符
manifestPlaceholders.put("UMENG_CHANNEL","google")
// buildConfigField 'String','WEB_URL','"http://www.google.com"'// 自定義BuildConfig屬性
// resValue 'string','channel_tips','google渠道歡迎你' 動態新增自定義的資源
dimension 'channel'
}
baidu{
manifestPlaceholders.put("UMENG_CHANNEL","baidu")
dimension 'channel'
}
free{
dimension 'pay'
}
paid{
dimension 'pay'
}
// 構建產物variant = ProductFlavor x BuildType
// ProductFlavor = 以dimension為分組的乘積
// variant = { FreeGoogleRelease FreeGoogleDebug FreeBaiduRelease FreeBaiduDebug PaidGoogleRlease PaidGoogleDebug PaidBaiduRlease PaidBaiduDebug }
}
dexOptions {
// jumboMode true 解決65535問題
// javaMaxHeapSize "3072M" 配置最大堆記憶體
// preDexLibraries屬性,是否預執行dex Libraries庫工程,開啟後會大大提高增量構建的速度,不過可能會影響clean構建的速度,預設為true,如需要使用dx的—multi-dex選項生成多個dex,導致和庫工程有衝突的時候,需要將該選項設定為false
// threadCount 2 用來配置Gradle執行dx命令時使用的執行緒數量,適當的執行緒數量可以提高dx效率
// incremental 配置是否啟用dx的增量模式(或許有時候不工作)
}
}
def buildTime() {
def date = new Date()
def formattedDate = date.format('yyyy-MM-dd', TimeZone.getTimeZone("UTC"))
return formattedDate
}
使用Gradle配置進行模組化開發
以下所有內容為筆記——均可忽略
Gradle基礎:
xxx | 作用 |
---|---|
Settings檔案 | 主要是為了配置子工程。 |
Build檔案(每個Project都會有一個Build檔案) | 配置版本,接入外掛,依賴庫,依賴的Maven中心庫 |
Task | 是一個操作,一個原子性的操作,比如打個jar包,複製一份檔案,編譯一次Java程式碼,上傳一個jar到Maven中心庫等,和Ant裡的Target,Maven中的goal是一樣的。(所謂task其實是project一個屬性Project.hasProperty(‘xxxTask’) 為 true) |
任務依賴 | dependsOn: xxxxTask |
自定義屬性
Project和Task以及SourceSet都可以新增額外的自定義屬性,通過應用所屬對應的ext屬性即可實現。
新增之後可以通過ext屬性對自定義屬性讀取和設定。
ext.age = 19
ext{
phone = 123423
address = ‘xxx’
}
自定義屬性作用域廣,可以跨Project,跨Task訪問這些自定義屬性。
指令碼即程式碼,程式碼也是指令碼
Gradle檔案中寫指令碼,但是寫的都是程式碼,可以即刻使用Groovy、Java以及Gradle的任何語法和API。可以定義Class、內部類、導包、定義方法、常量、介面、列舉等。
Gradle任務
多種方法訪問任務
一:
task exTask1
exTask1.doLast{
println ‘exTask1.doLast’
}
二:
task exTask2
tasks[‘exTask2’].doLast{
println ‘exTask2.doLast’
}
tasks[‘exTask2’] 其實就是呼叫 tasks.getByName(‘exTask2’) 原始碼是呼叫 findByName(String name) 實現的
也可以通過路徑進行訪問:
findByPath(‘:example:exTask2’)
getByPath(‘:example:exTask2’)
get如果找不到會丟擲UnknownTaskException異常,而find在找不到該任務的時候會返回null
任務的分組和描述
在建立任務的時候,儘量進行分組和描述,便於對任務進行歸類整理,也便於閱讀:
def Task myTask = task exTask3
myTask.group = BasePlugin.BUILD_GROUP
myTask.description = ‘這是一個構建的引導任務’
可以通過gradle tasks檢視任務的分類描述
<<操作符
“<<” 操作符在Gradle的Task上是doLast方法的短標記形式,也就是說”<<”可以代替doLast
任務的執行分析
當我們執行Task的時候,其實就是執行其擁有的actions列表,這個列表儲存在Task物件實力中的actions成員變數中,其型別是一個List
doFirst其實是add在第一個位置,doLast新增在最後一個位置
任務順序
shouldRunAfter和mustRunAfter可以控制任務應該或者一定在某個任務之後執行。
例如:先執行單元測試,才能進行打包
任務的啟用和禁用
Task中有個enabled屬性,用於啟用和禁用任務,預設是true,表啟用;設定為false則禁止改任務執行,輸出會提示該任務被跳過。
任務的onlyif斷言
斷言就是一個條件表示式。Task有個onlyIf方法,接受閉包作為引數,如果返回true則該任務執行,否則跳過。
用途:比如控制哪些情況下打什麼包,什麼時候執行單元測試,什麼情況下執行單元測試的時候不執行網路測試等。
Example:
任務規則
當執行、依賴一個不存在的任務時,Gradle會執行失敗。可以使用規則對其進行改進,當執行、依賴不存在的任務時,不會執行失敗,而是列印提示資訊,提示改任務不存在:
Gradle外掛
Gradle本身提供了基本的概念和整體核心的框架,其他用於描述真實使用場景邏輯的都以外掛擴充套件的方式來實現,比如構建Java應用,就是通過Java外掛來實現的。
外掛的作用:個人理解就是編譯過程中,能用程式程式碼做的任何事情(程式碼生成、庫拉取、編譯修改、程式碼目錄指定、擴充套件屬性等等)
應用外掛
二進位制外掛:就是實現了org.gralde.api.Plugin介面的外掛
apply plugin:’java’
上面語句把Java外掛應用到我們的專案中了,其中’java’是Java外掛的plugin id,他是唯一的。
也可以:
apply plugin:org.gradle.api.plugins.JavaPlugin
也可以:
apply plugin:JavaPlugin
二進位制外掛一半都是被打爆在一個jar裡獨立釋出的。我們自定義的外掛,釋出的時候制定plugin id最好是一個全限定名稱,就像包名,避免重複。
指令碼外掛
build.gradle
apply from:’version.gradle’
其實就是把指令碼載入進來,和二進位制外掛不同的使用from關鍵字,後面緊跟一個指令碼檔案,可以是本地的,也可以是網路的,如果是網路上的話要使用HTTP UR。
應用第三方釋出的外掛
第三方釋出的jar的二進位制外掛,應用的時候,必須要現在buildscript{}裡面配置classpath才能使用。
比如Andriod Gradle外掛,就屬於Andrid釋出的第三方外掛,如果要使用就要進行配置:
buildScript{}塊是一個在構建專案前,為專案進行前期準備和初始化相關配置以來的地方,配置好所需的以來,就可以應用外掛了:
apply plugin:’com.android.application’
使用plugins DSL應用外掛
Gradle2.1以上版本才可以用,如果該外掛已經被託管在https://plugins.gradle.org/網站上,我們就不用在buidscript裡配置classpath以來了,直接使用plugins就可以應用外掛:
更多好用的外掛:
自定義外掛
指令碼外掛
Groovy工程外掛(二進位制外掛)
Gradle外掛基礎
sourceSets原始碼目錄
第三方依賴:
倉庫配置:
Repositories{
mavenCentral()
}
庫依賴
專案依賴
Jar依賴
如何構建Java專案
build任務:編譯原始碼,處理資原始檔等等
clean任務:刪除build目錄以及其他構建生成的檔案。
assemble任務:不會執行單元測試,只會編譯和打包
check任務:只會執行單元測試,有時候還會做一些質量檢查
原始碼集合SourceSet概念
SourceSet——原始碼集合——源集
有了源集,我們能針對不同的業務和應用進行原始碼分組
釋出構建
將程式碼釋出到庫中
Andriod Gradle外掛
Android其實就是Gradle的一個第三方外掛,由Google的Android團隊開發的。
Andriod Gradle外掛分類
App外掛id:com.android.applicaton
Library外掛id:com.android.library
Test外掛id: com.android.test
Android Gradle外掛
Android Gradle外掛是第三方外掛,託管在Jcenter上,應用之前,需要先配置classpath
compileSdkVersion
compileSdkVersion 23 配置SDK的API Level,對應的是Android 6.0 SDK
方法的括號可以省略,分號可以省略,所以就是上面的寫法。
buildToolsVersion
buildToolsVersion ’23.0.1’:Android構建工具的版本(是一個工具包,包括appt、dex等工具)
defaultConfig
defaultConfig是預設配置,它是一個ProductFlavor。ProductFlavor允許我們根據不同的情況同時生成多個不同的APK包。
buildTypes
buildTypes是一個NamedDomainObjectContainer型別,是一個域物件(與SourceSet一樣)。
buildTypes裡面有release、debug等,也可以新增N多自定義型別。
Android Gradle任務
assemble、check、build、connectedCheck、deviceCheck、lint、install、uninstall、gigningReport、androidDependencies等任務
從Eclipse遷移到Android Gradle工程
1. 直接使用Android Studio匯入
2. Eclipse>Export>Generate Gradle Build Files(生成Setting和build指令碼)>Android Studio>Import Project (這種方式保持了Eclipse原本的專案格式,只是重寫了SourceSet)
自定義Android Gradle工程
defaultConfig 是一個ProductFlavor,如果ProductFlavor沒有被特殊定的話,預設會使用defaultConfig{}塊值指定的配置(包名、版本號、版本名稱等)
applicationId:包名
minSdkVersion:App最低支援的Android作業系統版本
versionCode:App內部版本號,用於版本的升級AA.BB.CC(BB為版本迭代,CC為bug修復版本)
versionName:App版本名稱
testApplicationId:用於配置測試App的包名,預設情況下是applicationId + “.test”,預設即可
testInstrumentationRunner:配置單元測試時使用的Runner,預設是android.testInstrumenttationTestRunner,如果要自定義Runner,修改即可。
signingConfig:配置簽名信息,對生成的App簽名
proguardFile:配置App ProGuard混淆所使用的ProGuard配置檔案。
proguardFiles:同事配置多個混淆檔案
配置簽名信息
Debug模式的簽名使用的就是SDK自動生成的debug證書(.andriod/debug.keystore)
構建的應用型別
applicationIdSuffix:用於配置基於預設applicationId的字尾
debuggable:是否生成一個可供除錯的apk
jniDebuggable:類上
minifyEnable:是否啟用Proguard混淆
multiDexEnabled:配置BuildType是否啟用自動拆分多個Dex的功能。解決65535問題
shrinkResources:是否自動清理未使用的資源,預設為false
混淆:
Android SDK提供了兩個Proguard配置檔案,proguard-android.txt和proguard-android-optimize.txt,一個是沒有優化的,另一個是優化的。
zipalign優化:是一個整理優化APK檔案的工具,客提高系統和應用的執行效率,更快地讀寫apk中的資源,降低記憶體的使用。
zipAlignEnabled true 即可
Gradle高階定義
使用共享庫:com.google.android.maps、android.test.runner等,是獨立庫,並不會被系統自動連線,需要獨立進行生成使用。
如果手機系統沒有需要的共享庫,將不能安裝該應用。
Android中,除了標準的SDK,還存在兩種庫:一種是add-ons庫,位於add-ons目錄下,大部分是第三方廠家或者公司開發的,為了讓開發者使用,但是又不想暴露具體標準實現;第二類是optional可選庫,位於platforms/android-xx/optional目錄下,一般是為了相容舊版本的API(org.apache.http.legacy 相容 HttpClient)
add-ons附件庫,Andriod Gradle會自動解析,自動新增到classpath裡。
Optional可選庫就不會了,使用需要:
批量修改生成的apk檔名
applicationVariants(僅僅適用於Android應用Gradle外掛)、libraryVariants(僅適用於Andriod庫Gradle外掛)、testVariants(以上兩種Gradle外掛都使用)
這三個元素直譯過來意思是變體,通俗地講他們就是Android構建的產物。
觸發這3種集合都會觸發建立所有任務。
動態生成版本資訊
版本:major.minor.path,第一個是主版本號,第二個是副版本號,第三個是補丁號
分模組:
從git的tag中獲取
tag的名字一般就是版本名稱,可以動態獲取tag名稱作為應用的名稱。
Git命令: git describe –abbrev=0 –tags
使用Gradle的exec,Project物件裡的exec方法
git tag動態獲取版本名稱
從屬性檔案中動態獲取和遞增
使用Properties屬性,gradle進行讀寫。
隱藏簽名檔案資訊
簽名信息存放到伺服器。
自動打包伺服器程式碼:
如果是Jenkins,只需要在Jenkins裡配置即可。
開發者直接使用debug簽名即可
如果有時候需要使用正式釋出的簽名打正式包,比如Jenkins,給每個開發者開放一個賬號,他們自己新建個Job就可以打正式的包了,打包之後可以在生成的構建裡下載。
動態配置AndroidManifest檔案
在構建過程中,動態修改AndroidManifest檔案中的內容(友盟統計等)
可以使用manifestPlaceholder、Manifest佔位符
ManifestPlaceholders是ProductFlavor的一個屬性
還可以直接:
還可以使用佔位符動態修改動態配置meta資訊,比如ContentProvider的auth授權。
自定義BuildConfig
注意:值是用單引號括起來的,value的值是什麼就寫什麼,要原封不動的放在單引號裡。
動態新增自定義的資源
資源還可以在Gradle中定義:
實現這一功能的是resValue方法,他在BuildType和ProductFlavor這兩個物件中都存在,也就是說我們可以分別針對不同渠道,或者不同的構建型別來自定義其特有的資源。
生成的資源位置,以Baidu為例,debug模式下,在build/generated/res/resValues/baidu/debug/values/generated.xml這個檔案中。
個人總結:包括圖片一樣可以做,自定義圖片名稱即可,可以通過名稱找圖片。
Java編譯選項
可以對Java原始檔的編碼、原始檔使用的JDK版本進行調優修改。(比如編碼UTF-8,配置Java原始碼的級別為1.6),Gradle提供了便捷入口:
Adb操作選項配置
DEX選項配置
對於生成DEX檔案的過程和處理,Android Gradle外掛會呼叫SDk中的dx命令進行處理。
有時會遇到記憶體不足的情況:java.lang.OutOfMemoryError:GC overhead limit exceeded
預設情況給dx分配的記憶體是一個G,1024MB
javaMaxHeapSize 配置最大堆記憶體
jumboMode屬性,解決65535問題
preDexLibraries屬性,是否預執行dex Libraries庫工程,開啟後會大大提高增量構建的速度,不過可能會影響clean構建的速度,預設為true,如需要使用dx的—multi-dex選項生成多個dex,導致和庫工程有衝突的時候,需要將該選項設定為false
threadCount屬性,用來配置Gradle執行dx命令時使用的執行緒數量,適當的執行緒數量可以提高dx效率
incremental 配置是否啟用dx的增量模式(或許有時候不工作)
突破65535方法限制
Facebook給的第一個方案是:打補丁
後來官方給的方案是Multidex,Android 5.0之後的ART執行方式,天然支援App有多個DEX檔案。ART在安裝App的時候執行預編譯,把多個DEX檔案合併成一個oat檔案執行。對於5.0之前的版本,虛擬機器限制沒個App只能有一個class.dex,要使用他們,需要使用Andriod提供的Multidex庫:
Andriod Build Tools 和 Android Support Repository 到21.1,這是支援Multidex功能的最低支援版本。
要在我們的專案中使用Multidex,首先要修改Gradle build配置檔案,啟用Multidex,並同時配置Multidex需要的jar依賴:
開啟了Multidex,會讓我們的方法多於65535個的時候生成多個DEX檔案,其名字為classes.dex,classes(…n).dex這樣的格式。要想可執行,虛擬機器需要把其他幾個生成的classed記載進來,必須在App啟程啟動的入口控制,就是Application。直接使用MultiDexApplication或者繼承它,或者重寫attachBaseContext方法實現:
思考:
自動清理未使用的資源
Android Lint、Recource Shrinking(構建時,打包前,會檢測所有資源,如果沒有被引用,這些資源就不會被打包到apk包中,不管自己的還是第三方的都會被處理)
Resource Shrinking要集合Code Shrinking一起使用,就是ProGuard,也就是啟用minifyEnabled。
自動清理未使用的資源可能會誤刪,因為我們再程式碼編寫的時候,可能會使用反射引用資原始檔,特別是第三方庫會這麼做,Gradle就區分不出來了,這種情況Gradle提供了keep方法來讓我們配置哪些資源不被清理:res/raw/keep.xml
Keep.xml 有一個屬性是tools:shrinkMode,用於配置自動清理資源的模式,預設是safe,是安全的,可以識別如下引用:
如果把清理模式改成strict就沒辦法識別了,這個資源會被認為沒有被引用,而被清除掉。
resConfig使用非常廣泛,不止於上面描述的語言,還包括Api Level、解析度等。
上述姿勢在打包的時候,不打包到apk中,實際並沒有刪除工程中的資源。
Android Gradle多專案構建
settings.gradle配置檔案
庫專案引用和配置
引用庫專案其實是庫專案釋出出來的aar包,預設情況下,Android庫專案發出來的包都是release版本的,當然可以通過配置來改變它,比如改成預設釋出的,下面是debug版本:
還可以針對不同的flavor+buildtype配置:
同時釋出多個版本的aar包以供不同專案引用:
引用方法:
庫專案單獨釋出
搭建自己的Maven私服,推薦使用Nexus Repository Manger,版本選擇2.x.x
釋出Mavne:
快照版本SNAPSHOT:
比如配置成1.00-SNAPSHOT,這時候會發布到snapshot中心庫,每次釋出版本號不會變化,只會在版本號後按順序號+1,如1.0.0-1、1.0.0-2、1.0.0-3等。這樣的版本號,引用的時候版本號寫成1.0.0-SNAPSHOT即可,Maven會幫我們下載最新(序列最大)的快照版本。這種方式適用於聯調測試的時候,每次修復好測試的問題就釋出一個快照版本,知道沒有問題為止,然後再放出release版本,正式釋出。
釋出配置:
使用自己Maven伺服器候中的庫:
可以使用一個Maven庫代替:Nexus Maven提供了一種group型別的repository,這種型別的repository可以同時整合好幾個repository,把他們同意當成一個group來對外發布,比如Nexus內建的public group,就包含了release和snapshot,就可以改成:
Android Gradle多渠道構建
Android Gradle的Flavor完美解決多渠道問題。
Android Gradle中,定義了個Build Variant的概念,直譯是構建變體,可以理解為構建的產物。一個Build Variant=Build Type + Product Flavor,Build Type就是我們構建的型別,比如Baidu、Google等,它們加起來就是baiduRelease、baiduDebug、googleRelease、googleDebug這幾種組合的構建產出. Product Flavor是多渠道構建的基礎.
Flurry多渠道和友盟多渠道構建
Flurry只需要配置不同的Flurry Key即可,可以自定義BildConfig:
使用: Flurry.init(this,FLURRY_KEY);
而友盟需要修改AndriodManifest.xml中的配置,通過配置meta-data標籤來設定:
則我們可以使用manifestPlaceholders,來進行替換。
多渠道構建定製
Flavor:氣味、味道,就是我們點菜說的口味。
applicationId:是ProductFlavor的屬性,用於設定改渠道的包名
consumerProguardFiles:混淆檔案配置
當釋出庫專案生成一個aar包的時候,使用consumerProguardFiles配置的混淆檔案列表也會被打包到aar裡一起釋出,當應用專案引用這個aar包,並且啟用混淆的時候,會自動使用aar包裡的混淆檔案對aar包程式碼進行混淆,這樣就不用對該aar包進行混淆配置了。
ConsumerPoguardFiles方法是一直新增的,不會清空以前的混淆檔案,而consumerProguardFiles屬性配置的方式是每次都是新的混淆檔案列表,以前配置的會先被清空。
proguardFiles:混淆使用的檔案配置
signingConfig:簽名配置
testApplicationId:單元測試有自己的專門apk測試包,testApplicationId是用來適配測試包的包名,使用方法與applicationId一樣。
一般的testApplicatonId的值為App的包名+.test
testFunctionalTest和testHandleProfiling
testFunctionalTest表示是否為功能測試,testHandleProfiling表示是否啟用分析功能。
他們主要用來控制測試包生成的AndroidManifest.xml,最終配置還要體現在AndroidManifest.xml檔案中的instrumentation標籤的配置上。
TestInstrumentationRunner、testInstrumentationRunnerArguments:測試相關(最終使用的都是adb shell am instrument這個命令),略
versionCode和versionName
渠道的版本號 和 版本名稱
useJack
用於標記是否啟用Jack和Jill這個全新的、高效能的編譯器。
書上說目前還處於實驗階段,有些特性還不支援,比如註解、JDK8的特性等。
正式產品中還是不要使用。
dimension
針對不同渠道需要再細分給出的解決方案。
Dimension是productFlavor的一個屬性,接受一個字串,作為該productFlavor的維度。
需要現在flavorDimesions裡面宣告維度,才能在ProductFlavor中使用:
提高多渠道構建的效率
美團研究出了一個辦法,利用了在apk的META-INF目錄下新增檔案不用重新簽名的原理:
1. 利用Android Gradle打一個基本包(母包)
2. 然後基於該包複製一個,檔名要能區分出產品、打包時間、版本、渠道等
3. 然後對複製出來的apk檔案進行修改,在其META-INF目錄下新增空檔案,但是空檔案的檔名要有意義,必須包含能區分渠道的名字,如mtchannel_google
4. 重複步驟2、3生成我們所需的所有渠道包apk,可以使用Python指令碼來做。
使用:在apk啟動的時候,讀取apk中的META-INF目錄下的字首為matchannel_檔案,如果找到的話,把檔名取出來,然後就可以得到渠道標識了:
持續整合:
Jenkins
怎樣更好地做持續整合
1. 需要一個統一的程式碼版本控制管理庫(可以使用Git進行管理,企業內部,可以使用Gitlab來搭建Git程式碼管理平臺,和Github是非常相似的)
2. 搭建類似於Jenkins的構建平臺,Jenkins是把所有構建流程串起來的一個工具。
3. 單元測試、程式碼覆蓋率,以及程式碼靜態檢查等平臺工具,Android裡我們可以使用jacoco作為程式碼覆蓋率工具,單元測試使用Andriod自帶的工具就可以,靜態程式碼檢查推薦Sonar(可以進行程式碼靜態分析,還可以呈現程式碼覆蓋率和單元測試報告)
4. 每天想程式碼庫的主幹提交程式碼,這樣我們的程式碼修改才可以每天彙集到一起,進行驗證。
5. 程式碼提交的時候,要出觸發一次自動構建,這樣才是持續的,才能早發現合併後的問題。
6. 發現問題要及時修改,每個參與的人都可以很快獲取最近的修改後的程式碼。要做到這些需要每個人都清楚整個程式碼庫的構建情況。
7. 每個開發者必須要自己現在本機測試後才能提交程式碼到主幹,不能不測試直接提交。
8. 開發者必須每天要提交自己的程式碼,更新最新程式碼,要經常和最新的程式碼保持一致,避免長時間沒有同步程式碼,造成不清楚其他開發者做了什麼, 也避免了衝突。
9. 要保證每次構建都要通過,是100%通過
10. 要保證每個人構建的目標都是可以釋出的產品,而不是一個測試版的甚至是半成品,這是我們構建的目標
相關推薦
Android-Gradle閱讀筆記
Gradle(2012) 是什麼? 類似Ant(2000)和Maven(2004)概念的專案自動化建構工具。 Ant Apache Ant是一個java庫,主要用來構建Java程式。(C、C++、Java專案、Android專案) 主要功能:描述互相
Gradle閱讀筆記-第二章groovy基礎
Groovy是基於JVM虛擬機器的一種動態語言,支援閉包,支援DSL 字串 在Groovy中,單引號和雙引號都可以定義一個字串常量,但是單引號不能對字串裡的表示式做運算,單引號沒有運算能力 集合 List定義及訪問: task pringList <<
讀書筆記--Android Gradle權威指南(上)
說了 聲明 通過命令 google robot 結構 信息 我只 cati 最近看了一本書《Android Gradle 權威指南》,對於 Gradle 理解又更深了,但不想過段時間就又忘光了,所以打算寫一篇讀書筆記,將書中一些我個人覺得蠻有用的點記錄、總結一下。 前言 首
《Self-Protection of Android Systems from Inter-component Communication Attacks》論文閱讀筆記
前言 本篇部落格是用來記錄自己在閱讀《Self-Protection of Android Systems from Inter-component Communication Attacks》這篇論文期間的閱讀筆記,方便自己日後翻閱檢視,如果對於這篇論文的閱讀有什麼不正確的地方,歡迎大家批評指
《System Service Call-oriented Symbolic Execution of Android Framework with Applications to...》論文閱讀筆記
System Service Call-oriented Symbolic Execution of Android Framework with Applications to Vulnerability Discovery and Exploit Generation 用於Andro
《AppIntent - Analyzing Sensitive Data Transmission in Android for Privacy Leakage Detection》論文閱讀筆記
AppIntent: Analyzing Sensitive Data Transmission in Android for Privacy Leakage Detection APPIntent:分析敏感資料傳播在Android裝置中隱私洩露的檢測 文獻引
android啟動的閱讀筆記
Android的啟動過程,分為 1、Bootloader引導 2、裝載與啟動Linux核心 3、啟動Android系統, 流程上 先是BOOT層bootloader啟動,初始化硬體,是硬體進入一個準備工作的狀態,(此時會有一個暫時的先調通串列埠的程序或者稱之為程式,為了輸出列印啟
《老羅的Android之旅》閱讀筆記——Activity啟動過程
ActivityManagerService啟動Activity的過程大致如下圖所示: 在這個圖中,ActivityManagerService和ActivityStack位於同一個程序中,而ApplicationThread和ActivityThread位於另一個程序
《老羅的Android之旅》閱讀筆記——IPC機制Binder
Android系統Binder機制中的四個元件Client、Server、Service Manager和Binder驅動程式的關係: Service Manager成為Binder守護程序的過程原始碼路徑:frameworks/base/cmds/servicema
《老羅的Android之旅》閱讀筆記——Launcher和Zygote的啟動過程
Launcher啟動過程 系統中的應用程式安裝好了以後, SystemServer元件接下來就通過ActivityManagerService來啟動Home應用程式Launcher了, Launcher在啟動的時候便會通過PackageManagerS
《老羅的Android之旅》閱讀筆記——廣播(Broadcast)機制
使用廣播的兩個步驟: 1. 廣播的接收者需要通過呼叫registerReceiver函式告訴系統,它對什麼樣的廣播有興趣,即指定IntentFilter,並且向系統註冊廣播接收器,即指定BroadcastReceiver 2. 廣播的傳送者通過呼叫sendBroadc
《老羅的Android之旅》閱讀筆記——SurfaceFlinger服務
Android應用程式請求SurfaceFlinger服務渲染自己的UI可以分為三步曲: 首先是建立一個到SurfaceFlinger服務的連線, 接著再通過這個連線來建立一個Surface, 最後請求SurfaceFlinger服務渲染該Surface。 根據Surfa
Android Studio Gradle使用筆記
[張武] Gradle是一個基於Apache Ant和Apache Maven概念的專案自動化建構工具。 —— 百度百科 Android Studio Gradle是android st
kindle閱讀筆記17年3月
好的 對齊 商都 自己 不為 添加 nbsp 國家 唐詩 資治通鑒(1) (司馬光) - 您在位置 #30-31的標註 | 添加於 2017年3月27日星期一 上午12:25:15 夫事未有不生於微而成於著,聖人之慮遠,故能謹其微而治之,眾人之識近,故必待其著而後救之;
jdk源碼閱讀筆記之java集合框架(四)(LinkedList)
ray private array public 源碼閱讀 jdk源碼閱讀 oid color 解釋 關於LinkedList的分析,會從且僅從其添加(add)方法入手。 因為上一篇已經分析過ArrayList,相似的地方就不再敘述,關註點在LinkedList的特點。 屬
vue中$watch源碼閱讀筆記
vue 告訴 應該 最好 notify type 十分 msg 建立 項目中使用了vue,一直在比較computed和$watch的使用場景,今天周末抽時間看了下vue中$watch的源碼部分,也查閱了一些別人的文章,暫時把自己的筆記記錄於此,供以後查閱: 實現一個簡單的
Android:日常學習筆記(7)———探究UI開發(1)
tac calling repl action its 內容 schema lesson try Android:日常學習筆記(7)———探究UI開發(1) 常用控件的使用方法 TextView 說明:TextView是安卓中最為簡單的一個控件,常用來在界面上顯示一段文本信
Android:日常學習筆記(7)———探究UI開發(4)
this 活動 eal enc panel .html http 中間 編寫 Android:日常學習筆記(7)———探究UI開發(4) UI概述 View 和 ViewGrou Android 應用中的所有用戶界面元素都是使用 View 和 ViewGroup 對象
Android:日常學習筆記(9)———探究廣播機制
ora rri enabled cas 管理 encoding protect 其他 acc Android:日常學習筆記(9)———探究廣播機制 引入廣播機制 Andorid廣播機制 廣播是任何應用均可接收的消息。系統將針對系統事件(例如:系統啟動或設備開始充電時)傳
Android:日常學習筆記(10)———使用LitePal操作數據庫
分享 數據 turn find netstat price 彈出 category 模式 Android:日常學習筆記(10)———使用LitePal操作數據庫 引入LitePal 什麽是LitePal LitePal是一款開源的Android數據庫框架,采用了對象關系