Gradle使用的语言是Groovy,所以写build.gradle时可以像正常编程一样按照需要进行编写。

Groovy简单介绍:

//定义变量
def person = [name: '路飞', age: 11, sex: 'male']
//定义函数
def test(x, y){
    println "x=${x}, y=${y}"    //省略了圆括号
    x + y   //最后一行为返回值,相当于return x+y
}

//调用test时候可省略圆括号,建议参数大于一个的时候还是加上的好
def result = test 1, 2
println result

一、gradle文件互相依赖

项目大了之后,build.gradle 可能越来越大,需要做拆分以便更好地管理。比如把所有debugCompile的依赖放入单独的debug.gradle文件。那么在build.gradle里依赖debug.gradle,如下:

apply from: 'debug.gradle'
apply from: 'http://git.showjoy.net/android/mvn-repo/raw/master/library.gradle'

二、剔除重复依赖

很多时候,多个依赖会同时包含一些基础的依赖,比如fastjson、image等模块。比如有多个业务模块module依赖了fastjson,如果都是aar依赖,

compile 'com.alibaba:fastjson:1.1.56.android'

那么gradle构建项目时自动会依赖最新版本的,不会发生重复依赖的问题。 而如果其中有一个改成了源码依赖fastjson,那么可能会出现重复引用的问题,

Duplicate zip entry [classes.jar:com/alibaba/fastjson/JSON.class

那么就需要在有引用fastjson的模块里用exclude剔除它:

compile('com.showjoy.shop:update:1.0.7') {
        exclude group: 'com.alibaba', module: 'alibaba:fastjson'
}

project源码依赖要exclude时,如下:

compile(project(':shopUpdate')) {
        exclude group: 'com.alibaba', module: 'alibaba:fastjson'
}

三、动态替换AndroidManifest.xml里的字符串

比如AndroidManifest.xml有如下定义:

<activity
            android:name="com.showjoy.shop.module.detail.DetailActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" >
                <category android:name="android.intent.category.DEFAULT" >
                <category android:name="android.intent.category.BROWSABLE" >
                <data
                    android:host="page.sh"
                    android:path="/detail"
                    android:scheme="${SCHEME}" >
            </intent-filter>
        </activity>

其中${SCHEME}这样的格式就需要在gradle里替换掉,在build.gradle里配置manifestPlaceholders:

android {
    defaultConfig {
        manifestPlaceholders = [SCHEME: "showjoyshop"]
    }
}

当然可以配置多个变量,

android {
    defaultConfig {
        manifestPlaceholders = [SCHEME: "showjoyshop", UMENG_KEY: "xxxsdsdxxsxssxs"]
    }
}

四、在gradle文件里动态设置额外信息

buildConfigField 用来设置静态变量:
resValue 设置字符串资源,buildConfigField的String记得用斜杠转义

defaultConfig {
    buildConfigField "boolean", "ONLINE", "false"//线下环境
    buildConfigField "String", "SCHEME", "\"showjoyshopdebug\""
    resValue "string", "build_time", "2016.11.17"
}

buildConfigField设置之后,会在BuildConfig.java自动生成静态变量

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.showjoy.shop";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 28;
  public static final String VERSION_NAME = "1.9.0";
  // Fields from build type: debug
  public static final boolean RELEASE = false;
  public static final String SCHEME = "showjoyshopdebug";
}

resValue设置的字符串资源,可以直接在java代码里引用:

context.getString(R.string.build_time) 

五、设置不同的buildtype

通常需要为debug、test、release设置不一样的环境,这时候就可以用到buildtype,设置如下:

android {
    buildTypes {
        debug {
            debuggable true
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'debug_proguard-rules.pro','chat_proguard-rules.pro'
            signingConfig signingConfigs.release
            buildConfigField "boolean", "ONLINE", "false"//线下环境

        }
        forTest {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro','chat_proguard-rules.pro'
            signingConfig signingConfigs.release
            buildConfigField "boolean", "ONLINE", "false"//线下环境
        }
    }
}

