栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android组件化设计1 --- Gradle的神奇之处

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android组件化设计1 --- Gradle的神奇之处

Android组件化设计

1 什么是Android组件化?2 Android组件化部署 --- Gradle的用法2.1 Gradle控制测试环境和线上环境问题1:整个app的根是什么?问题2 : 抽取gradle中公共的代码问题3:Gradle配置线上和测试环境问题4:Gradle配置模块是否能够独立运行问题5:如果是线上环境打包,不想打进去测试代码

1 什么是Android组件化?

Android组件化是工程化的思想之一,如果在项目中不区分模块,所有的模块都放在一起,耦合度非常高,每个模块之前无法分离,不具备插拔特性,而且不易于扩展维护

那么组件化的优势在哪?
首先组件化能够使得整个项目的架构更加清晰,各个模块之间是分离的,而且每个模块能够独立运行,每个组件之前可以自由组合,拆分

通过下面这个图,来看一下组件化是什么样的

app作为一个壳,包裹下面所有的业务层组件和基础层组件,而且组件1 组件2 … 他们之间是不能平行通信的,需要通过基础层路由,来完成组件之前的通信,这样就实现了组件之前的相互隔离

2 Android组件化部署 — Gradle的用法

了解什么是组件化之后,这里就会介绍,怎样才能完成组件化的部署

这里说一些常见的场景:

1 通常在一个产品上线之前,需要在测试环境中开发,测试,等到功能完善测试完成之后,完成封板,转为线上环境,这就需要在打包时,来区分测试环境还是线上环境

2 在打包时,我不需要将所有的模块都打包,我只需要测试其中1个模块,那么这就需要每个模块之间都能够独立运行

3 打包发布时,需要把所有的模块都打包,这就是集成化的概念,要求app壳能够独立运行,而且每个模块都需要依附于app壳

2.1 Gradle控制测试环境和线上环境
问题1:整个app的根是什么?

整个app的根就是 setting.gradle

根目录 # settings.gradle

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        jcenter() // Warning: this repository is going to shut down soon
    }
}
//项目的名称  modulelization
//包含app壳,以及2个模块 login register
//还有2个Android library 
rootProject.name = "modulelization"
include ':app'
include ':moudle1'
include ':moudle2'
include ':business'
include ':login'
include ':register'

执行的顺序:从setting.gradle开始,找到根目录的build.gradle,然后再找到app壳的build.gradle

在每个模块的gradle中,输出一句话,build的顺序就是按照在工程中的顺序依次打印出来的

> Configure project :app
组件化

> Configure project :login
组件化 login

> Configure project :moudle1
组件化 moudle 01

> Configure project :moudle2
组件化 moudle 02

> Configure project :register
组件化 register

问题2 : 抽取gradle中公共的代码

在一个项目中,每个模块都存在一个gradle,而且每个gradle中都存在很多相似的代码,尤其是一些版本号,如果需要修改版本号,那么每个gradle都要修改一遍吗?

所以这里就需要把每个模块的相同代码抽取出来,在app的根目录下创建一个gradle(config.gradle),添加一个扩展块ext

