使用Gradle构建Android程序

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

环境要求

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

开始(改造Eclipse项目)

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

独立项目构建

在我的另一篇博客Gradle插件用户指南(译)中,3.1节可以看到,
一个最简单的build.gradle文件是这样的:


 
 
  1. buildscript {
  2. repositories {
  3. jcenter()
  4. }
  5. dependencies {
  6. classpath 'com.android.tools.build:gradle:1.1.0'
  7. }
  8. }
  9. apply plugin: 'com.android.application'
  10. android {
  11. compileSdkVersion 19
  12. buildToolsVersion "22.0.1"
  13. }

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


 
 
  1. project-root
  2. |-src
  3. |-main
  4. |-java
  5. |-res
  6. |-drawable
  7. |-layout
  8. |-values
  9. |-AndroidManifest.xml

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


 
 
  1. buildscript {
  2. repositories {
  3. jcenter()
  4. }
  5.  
  6. dependencies {
  7. classpath 'com.android.tools.build:gradle:1.1.0'
  8. }
  9. }
  10.  
  11. apply plugin: 'com.android.application'
  12.  
  13. android {
  14. compileSdkVersion 19
  15. buildToolsVersion "22.0.1"
  16.  
  17. sourceSets {
  18. main{
  19. manifest.srcFile 'AndroidManifest.xml'
  20.  
  21. java.srcDirs = ['src']
  22. aidl.srcDirs = ['src']
  23. renderscript.srcDirs = ['src']
  24.  
  25. res.srcDirs = ['res']
  26.  
  27. assets.srcDirs = ['assets']
  28.  
  29. jniLibs.srcDirs = ['libs']
  30.  
  31. }
  32. }
  33.  
  34. dependencies {
  35. compile fileTree(dir:'libs', include:['*.jar'])
  36. }
  37. }

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

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

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

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


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

多项目构建

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

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


 
 
  1. root
  2. |-main-project
  3. |-library-project1
  4. |-library-project2

并且,依赖关系如下:


 
 
  1. main-project -> library-project1
  2. library-project1 -> library-project2

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


 
 
  1. settings.gradle
  2. build.gradle
  3. main-project/build.gradle
  4. library-project1/build.gradle
  5. library-project2/build.gradle

文件位置是这样:


 
 
  1. root
  2. |-main-project
  3. |- ...
  4. |-build.gradle
  5. |-library-project1
  6. |- ...
  7. |-build.gradle
  8. |-library-project2
  9. |- ...
  10. |-build.gradle
  11. |-build.gradle
  12. |-settings.gradle

文件内容如下:

  • settings.gradle:

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

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


 
 
  1. ':library:library-project1'
  • build.gradle:

    
       
       
    1. buildscript {
    2. repositories {
    3. jcenter()
    4. }
    5. dependencies {
    6. classpath 'com.android.tools.build:gradle:1.0.0'
    7. }
    8. }

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

  • main-project/build.gradle:

    
       
       
    1. apply plugin: 'com.android.application'
    2. android {
    3. compileSdkVersion 19
    4. buildToolsVersion "22.0.1"
    5. sourceSets {
    6. main{
    7. manifest.srcFile 'AndroidManifest.xml'
    8. java.srcDirs = ['src']
    9. aidl.srcDirs = ['src']
    10. renderscript.srcDirs = ['src']
    11. res.srcDirs = ['res']
    12. assets.srcDirs = ['assets']
    13. jniLibs.srcDirs = ['libs']
    14. }
    15. }
    16. dependencies {
    17. compile fileTree(dir:'libs', include:['*.jar'])
    18. compile project(':library-project1')
    19. }
    20. }

这个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,就会生成下面几个文件:


 
 
  1. project-root
  2. |-gradle
  3. |-wrapper
  4. |-gradle-wrapper.jar
  5. |-gradle-wrapper.properties
  6. |-gradlew
  7. |-gradlew.bat

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


 
 
  1. ./gradlew assemble

如果运行时,发现系统没有对应版本的gradle,会通过gradle-wrapper.jar下载gradle-wrapper.properties中指定的gradle版本。这样的话,
任何人获取代码后,不用安装gradle,就可以构建工程

gradle-wrapper.properties文件中指定的版本,就是运行gradle wrapper命令时的gradle版本。
当然,也可以手动指定别的版本,在根目录下build.gradle文件中添加:


 
 
  1. task wrapper(type: Wrapper) {
  2. gradleVersion = '2.3'
  3. }

再运行gradle wrapper

使用Android Studio

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

使用Android Studio 创建 Android 项目

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

新建项目的结构如下:


 
 
  1. project-root
  2. |-app
  3. |-src
  4. |-androidTest
  5. |-main
  6. |-java
  7. |-res
  8. |-AndroidManifest.xml
  9. |-build.gradle
  10. |-gradle
  11. |-wrapper
  12. |-gradle-wrapper.jar
  13. |-gradle-wrapper.properties
  14. |-build.gradle
  15. |-gradle.properties
  16. |-gradlew
  17. |-gradlew.bat
  18. |-local.properties
  19. |-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中。


 
 
  1. File -> Open...
  2. 或者Android Studio启动页的
  3. Open an existing Android Studio project

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

image

如果运行过前面的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标签来区分渠道:


 
 
  1. <meta-data
  2. android:name="UMENG_CHANNEL"
  3. android:value="official" />

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

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

  1. 修改AndroidManifest.xml,添加placeHolder变量

    
       
       
    1. <meta-data
    2. android:name="UMENG_CHANNEL"
    3. android:value="${channel_param}" />
  2. 配置build.gradle文件

    
       
       
    1. android {
    2. ...
    3. defaultConfig {
    4. ...
    5. manifestPlaceholders = [channel_param: "official"]
    6. }
    7. productFlavors {
    8. channel1 {
    9. ...
    10. }
    11. ...
    12. channelN {
    13. ...
    14. }
    15. }
    16. productFlavors.all {
    17. flavor -> flavor.manifestPlaceholders = [channel_param: name]
    18. }
    19. }

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

    
       
       
    1. channel1 {
    2. manifestPlaceholder = [channel_param:name]
    3. }

再进一步,国内的应用商店可以说数以百计,如果每个都在build.gradle文件里写一个flavor,那么build.gradle文件就会变得冗长。
我们把渠道号写到一个单独的文件里channels.txt,内容如下:


 
 
  1. channel-360
  2. channel-baidu

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


 
 
  1. android {
  2. ...
  3. defaultConfig {
  4. ...
  5. manifestPlaceholders = [channel_param: "official"]
  6. }
  7.  
  8. flavors()
  9. }
  10.  
  11. def flavors() {
  12. def path = './channels.txt' //channels.txt的路径
  13. file(path).eachLine {
  14. line ->
  15. if(!line.startsWith("//")) {
  16. //动态创建productFlavor
  17. android.productFlavors.create(line, {
  18. manifestPlaceholders = [channel_param: name]
  19. })
  20.  
  21. }
  22. }
  23. }

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值