组件化架构笔记(第三章)

Gradle基础

Gradle的生命周期分为三个不同的阶段:初始化 -》 配置 -》 构建

初始化:settings.gradle

配置:build.gradle

构建:gradle

初始化阶段会读取根目录下setting.gradle的include信息,决定哪些工程会加入构建过程,并且创建project实例。

配置阶段会按引用树去执行所有工程的build.gradle脚本,配置project对象,一个对象由多个任务组成。

运行阶段会根据Gradle命令传递过来的Task名称,执行相关依赖任务。

版本参数优化

每个module的build.gradle文件都拥有一些必要的属性,同一个Android工程中,在不同的模块中要求这些属性一致,如果不一致会造成资源 的重复,另一方面会降低编译效率。那么就必须有一个统一的、基础的gradle配置。

项目依赖统一管理方案

资源引用配置

1 使用sourceSets的方式来指定文件的路径。

sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
}

2 可以动态添加res资源,在buildtype 和productFlavor中定义resValue变量

resValue "string","app_name","xxx"

resValue只能动态添加资源,无法替换资源。如果资源名重复,Gradle会提示重复定义资源。

3可以指定特定尺寸的资源

resConfigs "hdpi","xhdpi","xxhdpi"

4 通过build.gradle编译生成BuildConfig文件,可以直接让代码读取到BuildConfig中的值。

buildConfigField("String","BASE_URL","\"https://xxx.com.cn\"")

在buildConfig文件中就会得到:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 10101;
  public static final String VERSION_NAME = "1.01.01";
  // Fields from build type: debug
  public static final String BASE_URL = "https://xxx.com.cn";
}
Gradle加载的优先级

BuildType -> productFlavor -> Main -> dependencies

最左边的优先级越高

Build types

Gradle在Android中的build type是用来处理app或者library应该被构建成什么类型,在这个配置中,我们可以定义应用的包名是什么,是否自动去除掉没有引用的资源,是否开启混淆等等。