可以为不同的buildtype设置不一样的配置,包括混淆,签名,动态变量等等。

在不同的buildType里,为通过变量设置不同的值:
通过buildConfigField和resValue为同一变量设置不一样的值,还可以通过前面讲到的manifestPlaceholders将AndroidManiManifest.xml里的某个特定值替换成不一样的字符串。

另外,不同的buildType可以用不同的依赖:
通常我们直接写compile时,所有buildType都会依赖,而单独为某个buildType依赖一个包时,可以例如写成 debugCompile,如:

compile 'com.showjoy.image:image:1.2.7'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4'
forTestCompile 'com.showjoy.shop:test:1.0.7'
releaseCompile('com.showjoy.shop:chat:1.1.6')

ps:括号可加可不加,需要exclude时,就需要加括号了。

命令行构建时,分别使用以下命令:

gradle assembledebug
gradle assemblerelease
gradle gradle assemblefortest

六、gradle.properties里的全局变量定义

gradle.properties除了配置gradle的一些信息外:

* 配置大内存:
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
* 守护进程
org.gradle.daemon=true
* 并行编译
org.gradle.parallel=true
* 开启缓存:
android.enableBuildCache=true
* 开启孵化模式:
org.gradle.configureondemand=true

还可以配置gradle变量,在各个gradle里引用。比如,分模块后,为了保持各个模块sdk的一致性,就可以在gradle.properties配置sdk的版本号,如下:

systemProp.compileSdkVersion=23
android.useDeprecatedNdk=true
org.gradle.daemon=true
org.gradle.parallel=true
systemProp.buildToolsVersion=23.0.2
systemProp.targetSdkVersion=21
org.gradle.jvmargs=-XX\:MaxPermSize\=4096m
org.gradle.configureondemand=true
systemProp.minSdkVersion=14

然后在gradle文件里使用:

android {
    compileSdkVersion Integer.parseInt(System.properties['compileSdkVersion'])
    buildToolsVersion System.properties['buildToolsVersion']

    defaultConfig {
        minSdkVersion Integer.parseInt(System.properties['minSdkVersion'])
        targetSdkVersion Integer.parseInt(System.properties['targetSdkVersion'])

    }
}

我们也可以在gradle.properties里随意的定义key-value,

STORE_PASSWORD test123
KEY_ALIAS test

然后在build.gradle里直接引用:

signingConfigs {
    release {
        storePassword STORE_PASSWORD
        keyAlias KEY_ALIAS
        keyPassword KEY_PASSWORD
    }
}

或者在gradle.properties里随意的定义变量:

isDebug=false

然后在build.gradle里使用:

isDebug.toBoolean()

七、设置第三方maven仓库

有时依赖第三方库时,可能需要设置第三方的仓库,或者公司拥有自己的仓库,那么就需要增加maven仓库,可以是本地的,也可以是线上的,如下:

allprojects {
    repositories {
        maven {url 'http://192.168.0.62:8081/repository/maven-releases/'}
        maven {url 'http://192.168.0.62:8081/repository/maven-snapshots/'}
        maven {url '/Users/lufei/Library/Android/sdk/extras/google/m2repository/'}
        jcenter()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/Pgyer/mvn_repo_pgyer/master" }
    }
}

八、library的私有混淆

一般library都是需要进行混淆配置的,但让使用者按照要求去修改混淆文件的方式不太友好,consumerProguardFiles可以让library's author在library中定义混淆参数,让混淆配置对使用者屏蔽,如下:

apply plugin: 'com.android.library'

android {
    defaultConfig {
        consumerProguardFiles 'proguard-rules.pro' // 自定义混淆配置
    }
}

打包工具会将*.pro文件打包进入aar中,library混淆时候会自动使用这个混淆配置文件。

以consumerProguardFiles方式加入的混淆具有以下特性:

  • *.pro文件会包含在aar文件中
  • 这些pro配置会在混淆的时候被使用
  • 此配置针对此aar进行混淆配置
  • 此配置只对库文件有效,对应用程序无效

