Android组件化架构学习笔记——Gradle优化

Gradle是Android项目开发环境的一部分,Android Studio每次配置编译时都需要使用Gradle。

一.Gradle基础:

Gradle本质上时一个自动构建工具,使用基于Groovy的特定领域语言(DSL)来声明项目设置。使用Groovy最大哦的原因就是Groovy基本语法和Java一样,最大程度适应Java开发。当利用Groovy编写自定义插件时,语法并没有太大差异,仅仅是配置机制需要调整。

Android Studio构建工程时,就是利用Gradle编写的插件来加载工程配置和编译文件。

  • 工程根目录的build.gradle时配置整个工程引用的Gradle文件,能够配置获取Gradle引用仓库的地址。
  • // Top-level build file where you can add configuration options common to all sub-projects/modules.
    
    buildscript {           //构建脚本引用
        repositories {      //插件仓库配置
            google()
            jcenter()       //jcenter本质上是一个maven仓库
            
        }
        dependencies {      //依赖插件
            classpath 'com.android.tools.build:gradle:3.4.1'
            classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
    
        }
    }
    
    allprojects {           //全部项目的配置
        repositories {      //全部项目引用的基础仓库配置
            google()
            jcenter()
            
        }
    }
    
    task clean(type: Delete) {          //声明任务
        delete rootProject.buildDir     //删除主路径buildDir文件
    }
    
    dependencies {              //第三方库的依赖
        compile 'com.alibaba:arouter-api:1.1.0'
        annotationProcessor 'com.alibaba:arouter-compiler:1.1.1'
        compile('com.facebook.fresco:fresco:0.10.0') {
            exclude group:''
        }
    
    
    }
    

