使用Gradle构建Android程序

Android Studio正式版早已经发布了,默认使用Gradle构建,GitHub上80%的Android项目也都是使用Gradle构建的,我们还有什么理由不使用Gradle呢?

环境要求

JDK下载地址

Android SDK下载地址

Gradle下载地址1下载地址2

给一个国内的下载地址:AndroidDevTools

开始(改造Eclipse项目)

eclipse可以直接用adt导出为gradle项目,android studio直接创建gradle项目。但是,我们还是有必要了解下手动改造,这让我们更清楚每个文件的作用。

独立项目构建

在我的另一篇博客Gradle插件用户指南(译)中,3.1节可以看到,

一个最简单的build.gradle文件是这样的:

buildscript{

repositories{

jcenter()

}

dependencies{

classpath'com.android.tools.build:gradle:1.1.0'

}

}

apply plugin:'com.android.application'

android{

compileSdkVersion19

buildToolsVersion"22.0.1"

}

这里,要求项目目录结构是gradle的默认目录:

project-root

|-src

|-main

|-java

|-res

|-drawable

|-layout

|-values

|-AndroidManifest.xml

如果是eclipse下的项目,需要配置下项目目录,修改后的build.gradle文件是这样的:

buildscript{

repositories{

jcenter()

}

dependencies{

classpath'com.android.tools.build:gradle:1.1.0'

}

}

apply plugin:'com.android.application'

android{

compileSdkVersion19

buildToolsVersion"22.0.1"

sourceSets{

main{

manifest.srcFile'AndroidManifest.xml'

java.srcDirs=['src']

aidl.srcDirs=['src']

renderscript.srcDirs=['src']

res.srcDirs=['res']

assets.srcDirs=['assets']

jniLibs.srcDirs=['libs']

}

}

dependencies{

compile fileTree(dir:'libs',include:['*.jar'])

}

}

与前面的build.gradle相比,只增加了sourceSets{...}块,在里面指定了对应的文件目录。

把这个build.gradle拷贝到项目根目录下,就可以使用gradle来构建你的app了。

打开终端/命令行,切换到项目根目录,运行gradle assemble,在main-project/build/outputs/apk下就可以看到生成的apk文件

Note:

要注意原项目的依赖,比如 ApiDemos ,是依赖support-v4的,要添加到dependencies中。

compile'com.android.support:support-v4:19.0.0'

多项目构建

如果程序是由多个子工程构成的话,上面的build.gradle文件就不够用了。

假设你的项目目录是这样的

root

|-main-project

|-library-project1

|-library-project2

并且,依赖关系如下:

main-project->library-project1

library-project1->library-project2

那么,Gradle构建文件应该包含以下几个文件:

settings.gradle

build.gradle

main-project/build.gradle

library-project1/build.gradle

library-project2/build.gradle

文件位置是这样:

root

|-main-project

|-...

|-build.gradle

|-library-project1

|-...

|-build.gradle

|-library-project2

|-...

|-build.gradle

|-build.gradle

|-settings.gradle

文件内容如下:

settings.gradle:

include':main-project','library-project1','library-project2'

settings.gradle声明了程序包含的子项目,如果子项目时包含在三级子目录下,例如root/library/library-project1,那么声明是这样的:

':library:library-project1'

build.gradle:

buildscript{

repositories{

jcenter()

}

dependencies{

classpath'com.android.tools.build:gradle:1.0.0'

}

}

根目录下的buidle.gradle声明了项目的编译环境,指定了Android Gradle插件的版本。和上一个章节,那个单一的build.gradle的前半部分内容是一样的。

main-project/build.gradle:

apply plugin:'com.android.application'

android{

compileSdkVersion19

buildToolsVersion"22.0.1"

sourceSets{

main{

manifest.srcFile'AndroidManifest.xml'

java.srcDirs=['src']

aidl.srcDirs=['src']

renderscript.srcDirs=['src']

res.srcDirs=['res']

assets.srcDirs=['assets']

jniLibs.srcDirs=['libs']

}

}

dependencies{

compile fileTree(dir:'libs',include:['*.jar'])

compile project(':library-project1')

}

}

这个build.gradle的内容与上一章节build.gradle的后半部分基本一致,只是多了一个库项目依赖的声明。

这里假设目录结构和eclipse下的android项目目录结构是一样的,如果实际目录和gradle的默认目录结构一样,可以去掉sourceSets{...}部分

library-project1/build.gradle和main-project/build.gradle基本一致,只有两个地方不一样。

apply plugin: 'com.android.application'改成apply plugin: 'com.android.library'

compile project(':library-project1')改成compile project(':library-project2')

library-project1/build.gradle和library-project2/build.gradle基本一致,只有一个地方不一样。

去掉compile project(':library-project2')

