oynix

于无声处听惊雷,于无色处见繁花

「巧用Gradle构建Android应用」读书整理

周末看完了「巧用Gradle构建Android应用」,故将新认知整理在此以便以后供自己以及有需要的人查看。

Gradle

  • Gradle构建过程实际上是执行DAG(Directed Acyclic Graph,有向无环图),允许定义自己的task并插入到其中。
    build.gradle中Android块时Android DSL()的入口。

  • 依赖的语法

    1
    2
    3
    4
    5
    6
    7
    //完整语法 (禁用传递依赖)
    testCompile group: 'junit', name: 'junit', version: '4.12'transitive: false
    //排除依赖
    androidTestCompile('org.splckframeword:spock-core:1.0-groovy-2.4') {
    exclude group: 'org.codehaus.groovy'
    exclude group: 'junit'
    }
  • 配置仓库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    repositories {
    maven {
    // 其中的username值和password值可以写在gradle.properties或者在执行gradlew命令时以参数输入
    // ./gradlew -Puser=user_from_pFlag -Ppass=pass_from_pFlag
    username 'username'
    password 'password'
    }
    url 'http://repo.mycompany.com/maven2'
    }
    // 还可以在ext块中配置
    ext {
    if (!project.hasProperty('user')) {
    def username = 'alice'
    }
    if (!project.hasProperty('pass')) {
    def password = 'passpass'
    }
    }
  • 升级Gradle版本

    1
    2
    3
    4
    5
    6
    // 方法一
    task wrapper(type: Wrapper) {
    gradleVersion = 2.12
    }
    ./gradlew wrapper
    // 方法二:直接修改gradle-wrapper.properties文件的distributionUrl属性。
  • 签名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    android {
    // ...other section...
    signingConfigs {
    release {
    keyAlias 'my_alias'
    keyPassword 'password'
    storeFile file('/Users/kousen/keystores/myapp.ketstore')
    storePassword 'password'
    }
    }
    }
    // 同样,密码可以放到gradle.properties中,或者以gradlew的参数输入
  • 构建类型

    1
    2
    3
    4
    5
    6
    7
    buildTypes {
    // 加后缀区分可同时安装在同一设备上
    debug {
    applicationIdSuffix '.debug'
    versionNameSuffix '-debug'
    }
    }
  • 产品定制&维度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    android {
    productFlavors {
    arrogant {
    dimension 'attitude'
    applicationId 'com.oreilly.helloword.arrg'
    }
    friendly {
    dimension 'attitude'
    applicationId 'com.oreilly.helloword.fund'
    }
    stark {
    dimension 'client'
    }
    }
    }
  • 自定义任务。Gradle的DSL API已经存在很多任务,如Copy、Wrapper和Exec等,这些任务可以简单地设置属性然后使用。比如Copy任务所包含的from和into属性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 复制任务
    task copyApks(type: Copy) {
    from("$buildDir/outputs/apk") {
    exclude '**/*unsigned.apk', '**/*unaligned.apk'
    }
    into '../apks'
    }
    // 显示所有可用任务的变种。这个任务中无论在doLast之前还是之后的所有事情都是在配置阶段执行,
    // doLast块中的代码在运行阶段执行
    // applicationVariants属性只针对com.android.application插件有效
    // libraryVariants属性只针对com.android.library插件有效
    task printVariantNames() {
    doLast {
    android.applicationVariants.all { variant ->
    println variant.name
    }
    }
    }
    // 执行安装所有应用的变种的任务
    // dependsOn属性显示这是配置阶段的一部分,而不是运行阶段。每一个变种名字都被首字母大写了
    // 并且相应的安装任务也被添加到installDebugFlavors任务的一个依赖
    task installDebugFlavors() {
    android.applicationVariants.all { v ->
    if (v.name.endWiths('Debug')) {
    String name = v.name.capitalize()
    dependsOn "install$name"
    }
    }
    }
  • 延长ADB超时时长

    1
    2
    3
    4
    5
    6
    // 30秒
    android {
    adbOptions {
    timeOutInMs = 30 * 1000
    }
    }
  • 添加自定义任务到构建过程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 基于assembleDebug的依赖意味着在运行copy任务之前所有调试APK都会被生成。
    task copyApks (type: Copy, dependsOn: assembleDebug) {
    from("$buildDir/outputs/apk") {
    exclude '**/*unsigned.apk', '**/*unsigned.apk'
    }
    into '../apks'
    }
    // 如果想要在每次构建的时候都运行copyApks任务,将其作为build任务的一个依赖
    build.dependsOn copyApks
  • 排除任务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    > ./gradlw build -x lint
    // Gradle运行时,其组装了一个task graph,通过gradle获得这个图的引用,所有对这个图的操纵都需要发生
    // 在其构建出来之后,所以需要使用whenReady属性
    gradle.taskGraph.whenReady { graph ->
    if (project.hasProperty('nolint')) {
    graph.allTask.findAll {
    it.name ==~/lint.*/}*.enabled = false
    }
    }
    }
  • 性能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // gradle.properties
    // 守护进程
    org.gradle.daemon=true
    // 按需配置设置
    org.gradle.configureondemand=true
    // 选择JVM设置 Xmx最大内存 Xms初始内存 XX:MaxPermSize永代久空间
    // HeapDumpOnOutOfMemoryError发生时,将堆中情况导出到一个文件中
    org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError

    // 使用dex选项
    dexOptions {
    incremental true
    javaMaxHeapSize '2g'
    jumboMode = true//运载dex文件中出现的大量字符串,可能需要配置ProdGuard
    preDexLibraries = true
    }
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2018/04/7f249ff0114f/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道