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

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
       }
}

你可能感兴趣的:(组件化架构笔记(第三章))