九、指定资源

在gradle里可以配置指定的资源路径,

  • 场景一:项目还是是Eclipse结构,想保留原有目录结构的同时导入到AS开发,可以自己手动配置项目目录结构
  • 场景二*:而且可以为不同的builtype指定不同的资源路径,如下:
android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            assets.srcDirs = ['assets']
        }

        fortest {
            java.srcDirs = ['src/fortest/java']
        }

        release {
            java.srcDirs = ['src/release/java']
        }
    }
}

main里面的路径就是所有的buildtype都是这样的路径,而fortestrelease都是前面定义的buildType的名称,里面的配置只对改buildtype

十、列出所有的依赖关系

为了排查重复依赖问题,可以通过以下命令来列出所有的依赖关系,一看就知道某个模块被多少其他模块依赖了,在主模块的目录下运行:

gradle dependencies > dependencies.txt

该命令将项目的依赖关系写进了dependencies.txt,示例:

+--- com.showjoy.shop:common:1.10.6
|    +--- com.showjoy.scan:scan:1.0.7
|    +--- com.showjoy.view:actionsheet:1.0.3
|    \--- com.showjoy.view:wheel:1.0.2
+--- com.showjoy.shop:select:1.0.1
+--- com.showjoy.shop:viewgroup:1.3.3
|    \--- com.android.support:support-v4:24.0.0 (*)
+--- com.showjoy.shop:account:1.0.10
+--- com.showjoy.shop:special:1.4.0
+--- com.showjoy.shop:update:1.0.7
+--- com.showjoy.shop:main:1.2.8
+--- com.showjoy.shop:weex:1.2.7
……

十一、在手机上同时按照release和debug版本

可以为release和debug设置不一样的applicationId,如下:

android {
    defaultConfig {
        applicationId "com" 
    }

    buildTypes {
        release {
            applicationIdSuffix '.showjoy.shop' 
        }
        debug{
            applicationIdSuffix '.showjoy.shop.debug' 
        }
    }
}

虽然达到了可以同时安装两个app的目的,但是要注意代码中对包名写死的情况,以及跳转协议写死的情况。否则运行的时候或者跳转的时候会有问题。

十二、聚合依赖多个库

有时候一些库是一起依赖的,剔除的时候也要一起,那么就可以这么做:

compile([
      'com.facebook.fresco:fresco:0.12.0'
       // 支持webP图片的静态图,需加入
      'com.facebook.fresco:webpsupport:0.12.0'
    // 支持Gif图片,需加入
      'com.facebook.fresco:animated-gif:0.12.0'
    // 支持webP图片的动态图,需加入
      'com.facebook.fresco:animated-webp:0.12.0'
      'com.squareup.okhttp3:okhttp:3.2.0'
      'com.facebook.fresco:imagepipeline-okhttp3:0.12.0'
])

这样团队里的其他同学就知道哪些library是相关的,在不使用这个library的时候也比较容易都移除。

十三、Gradle插件plugin

Gradle作为框架,它负责定义流程和规则,而具体的编译工作则是通过插件的方式来完成的。插件就是一系列任务的集合,主要作用是把一些重复利用的逻辑打包,这样就可以在不同的项目中可以重复的使用。

比如在主模块的build.gradle里会有apply plugin: 'com.android.application',这就是引用编译Android App的Application插件; 同理,编译Android Library会需要依赖apply plugin: 'com.android.library'

而像这两种从哪获取的呢? 看一下project-lever的build.gradle

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
        classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.5'
    }
}

这里依赖里包含了classpath 'com.android.tools.build:gradle:2.2.3',所以apply plugin: 'com.android.application'时才能找到。然后才可以配置属性:

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
}

这里的插件,开发者都可以进行开发,发布后,在project-lever的build.gradle添加依赖,然后在gradle文件里就可以引用插件,使用插件了。

十四、setting.gradle 配置

可以指定项目路径
include ":weex_sdk"
project(":weex_sdk").projectDir=new File("../sdk")

标签: none

添加新评论