根目录的build.gradle文件会影响工程中其他模块的build.gradle文件的引用仓库的路径

  • 当创建出一个新的module时,每个module都会有一个build.gradle文件。
  • apply plugin: 'com.android.application'     //引用编译构建Gradle插件
    
    android {
        compileSdkVersion 28                    //编译的工具对应版本
        buildToolsVersion "29.0.0"              //编译工具对应版本
        defaultConfig {                         //默认配置
            applicationId "com.example.demo1"   
            minSdkVersion 15                    //最低支持版本
            targetSdkVersion 28                 //支持的目标版本
            versionCode 1                       //版本号
            versionName "1.0"                   //版本名
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"      //测试脚本
        }
        buildTypes {                    //构建类型
            release {                   //release版本配置
                minifyEnabled false     //是否打开混淆
                shrinkResources true    //是否打开资源混淆
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'     //混淆文件
                
            }
        }
    
        productFlavors {
            //用户版本
            client {
                manifestPlacehoders = [
                    channel:"10086",     //渠道号
                    verNum:"1",          //版本号
                    app_name:"Gank"      //app名
                ]
            }
    
            //服务版本
            server {
                manifestPlacehoders = [
                        channel:"10087",     //渠道号
                        verNum:"1",          //版本号
                        app_name:"Gank服务版"      //app名
                ]
            }
    
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
        classpath 'com.android.tools.build:gradle:3.1.1'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
        implementation 'com.android.support:localbroadcastmanager:28.0.0'// add plugin
    //    implementation "io.reactivex.rxjava3:rxjava:3.x.y"
    
    
    }

build.gradle的第一行代码重点引用了构建需要用到的Gradle插件工具库。对比编写Java代码,可以认为相当于"import"了一个Java工具库。

每个build.gradle自身是一个Project对象,project.apply()会加载某个工具库到project对象中;

apply plugin:"XXX"的方法会将project对象传递入工具库,然后再通过插件中的Groovy文件来操作project对象的属性,以完善配置初始化信息;

其中android{}和dependencies{}是函数方程式,使用闭包函数的编写方式。其真实调用android{}和dependencies{}方法。方法中会设置project的属性;

每个Project中包含很多Task的构建任务,每个Task中可以包含很多Action动作,每个Action相当于一个代码块,包含很多需要被执行的代码。

  • Gradle对Android工程配置的地方,是主目录中的settings.gradle的文件;
  • 当添加一个module时,Gradle会自动添加一个文件路径到settings.gradle中的include函数中,声明这些文件夹以一个模块的形式存在,将此模块引用到Gradle中进行编译构建。如移除其中一项,对应的文件夹将不会被Gradle插件识别,Android  Studio也不会认为此文件夹为一个module目录;
  • 每个Gradle文件都是一个project对象,Gradle管理这个project的生命周期

Gradle的生命周期settings.gradle(初始化)->build.gradle(配置)->gradle(构建):

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

2.配置阶段会按引用树去执行所有工程的build.gradle脚本,配置project对象,一个对象由多个任务组件。此阶段也会去创建/配置Task及相关信息;

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

二.版本参数优化:

每个module的build.gradle文件都拥有一些必要的属性,同一个Android工程中,在不同模块中要求这些属性一致,如complieSDKVersion/buildToolVersion等。如引用不一致,属性不会被合并引入工程中,这样一方面会造成资源的重复/包量增大,另一方面会降低编译效率。

那就必有一个统一的/基础的Gradle配置,以下有三种方案可选:

第一种方式使用共同参数的方式进行配置:

  • 创建一个common_config.gradle文件;
  • 在common_config.gradle中编写一些简单的变量信息;
  • project.ext {
        complieSdkVersion = 28
        buildToolVersion = "29.0.0"
        minSdkVersion = 15
        targetSdkVersion = 28
        applicationId "com.example.demo1"
    }
    project.ext相当于一个变量类,其中属性可以看作类中的静态变量。
  • 在module的首行build.gradle中添加common_config文件,并通过引用类似引用静态变量的方式来引用属性。
  • apply plugin: 'com.android.library'
    apply plugin: '${rootProject.rootDir}/common_config.gradle'     //引用额外的配置
    android {
        compileSdkVersion project.ext.complieSdkVersion
        buildToolsVersion project.ext.buildToolVersion
    
    
        defaultConfig {
            minSdkVersion project.ext.minSdkVersion
            targetSdkVersion project.ext.targetSdkVersion
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        implementation 'com.android.support:appcompat-v7:28.0.0'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    

第二种方式时使用Android对象配置:

因为apply from引用了common_build.gradle,所以可以引用build.gradle中的Android对象。android{}中提供了android这个变量,可以进一步简化android{}的参数编写来简化代码。在common_build.gradle的project.ext中添加一个闭包方法来指定project对象变量。

  • setDefaultConfig = {
        extension ->        //闭包参数extension相当于android对象
            extension.compileSdkVersion compileSdkVersion
            extension.buildToolsVersion buildToolsVersion
            extension.defaultConfig {
                minSdkVersion minSdkVersion
                targetSdkVersion targetSdkVersion
    
                testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            }
            extension.dataBinging{
                enabled = true
            }
    }

然后在build.gradle中就可以使用setDefaultConfig了,类似属性设置一样,实质上是函数调用。

  • android {
        project.ext.setDefaultConfig android    //调用配置函数
        ....
    }

第三种方式时使用project对象配置:

  • //设置app 设置
    setAppDefaultConfig = {
        extension ->
            extension.apply plugin:'com.android.application'    //引入application插件库
            extension.descriptaion "app"
            setAndroidConfig extension.android
            setDependencies extension.dependencies
    }
    
    //设置Lib配置
    setLibDefaultConfig = {
        extension ->
            extension.apply plugin:'com.android.application'
            extension.descriptaion "lib"
            setAndroidConfig extension.android
            setDependencies extension.dependencies
    }
    
    //设置Android配置
    setAndroidDefaultConfig = {
        extension ->
            extension.compileSdkVersion 28
            extension.buildToolsVersion "29.0.0"
            extension.defaultConfig {
                minSdkVersion 15
                targetSdkVersion 28
    
                testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
                javaCompileOptions {
                    annotationProcessorOptions {
                        arguments = [moduleName:extension.project.getName()]
                    }
                }
            }
            extension.dataBinging{
                enabled = true
            }
    }
    
    //设置依赖
    setDependencies = {
        extension ->
            extension.compile fileTree(dir: 'lib','include',['*.jar'])
            //每个module都需要引用路由apt插件库才能生成相应的代码,这里无须重复编写每个module
            extension.annotationProcessor 'com.alibaba:arouter-compiler:1.1.1'
    }

在build.gradle中只需要传入project对象到闭包函数中即可:

  • //application module配置
    apply plugin: '${rootProject.rootDir}/common_config.gradle'     //引用额外的配置
    project.ext.setAppDefaultConfig project
    
    //library module配置
    apply plugin: '${rootProject.rootDir}/common_config.gradle'     //引用额外的配置
    project.ext.setLibDefaultConfig project

因为组件化会用到application module和library module,所以需要分开编写共性的方法,可以为一些公用的库添加引用。

三.调试优化:

业务模块调试,将单一模块做成app启动,然后用于调试测试。这样保证单独模块可以分离调试。

需要变更的地方:

  • 业务模块是Library module,独立调试需要将模块做成application module才能引入app构建流程。在common_config.gradle中,只需替换对象即可。
  • 每个Application都需要配置ApplicationId

可以使用直接配置属性:

applicationId project.ext.applicationId

也可以在common_config中添加函数配置:

  • setAppDefaultConfig = {
        extension ->
            ...
            extension.android.defaultConfig{
                applicationId applicationId+"."+extension.getName()
            }
            ...
    }

这里extension.getName(),在默认ApplicationId后添加module名字,用于区分不同module产生的单独的app。

  • 在src中建立debug文件夹,同main文件夹目录类似,用于放置需要调试AndroidManifest.xml文件/Java文件/res资源文件。AndroidManifest文件需要设置默认启动activity文件,不给启动activity设置Default属性,否则会导致安装后activity被启动的问题:
  •     <activity android:name=".DebugActivity"
                android:theme="@style/AppTheme">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
  • 在common_config中需要声明单独模块调试变量,如:
  • project.ext{
        ...
        isNewDebug = false
        ...
    }

    在模块build.gradle中变量isNewDebug作为开关:

  •         if(project.ext.isNewDebug){
                project.setLibDefaultConfig project     //设置lib配置
            }else {
                project.setAppDefaultConfig project     //设置app配置
            }
    

    在sourceSets资源配置,配置AndroidManifest的地址及res资源地址,编译构建是Gradle会选取内的资源:

  • sourceSets {
        main{
            if (project.ext.isNewDebug) {
                manifest.srcFile 'src/debug/AndroidManifest.xml'
                res.srcDirs = ['src/debug/res','src/main/res']
            }else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                resources {
                    //排除Java/debug文件夹下的所有文件
                    exclude 'src/debug/*'
                }
            }
        }
    }
  • app module需要移除已经单独调试的模块的依赖:
  • dependencies {
        if(!project.ext.isNewDebug){
            compile project(':news')
        }
    }
    

四.资源引用配置:

Gra​​​​​dle​​有多种引用的方式

  • 使用sourceSets的方式指定文件的路径。sourceSets还可以指定更多的资源设置属性的路径:
  • sourceSets {
        main{
            manifest.srcFile 'src/debug/AndroidManifest.xml'    //指定AndroidManifest
            res.srcDirs = ['src/main/res']                      //指定Java文件路径
            resources.srcDirs = ['src']                          //全部资源文件路径
            aidl.srcDirs = ["src"]                              //指定aidl文件路径
            renderscript.srcDirs = ['src']                      //指定renderscript文件路径
            res.srcDirs = ['src']                               //res资源文件路径
            assets.srcDirs = ['assets']                         //指定资产文件路径
            
        }
    }
  • 可以动态添加res资源,在buildtype和productFlavor中定义resValue:
  • resValue "string","app_name",....
  • 可以指定特定尺寸的资源,也可以在buildType和productFlavor中定义:
  • resConfigs "hdpi","xhdpi","xxhdpi"
  • Gradle加载优先级为BuildType->productFlavor->main->dependencies。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章