从零开始学习SpringBootAndroid架构安卓组件化开发

从零开始Android组件化改造(二) - Gradle的管理

2019-04-30  本文已影响2人  BzCoder

我的Github:https://github.com/BzCoder
欢迎各位留言讨论

Gradle的管理在组件化改造中是一个非常有学问的环节。在我看来Gradle在其中的主要几个职责:

接下来我们就一点一点的讲。

1.引入包的版本管理

这其实不是组件化开发的专利。正如其他的项目一样,统一的版本号我们都管理在Config.gradle中。类似下面的文件。在模块中引入模块时,统一通过类似api rootProject.ext.dependencies["mmkv"]的引入方式来保证版本的统一。这个很好理解,因为都是常规操作。

ext {

    android = [
            applicationId    : "${PACKAGE_NAME}",
            compileSdkVersion: 28,
            buildToolsVersion: "28.0.3",
            minSdkVersion    : 18,
            targetSdkVersion : 28,
            versionCode      : VERSION_CODE as int,
            versionName      : "${VERSION_NAME}"
    ]

    version = [
            androidSupportSdkVersion: "28.0.0",
            retrofitSdkVersion      : "2.4.0",
            dagger2SdkVersion       : "2.19",
    ]

    dependencies = [
            //support
            "appcompat-v7"             : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
            "design"                   : "com.android.support:design:${version["androidSupportSdkVersion"]}",
            "support-v4"               : "com.android.support:support-v4:${version["androidSupportSdkVersion"]}",
            "cardview-v7"              : "com.android.support:cardview-v7:${version["androidSupportSdkVersion"]}",
            "annotations"              : "com.android.support:support-annotations:${version["androidSupportSdkVersion"]}",
            "recyclerview-v7"          : "com.android.support:recyclerview-v7:${version["androidSupportSdkVersion"]}",
            "constraint-layout"        : 'com.android.support.constraint:constraint-layout:1.1.3',
]
  defaultConfig {
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]
        testInstrumentationRunner rootProject.ext.dependencies["androidJUnitRunner"]
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
                includeCompileClasspath true
            }
        }

        multiDexEnabled true
    }

2.组件化编译与总体编译的切换

2.1 App与Lib

我们知道,lib模块需要引入apply plugin: 'com.android.library',应用模块引入apply plugin: 'com.android.application',而在组件化开发中,这两种状态是要不断地切换的,所以我们可以在gradle.properties设定参数isBuildModule来控制。于是gradle的头部就变成了以下

if (isBuildModule.toBoolean()) {
    apply plugin: 'com.android.application'

} else {
    apply plugin: 'com.android.library'
}

当然在实际开发中我们设计了多层,相应的我们也给每层建立了基础gradle,参数也随之变成了isBuildModuleOne,isBuildModuleTwo,isBuildModuleThree...每一层的业务只要依赖该层基础gradle即可。

2.2 两套Manifest

组件化编译和整体编译,他们的清单文件也是不同的。我们通过在Gradle中android节点中加入以下代码来控制工程使用两套Manifest,但是这种方案美中不足的是,你的每个Activity的注册都必须要写两次

 sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
            if (isBuildModule.toBoolean()) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
    }

2.3 不同编译方式时导入不同的包

说到包的导入,我们先必须明确两个关键字的概念。

根据以上原则
在模块互相导入时,我们使用如下格式:

 if (moduleTv.toBoolean()) {
            runtimeOnly project(":moduleTv")
        }

这样写,首先(if语句)可以通过配置文件来确认某个模块是否加入,使用runtimeOnly ,可以在某一个Module组件化编译时,不会影响其他引用它的模块。

在通用模块导入时,我们使用如下格式:
butterknife,dagger2等的包引入。

   if (isBuildModule.toBoolean()) {
        //view
        annotationProcessor(rootProject.ext.dependencies["butterknife-compiler"]) {
            exclude module: 'support-annotations'
        }
        //tools
        annotationProcessor rootProject.ext.dependencies["dagger2-compiler"]
        annotationProcessor rootProject.ext.dependencies["arouter-compiler"]
        //test
        debugImplementation rootProject.ext.dependencies["canary-debug"]
        releaseImplementation rootProject.ext.dependencies["canary-release"]
        testImplementation rootProject.ext.dependencies["canary-release"]
    } else {
        compileOnly rootProject.ext.dependencies["butterknife-compiler"]
        compileOnly rootProject.ext.dependencies["dagger2-compiler"]
        compileOnly rootProject.ext.dependencies["arouter-compiler"]
        compileOnly rootProject.ext.dependencies["canary-debug"]
        compileOnly rootProject.ext.dependencies["canary-release"]
    }

这样写只有在组件化编译的时候,模块才会真正把基础包引入,整体打包时,只有一份。

3.Manifest与gradle.properties的数据桥梁

因为我们目标想把所有的配置文件都整合到gradle.properties中,但是manifest又不能直接调用gradle.properties中的参数,我们就必须借助gradle作为“中间人”。我们在gradle的defaultconfig节点中加入(以下为推送的写法)

 manifestPlaceholders = [
                GETUI_APP_ID    : "${PUSH_APPID}",
                GETUI_APP_KEY   : "${PUSH_APPKEY}",
                GETUI_APP_SECRET: "${PUSH_APPSECRET}"
]

这样一来,在Manifest中就可以取到gradle.properties 的参数了。

总结

Gradle的配置总的来说不是太难,以上方案也存在可以优化的地方,就是Manifest,携程曾经有一篇文件是利用manifest的tools:node ="remove"来进行manifest的合并,但是很可惜,在我自己实践的过程中,遇到了不少困难,最终没有采用携程的方案。好的,那么今天的文章就先暂时写到这里。

上一篇下一篇

猜你喜欢

热点阅读