至此,多项目的工程完成了gradle改造,可以在项目根目录下运行gradle assemble进行构建了。

构建的其他细节,请参考我的另一篇博客Gradle插件用户指南(译)

gradle wrapper

和Eclipse导出或者Android Studio创建的项目相比,我们改造完的项目还差了几个文件。

在项目根目录下,运行终端命令gradle wrapper,就会生成下面几个文件:

project-root

|-gradle

|-wrapper

|-gradle-wrapper.jar

|-gradle-wrapper.properties

|-gradlew

|-gradlew.bat

gradlew,gradlew.bat是支持多平台的gradle运行命令,通过gradlew,可以执行gradle构建任务,例如:

./gradlew assemble

如果运行时,发现系统没有对应版本的gradle,会通过gradle-wrapper.jar下载gradle-wrapper.properties中指定的gradle版本。这样的话,

任何人获取代码后,不用安装gradle,就可以构建工程

gradle-wrapper.properties文件中指定的版本,就是运行gradle wrapper命令时的gradle版本。

当然,也可以手动指定别的版本,在根目录下build.gradle文件中添加:

task wrapper(type:Wrapper){

gradleVersion='2.3'

}

再运行gradle wrapper。

使用Android Studio

Android Studio创建的项目默认使用Gradle构建,并且目录结构也是Gradle默认的。

使用Android Studio 创建 Android 项目

这个很简单,新建项目,按照引导一步一步往下走就行了。

新建项目的结构如下:

project-root

|-app

|-src

|-androidTest

|-main

|-java

|-res

|-AndroidManifest.xml

|-build.gradle

|-gradle

|-wrapper

|-gradle-wrapper.jar

|-gradle-wrapper.properties

|-build.gradle

|-gradle.properties

|-gradlew

|-gradlew.bat

|-local.properties

|-settings.gradle

app

是项目代码和资源目录

gradlew,gradlew.bat,gradle/wrapper

上一章节已经介绍过了

build.gradle,settings.gradle

上一章节已经介绍过了

gradle.properties

gradle运行的参数

local.properties

本地环境参数,例如android sdk路径:sdk.dir

导入Gradle项目到Android Studio

对于非Android Studio项目,完成gradle改造后,可以导入到Android Studio中。

File->Open...

或者AndroidStudio启动页的

Openan existingAndroidStudioproject

直接选择打开项目根目录下的settings.gradle(如果没有的话,打开build.gradle)文件,或者setting.gradle文件的父目录,结果如下图:

如果运行过前面的gradle wrapper命令的话(或者是由eclipse导出的gradle项目),目录下有wrapper文件夹,Use default gradle wrapper(recommanded)选项就是可选的,否则只能选择Use local gradle distribution。

混淆与签名

请看我另一篇博客Gradle插件用户指南(译)3.4.3节和3.4.4节

构建多渠道包

动态替换AndroidManifest.xml中的文本

以友盟为例,是通过在AndroidManifest.xml中添加meta-data标签来区分渠道:

android:name="UMENG_CHANNEL"

android:value="official"/>

不同的value值对应不同的渠道。

android gradle plugin从0.13.0版本开始,productFlavor开始支持manifestPlaceHolder,我们使用这个就可以实现友盟的多渠道打包。

修改AndroidManifest.xml,添加placeHolder变量

android:name="UMENG_CHANNEL"

android:value="${channel_param}"/>

配置build.gradle文件

android{

...

defaultConfig{

...

manifestPlaceholders=[channel_param:"official"]

}

productFlavors{

channel1{

...

}

...

channelN{

...

}

}

productFlavors.all{

flavor->flavor.manifestPlaceholders=[channel_param:name]

}

}

productFlavors.all是合并的写法,也可以分开写:

channel1{

manifestPlaceholder=[channel_param:name]

}

再进一步,国内的应用商店可以说数以百计,如果每个都在build.gradle文件里写一个flavor,那么build.gradle文件就会变得冗长。

我们把渠道号写到一个单独的文件里channels.txt,内容如下:

channel-360

channel-baidu

然后在build.gradle里定义函数flavors(),作用就是根据channels.txt里的内容动态创建productFlavor,然后在build.gradle中调用这个函数,优化后的结果是这样:

android{

...

defaultConfig{

...

manifestPlaceholders=[channel_param:"official"]

}

flavors()

}

defflavors(){

defpath='./channels.txt'//channels.txt的路径

file(path).eachLine{

line->

if(!line.startsWith("//")){

//动态创建productFlavor

android.productFlavors.create(line,{

manifestPlaceholders=[channel_param:name]

})

}

}

}

在Android Studio中,点击Sync Project with Gradle Files,就可以在Gradle窗口中看到相应的渠道构建任务了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容