buildTypes {
        release {
            //设置正式包名称
            applicationVariants.all { variant ->
                variant.outputs.all { output ->
                    project.ext { appName = 'xxx' }
                    def newName = project.ext.appName +"-" + defaultConfig.versionName + "-" +buildTime() + ".apk"
                    outputFileName = new File(newName)
                }
            }
            //开启混淆
            minifyEnabled true
            //Zipalign优化
            zipAlignEnabled true
            //移除无用的resource文件
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            
        }
        debug {
            minifyEnabled false
            shrinkResources false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.debug
            applicationVariants.all { variant ->
                variant.outputs.all { output ->
                    project.ext { appName = 'XXX' }
                    def newName = project.ext.appName +"-" + defaultConfig.versionName + "-" +buildTime() + ".apk"
                    outputFileName = new File(newName)
                }
            }
        }
Product flavors

与build type相反,build type用来构建不同类型的app,debug版或release版,而produc flavors则是用来在同一个app上创建不同的版本,如付费版和免费版。一个非常常见的应用场景就是我们创建了一个银行管理的app给不同银行提供服务,但是不同的银行App的logo不一样,有produc flavors就能在基于一套代码上创建不同版本的app或者library。

productFlavors {
           red {
               applicationId 'com.gradleforandroid.red'
               versionCode 3
            }
         blue {
               applicationId 'com.gradleforandroid.blue'
               minSdkVersion 14
               versionCode 4
            }
      }

Multiflavor variants

在某些情况下,我们可能需要进行flavors的组合,比方说你的app有两套主题,绿色主题和红色主题,然后有两个版本,付费版和免费版,你可能需要进行组合,类似于红色免费版,红色付费版,绿色免费版,绿色付费版。通过使用flavorDimensions可以解决flavors组合的问题,

flavorDimensions "color", "price"
       productFlavors {
           red {
               flavorDimension "color"
           }
           blue {
               flavorDimension "color"
          }
         free {
               flavorDimension "price"
           }
            paid {
               flavorDimension "price"
         }
      }

Variant filters

在某些情况下,可能我们不想使用某种build variant,例如现在有debug和release的build type,red和blue的flavors,但是,blue还是测试环境根本现在用不到blue的release版本,那么我们可以直接过滤掉,在android studio中的buildVariants窗口就不会出现了,过滤可以在app模块或者library模块的build.gradle文件中加入如下代码:

android.variantFilter { variant ->
    if (variant.buildType.name.equals('release')) {
        variant.getFlavors().each() { flavor ->
            if (flavor.name.equals('blue')) {
                variant.setIgnore(true);
            }
        }
    }
}   

gradle的依赖特性

1 implementation

会将指定的依赖添加到编译路径,并且会将该依赖打包到输出,如apk中,但是这个依赖在编译时不能暴露给其他模块,例如依赖此模块的其他模块。这种方式指定的依赖在编译时只能在当前模块中访问。

例如:

有两个模块app 和test,模块app依赖test,test添加了远程二进制库依赖joda-time,在test模块中使用没有问题,在app模块中使用则报错。

2 api

使用api配置的依赖会将对应的依赖添加到编译路径,并将依赖打包输出,但是这个依赖是可以传递的,比如模块A依赖模块B,B依赖库C,模块B在编译时能够访问到库C,但是与implemetation不同的是,在模块A中库C也是可以访问的。

3 compileOnly

compileOnly修饰的依赖会添加到编译路径中,但是不会打包到apk中,因此只能在编译时访问,且compileOnly修饰的依赖不会传递

4 runtimeOnly

这个与compileOnly相反,它修饰的依赖不会添加到编译路径中,但是被打包到apk中,运行时使用。

5 annotationProcessor

用于注解处理器的依赖配置,像第三方库 ButterKnife

Gradle的一些配置

开启Gradle的守护进程来构建项目:

org.gradle.daemon=true

如果你要构建一个多Module并且依赖关系比较复杂的项目,那么你可以使用并行项目执行:

org.gradle.parallel=true

在Gradle主目录中配置的属性优先级高于在项目中配置的属性。当你并不想一个个项目的去改动配置时,可以定义一份常用的Gradle配置文件放在Gradle的主目录下

对于内存较小的机器避免Gradle编译卡顿

修改gradle.properties,避免影响其它人编译速度,把修改的gradle.properties文件放到用户文件夹.gradle下

#设置最大堆内存为1.5g和最大非堆内存0.5g
org.gradle.jvmargs=-Xmx1536m -XX\:MaxPermSize\=512m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8
#不启用守护进程
org.gradle.daemon=false
#不启用并行编译
org.gradle.parallel=false
#使用构建缓存
android.enableBuildCache=true

修改build.gradle文件,如下:

dexOptions {
        //最大堆内存
        javaMaxHeapSize "2g" // 1g should be also OK
}
压缩Apk大小
加快Build速度

Gradle的Android插件在 buildType 上有一个名为 minifyEnabled 的布尔属性,我们需要将其设置为true以启用ProGuard:

android {
       buildTypes {
           release {
               minifyEnabled true
               proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
           }
        }
}

压缩Resource文件

自动压缩的方式很简单,就是在构建中配置 shrinkResources 属性。如果将此属性设置为true,Android构建工具将自动检测哪些资源未被使用,并且不会将它们包括在APK中。

android {
   buildTypes {
       release {
               minifyEnabled = true
               shrinkResources = true
        }
   }
}

使用 resConfigs 属性配置要保留的资源,然后其余的将被抛出。

defaultConfig {
           resConfigs "en", "da", "nl"
           resConfigs "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}
忽略Lint检查

当使用Gradle执行构建时,Android构建任务将会对代码执行Lint检查。Lint是一个静态代码分析工具,用于标记布局和Java代码中的潜在错误。在某些情况下,Lint一旦报错,构建就会停止。如果之前没有在项目中使用Lint,并且我们想迁移到Gradle,Lint可能会出现很多错误。为了使构建工作不会因为Lint检查而中断,你可以配置Gradle来忽略Lint错误,并通过禁用 abortOnError 来阻止它们中止构建。这只是一个临时解决方案,因为忽略Lint检查可能会产生像丢失翻译类似这样的潜在错误,这可能会导致应用程序崩溃的问题。为了防止Lint阻塞构建过程,可以像下面这样禁用abortOnError:

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

推荐阅读更多精彩内容