[deprecated]gradle the android
TRANSCRIPT
Gradle the Android 入門篇
Cloud
Overview
Gradle基础姿势!
一丁点儿Groovy语法!
Gradle编译Android项⺫⽬目!
Gradle插件开发
Why Gradle?
gradle ≥ ant + maven + makefile!
gradle + Android Studio ≥ Eclipse + ADT + ant + maven + makefile!
Google选择了gradle
Environment Setup
安装gradle > sudo apt-get install gvm> gvm install gradle !
使用gradle-wrapper ${sdk}/tools/templates/gradle/wrapper即拷即用!
额外的groovy> gvm install groovy > groovyConsole
Terminology
Eclipse Gradle Android Studio
workspace settings.gradle project
project build.gradle module
library project module dependency module library
settings.gradle & build.gradle
settings.gradle: 声明工程中所有Module, settings是gradle找到整个工程的入口!
build.gradle: 每一个build.gradle是所在目录Module的入口 当前Module的DSL入口为 project!
settings.gradle同级目录下的build.gradle也是一个模块的入口, 此模块叫做rootProject 所有子模块都可以通过 rootProject 找到此模块
Diff from Ant
Feature Gradle Ant
Maven √ ×
AAR Dependencies √ ×
Variants for multiple-flavors √ ×
NDK support乄#
(Coming soon in AS)√
Basic Sample for Androidbuildscript { repositories { mavenCentral() } ! dependencies { classpath 'com.android.tools.build:gradle:0.11.1' } } !apply plugin: 'com.android.application' !android { compileSdkVersion 19 buildToolsVersion "19.1.0" }
build.gradle { !
repositories { // 定义插件仓库 mavenCentral() mavenLocal() maven { url uri(‘path/to/your/repo’) } }!
dependencies { classpath ‘group:name:version’ classpath group:’yourDependencyGroup’, name:’yourDependencyName’ version: ‘1.1’ classpath ‘com.meizu:MeizuConfigerPlugin:0.13.1’ }!
}
apply plugin: ‘some.plugin’!
apply plugin: ‘eclipse’!
apply plugin: ‘java’!
apply plugin: ‘com.android .application’!
apply from: ‘path/to/your/shared.gradle’
android { /*!
android DSL 的入口!
用于自定义所有android编译相关!
依赖local.properties中定义的SDK路径如sdk.dir=/Users/me/android/sdk
或者ANDROID_HOME环境变量!
*/}
Basic Groovy Grammars
def name = 'Green' def name = "Green" def quote = """First line |Second line \ |, still in second line. """.stripMargin()!
def fullName = "Jim ${name}" // Jim Green !
def CLOUD_HOME = '/Users/me/flyme/meizu/Cloud' def snsPath = "$CLOUD_HOME/MzSnsSyncService"
def greeting = { name-> println "Hello $name" } void greeting(String name){…} greeting "Jack" // 输出Hello Jack!
def greeting = { println "Hello $it" }!
def handleGreeting = { master, greet, guest-> print "$master says: " greet guest } handGreeting 'Jim', greeting, 'Jack'!
Jim says: Hello Jack
doFirst { // do something } doFirst(Closure cl) { closureList.add(cl) }!
compile.doLast { // do something } <-> compile <<< { // do something }<<< 相当于 add last
aStringList <<< 'Foo'aStringList <<< ['Foo', 'Bar']
class Car { String wheel, door, seat void setWheel(String w) {wheel = w} void getDoor() {door} } def car = new Car() car.wheel = "left wheel" <-> car.setWheel("left wheel") println car.door <-> println car.getDoor()
Operator Mehod
a + b a.plus b
a << b a.leftShift b
a++ a.next()
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
+a a.positive()
a == b <-> a.equals(b)or a.compareTo(b)
Project Structure
src/libs/ |- armeabi/*.sores/[代码libs之外全是res]
gen/bin/ AndroidManifest.xml
app/ |- build.gradle |- build/ |- libs/ |- src/ |- main/ : |- res/[drawable*|layout*|values*|menu] : |- java/ : |- res/ : |- AndroidManifest.xml : |- [aidl|assets|jni|rs etc.] |- androidTest/ |- [flavors|buildTypes folders] build/ [gradle/ | gradlew | gradlew.bat][build.gradle | settings.gradle]
Configure the Structure
android.sourceSets.main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] sets.srcDirs = ['assets'] jniLibs.srcDirs = ['libs'] }
tests工程呢?android.sourceSets.androidTest.setRoot('tests')!
等价于android { sourceSets { androidTest.setRoot('tests') androidTest { setRoot 'tests' root = 'tests' } } }!
DSL…
settings.gradle
对于多个module的工程include ':Module1' project(':Module1').projectDir = new File(settingsDir, '../custom/path/module')
settings.gradle中所有include的模块都是子模块, 根模块默认为settings.gradle同级目录build.gradle,
此模块DSL入口叫做rootProject
settings.gradle + build.gradle(rootProject) |- module1/build.gradle(project) |- module2/build.gradle(project) |- custom/path/module3/build.gradle |- ../relative/path/module4/build.gradle |- $workspace/module5/build.gradle!
build.gradle + [settings.gradle] 单独只有⼀一个rootProject可以忽略settings
Default build.gradle
buildscript {//引用仓库, 配置编译classpath }!
android{ compileSdkVersion 19 buildToolsVersion '19.1.0' defaultConfig { versionCode 12 versionName "1.0" minSdkVersion 19 targetSdkVersion 20 applicationId "com.meizu.flyme.cloud" } }!
dependencies { // 定义模块依赖项目 }
Basic Tasks
basic android tasks decription
assemble将一系列编译任务产生的输出#
(outputs)打包成APK
check 检查项⺫⽬目, 主要依赖任务是lint
build assemble+check
clean 清除gradle任务产生的outputs
gradle tasks
Build tasks: assemble*, build, clean!
Verification tasks: *check, lint, test…!
Install tasks: install*, uninstall*!
Help tasks: tasks, projects, help, …!
Build Setup tasks: init, wrapper!
Other tasks: compile**!
Android tasks: androidDependencies, signingReport
Task assemble
assemble* (assembleDebug | assembleRelease) -> preBuild -> compile*Ndk -> prepare*Library -> check*Manifest -> prepare*Dependencies -> compile*Aidl -> compile*Renderscript -> generate*BuildConfig -> generate*Assets-> merge*Assets -> generate*ResValues-> generate*Resources -> merge*Resources-> process*Manifest -> process*Resources -> generate*Sources -> compile*Java -> preDex* -> dex* -> process*JavaRes-> validate*Signing -> package* -> zipalign* -> assemble* done
Tasks outputs
generated intermediates tmp outputs
generated* pre* compile*Java package*
compile* zipalign
check* lint results
merge*
*dex
process*
Gralde Tasks tips & tricks
./gradlew clean assemble check
./gradlew cl assem chec!
./gradlew assembleM75Debug // ?
./gradlew assemMDebu
./graldew aMD
BuildTypesandroid gradle plugin对每个项⺫⽬目都⾃自动设置了两个默认的buildType: debug | release!
android.buildTypes { debug { debuggable true applicationIdSuffix ".debug" // versionNameSuffix minifyEnabled true // runProguard true } jnidebug.initWith(buildTypes.debug) jnidebug { packageNameSuffix ".jnidebug" jniDebuggable true } }
Signing Configurationsandroid { signingConfigs { debug { storeFile file("path/to/debug.keystore") } customConfig { storeFile file("path/to/another.keystore") storePassword "android" keyAlias "customKey" keyPassword "android" } } buildTypes { custom { signingConfig singingConfigs.customConfig } } }
Proguardandroid { buildTypes { release { minifyEnabled true proguardFile getDefaultProguardFile('proguard-android.txt'), my-proguard-rule.txt, another-proguard-rule.pro } } productFlavors { flavor1 { } mx3 { proguardFile mx3-proguard-rules.pro } } }
Flavors
android.sourceSets.main { ... }!
android.productFlavors { flavor1 { versionCode 12 versionName "1.0" minSdkVersion 19 targetSdkVersion 20 applicationId "com.meizu.flyme.cloud" proguardFile "your/path/to/proguard-rules.txt" } }
android.sourceSets.main { ... }!
android.sourceSets.flavor1 { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] sets.srcDirs = ['assets'] jniLibs.srcDirs = ['libs'] }
app/src/ |- main/ : |- res/ : |- java/ : |- res/ : |- AndroidManifest.xml : |- [aidl|assets|jni|rs etc.] |- flavor1/ |- res/ |- java/ |- res/ |- AndroidManifest.xml |- [aidl|assets|jni|rs etc.]
app/ |- build.gradle |- build/ |- libs/ |- src/ |- main/ : |- res/[drawable*|layout*|values*|menu] : |- java/ : |- res/ : |- AndroidManifest.xml : |- [aidl|assets|jni|rs etc.] |- androidTest/ |- [flavors|buildTypes folders] build/ [gradle/ | gradlew | gradlew.bat][build.gradle | settings.gradle]
android.productFlavors { mx3 { } m75 { } }!
Flavor! Debug(buildType)! Release(buildType) MX3! ! ! MX3Debug! ! ! MX3Release MX3! ! ! MX3Debug! ! ! MX3Release M75! ! ! M75Debug! ! ! M75Release M75! ! ! M75Debug! ! ! M75Release!
./gradlew asM7R ?!
./gradlew assembleM75Release
<!-- 高德地图API eng key -->
<meta-data android:name="com.amap.api.v2.apikey" android:value="@string/amap_key" />!
src/MX3/res/values/string.xml <string name="amap_key" translatable="false">1450abc101adb0148004445626ad****</string>!
src/M75/res/values/string.xml <string name="amap_key" translatable="false">635452f594448d8ca0465fed1007****</string>!
buildTypes同样src/debug/res/values/string.xml src/release/res/values/string.xml
-src |-debug |-res |-values |-strings.xml |-main |-res |-values |-strings.xml |-M75 |-res |-values |-strings.xml
flavorGroup: 参⻅见gradle flavor.pdf文档
Build Variants
Variant = flavorGroup* + buildType!
Application Variant | Library Variant Test Variant
Variant -> mx3ArmEngDebug!
优先级: mx3 > arm > eng > debug+defaultConfig!
./gradlew assembleMx3ArmEngDebug
android.applicationVariants.each { variant -> ....}!
def plugin = project.plugins.findPlugin('android') ?: project.plugins.findPlugin('android-library') def variants = plugin.class.name.endsWith('.LibraryPlugin') ? libraryVariants : applicationVariants variants.all { variant -> variant.packageApplication?.doFirst { if (gradleAfter(1.8) ) { def shouldPackageSo = 'true' == project.properties.get('unpackageSo') android.sourceSets.main.jniLibs.srcDirs = shouldPackageSo ? android.sourceSets.main.jniLibs.srcDirs << ['libs'] : [] } } }
New task
task clearJar(type: Delete) { delete 'outputs/shared_sdk.jar' } task makeJar(type: Copy) { from('build/intermediates/bundles/release') into('outputs/') include('classes.jar') rename ('classes.jar', 'shared_sdk.jar') } makeJar.dependsOn(clearJar, build)
pre* generate* … *dex …
assemble*
makeJar
dependsOn
yourTask
yourTask
task <-> tasks.createtask aTask(type: SomeType) {}tasks.create(name: 'aTask', type: SomeType){} task ('aTask', type: SomeType) {}!
task常用type: Copy: org.gradle.api.tasks.Copy Delete: org.gradle.api.tasks.Delete Compile, JavaCompile!
android常用task type: packageApplication
aTask.doFirst { // do something first }!
aTask.doLast { // do something last } aTask<< { // do something last }
Gradle Plugin
TODO
References
Gradle docs chapter 58 to 60!
[Android gradle plugin user guide](http://tools.android.com/tech-docs/new-build-system/user-guide)!
[Gradle custom plugin](http://code4reference.com/2012/08/gradle-custom-plugin-part-1/)
–刘俊
“The End”