ext{
    
    //
    compileSdk 31

    defaultConfig {
        applicationId "com.study.login"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

在gradle中,相似的代码见上文,都是一些key value的形式,那么可以做一个map给放进去

根目录 # config.gradle

//扩展块
ext{

    //建立map存储
    androidId = [
            compileSdk : 31,
            applicationId : "com.study.login",
            minSdk : 21,
            targetSdk : 31,
            versionCode : 1,
            versionName : "1.0",
            testInstrumentationRunner : "android.support.test.runner.AndroidJUnitRunner",
    ]

}

如果想要使用这个扩展,需要放在项目根gradle中引入,才可以使用

根目录 # build.gradle

//引入创建的  config.gradle
apply from : 'config.gradle'

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

这样在每个模块中,都可以使用自定义的map中的值,而且修改时,只需要修改config.gradle中的字段就可以

//优化  提高性能
def config = rootProject.ext.androidId

android {
    compileSdk config.compileSdk

    defaultConfig {
        applicationId "com.study.modulelization"
        minSdk config.minSdk
        targetSdk config.targetSdk
        versionCode config.versionCode
        versionName config.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

除此之外,还有gradle中配置的依赖,如果有300行的依赖需要配置,那么在修改每个库的版本号时,需要逐一修改,这里也可以通过公共抽取配置

app # build.gradle

dependencies {
	
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

config.gradle

dependency = [
        coreKtx : 'androidx.core:core-ktx:1.7.0',
        appcompat : 'androidx.appcompat:appcompat:1.4.1',
        material : 'com.google.android.material:material:1.5.0',
        constraintlayout : 'androidx.constraintlayout:constraintlayout:2.1.3'
]

修改后的 app # build.gradle

dependencies {

    implementation dependency.coreKtx
    implementation dependency.appcompat
    implementation dependency.material
    implementation dependency.constraintlayout
    
    //这种视情况而定
    dependency.each{k,v -> implementation v}

    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

这样设置也没有问题,既然是一个map,那就可以一行代码实现全部的依赖


问题3:Gradle配置线上和测试环境

传统的老办法,在区分线上或者测试环境,都是通过配置不同的URL,通过代码设置线上或者测试环境

class HttpConfig {

    companion object{

        private const val DEBUG = "http://106.108.2.3//test-baidu.com"
        private const val RELEASE = "http://106.108.2.3//baidu.com"
    }
}

那么在Gradle中,如何配置线上或者测试环境的切换

config.gradle # ext

isRelease = false
//线上 测试环境配置
url = [
        DEBUG  : "http://106.108.2.3//test-baidu.com",
        RELEASE: "http://106.108.2.3//baidu.com"
]

app壳 # build.gradle

defaultConfig {
        applicationId "com.study.modulelization"
        minSdk config.minSdk
        targetSdk config.targetSdk
        versionCode config.versionCode
        versionName config.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
		//三个参数
		//字段类型 字段名 字段值
        buildConfigField("Boolean","isRelease","${rootProject.isRelease}")

    }

    buildTypes {

        debug{
            buildConfigField("String","debugUrl",""${rootProject.url.DEBUG} "")
        }

        release {
            buildConfigField("String","releaseUrl",""${rootProject.url.RELEASE}"")
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

如果要在Java中引入Gradle中配置的数据,就需要使用到buildConfigField,其中需要传入三个参数,见注释即可

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.study.modulelization";
  public static final String BUILD_TYPE = "debug";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Field from build type: debug
  public static final String debugUrl = "http://106.108.2.3//test-baidu.com ";
  // Field from default config.
  public static final Boolean isRelease = false;
}

这样在BuildConfig中,就看到了这几个字段,这种就可以把之前用代码写的配置代码删除掉,因为太low了

HttpConfig

companion object{
    val hostUrl:String = if(BuildConfig.isRelease) BuildConfig.debugUrl else BuildConfig.releaseUrl
}

这样在HttpConfig文件中,加这一行即可


问题4:Gradle配置模块是否能够独立运行

在模块的gradle中,存在两个不同的plugins,分别是”com.android.library“ 和 ”com.android.application“,其中library是不能独立运行的,而application是可以独立运行的

Library projects cannot set applicationId. applicationId is set to ‘com.study.register’ in default config.

还有一个区分就是library是不能有applicationId的,而application能够独立运行的是有applicationId的

register # build.gradle

if(isRelease){

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

apply plugin: 'kotlin-android'


println("组件化 register")


android {
    compileSdk 31

    defaultConfig {
        if(!isRelease){
            applicationId "com.study.register"
        }

其中不可独立运行,app壳是能够依赖的,但是如果能够独立运行,app壳是不能依赖的

app壳 # build.gradle

if(rootProject.isRelease){
    //依赖包
    implementation project(path: ':register')
}

问题5:一个模块单独运行,如何区分测试环境和线上环境

app启动展示的界面是通过AndroidManifest来保存界面数据,可以设置首页展示的页面,但是为了能够区分测试环境和线上环境,不能通过下面这种方式来判断

那么通过gradle来判断测试或者线上环境,来分配不同的清单文件AndroidManifest就可以完成线上或者测试的区分

register # build.gradle

 sourceSets{

   main{
        if(rootProject.isRelease){

            manifest.srcFile 'src/main/AndroidManifest.xml'
        }else{

            manifest.srcFile 'src/main/debug/AndroidManifest.xml'
        }
    }
}

在register中创建两个Manifest文件区分一下,通过sourceSets用来设置文件的存放位置,如果是测试环境,就从测试debug文件夹下拿AndroidManifest文件


问题5:如果是线上环境打包,不想打进去测试代码

当上线打包后,因为测试代码会增大包体积,那么在线上环境的时候,需要把debug目录下的代码全部屏蔽掉

sourceSets{

    main{
        if(rootProject.isRelease){

            manifest.srcFile 'src/main/AndroidManifest.xml'
            //屏蔽测试代码
            java {
                exclude("**/debug/**")
            }
        }else{

            manifest.srcFile 'src/main/debug/AndroidManifest.xml'

        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/716646.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号