【Android】项目的组件化搭建

介绍

模块化和组件化

模块化:

将一个程序按照功能做拆分,分成独立的模块,每个模块只包含和它功能相关的内容;

组件化:
  1. 组件对应单独的功能组件,比如:登录组件,支付组件;
  2. 每个组件都可以单独编译开发,抽出SDK发布;
  3. 一个模块包含了一个或多个组件;

优势:

  1. 减少了编译时间:每个业务功能,可以独立编译运行;
  2. 减少了沟通成本,一定程度上减少了个人开发风格的差异;
  3. 解耦:将一个app分成多个模块,一个模块就是一个组件;
  4. 复用:可以新项目微调/直接使用;

组件分层

  1. 基础组件:
  1. 基础公共模块,最底层的;
  2. 网络请求框架,图片加载框架等主流的第三方库;
  3. SDK;
  1. common组件
  1. 支持业务/功能组件,依赖基础组件;
  2. 业务组件和功能组件只依赖此组件俩获取基础能力;
  1. 功能组件
  1. 依赖基础组件层;
  2. 对一些公用的功能业务进行封装实现;
  1. 业务组件
  1. 依赖基础组件层和一些公用功能组件;
  2. 各组件不通信,得通过路由通信;
  3. 业务组件可以在library和application之间切换,但是最后打包时必须是library ;
  1. 主工程
  1. 依赖各业务组件;
  2. 除了全局的配置和主Activity之外,不包含业务代码,是应用的入口;

组件化项目的搭建

抽离共用的build.gradle版本数据

每个模块独立开发,可能会遇到版本信息不一致,这时我们需要统一管理项目的依赖库;

怎么管理:

  1. 创建config.gradle文件:一些sdk版本,依赖库;
java 复制代码
ext{
    //ext是指额外的属性和变量,整个构建脚本中重复使用和共享;
    isDebug = false;
    android = [
            compileSdkVersion: 33,  //编译app的最低SDK版本
            minSdkVersion    : 32,//运行app的最低SDK版本
            targetSdkVersion : 33,//目标pp的的最低SDK版本
            versionCode      : 1,//指定可以识别该app数字
            versionName      : "1.0"//编指定可以识别该app的字符
    ]
    //每个模块的application地址
    applicationId = {
        //  "app"  : "com.example.dome",
    }
    //常用库的依赖
    library = [
            "appcompat"       : "androidx.appcompat:appcompat:1.6.1",
            "material"        : "com.google.android.material:material:1.5.0",
            "constraintlayout": "androidx.constraintlayout:constraintlayout:2.1.4"
    ]
//第三方库
    libGson = "com.google.code.gson:gson:2.8.6"
    libARouter = "com.alibaba:arouter-api:1.5.2"
    libARouterCompiler = "com.alibaba:arouter-compiler:1.5.2"

}
  1. 让总的build.gradle去apply它;
java 复制代码
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
    alias(libs.plugins.android.library) apply false
}
apply from:"config.gradle"
  1. 以后的版本修改改config.gradle;

创建基础层

  1. 建立一个Module,然后可以放在一个包下统一管理:

  2. 修改该模块下的Build.gradle,主要要和config.gradle搭配使用;

java 复制代码
plugins {
    alias(libs.plugins.android.library)

}
def swy = rootProject.ext
android {
    namespace swy.applicationId.libbase
    compileSdk swy.android.compileSdkVersion

    defaultConfig {
        minSdk swy.android.minSdkVersion

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
}

dependencies {
    api swy.library.appcompat
    api swy.library.material
    api swy.library.constraintlayout

    //等价于
    library.forEach {k,v->implementation v}

    api swy.libGson

    implementation libs.appcompat
    implementation libs.material
    testImplementation libs.junit
    androidTestImplementation libs.ext.junit
    androidTestImplementation libs.espresso.core
}
  1. 要获得项目根目录的引用,得到ext ,使用公用依赖等;
  2. 使用了def , 减少了rootProject.ext的次数,提高性能;
  3. 改动:
  1. 引入rootProject.ext;
  2. 改变命名空间:
    namespace swy.applicationId.libbase
  3. 使用android的[]下的一些版本;
  4. 依赖:添加公用依赖和第三方库依赖;
  1. api的方式引用:a模块导入依赖,b模块通过api 可以导入a导入依赖;

创建组件层

  1. 创建Module: 需要注意的点有:我们需要在我们组件模块的包名前加上module(或者其他的),否则可能包导致冲突;这次我们需要点第一个;使用application插件;
  2. 创建debug模块,移动AM到debug模块中;

打包模式下不需要其他的活动清单,对里面内容改动:

java 复制代码
<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
       >
        <activity
            android:name=".MainActivity"
            android:exported="true">

        </activity>
    </application>

</manifest>

这样做是因为,如果是单独调试,那么需要一个启动页AM, 但是如果是打包的话,合并就会有多个启动页,这个时候就不需要其他的活动清单;

  1. 关于build.gradle的变动:
java 复制代码
if(rootProject.ext.isDebug){
    apply plugin: 'com.android.application'
}
else{
    apply plugin: 'com.android.library'
}
def swy = rootProject.ext
android {
    namespace swy.applicationId.login
    compileSdk swy.android.compileSdkVersion

    defaultConfig {
        if(swy.isDebug){
            applicationId swy.applicationId.login
        }
        minSdk swy.android.minSdkVersion
        targetSdk swy.android.targetSdkVersion
        versionCode swy.android.versionCode
        versionName swy.android.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    sourceSets{
        main{
            if(swy.isDebug){
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            }
            else{
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java{
                    exclude "**/debug/**"
                }
            }
        }
    }
}

dependencies {

    implementation project(':modulesBase:libBase')

    implementation libs.appcompat
    implementation libs.material
    implementation libs.activity
    implementation libs.constraintlayout
    testImplementation libs.junit
    androidTestImplementation libs.ext.junit
    androidTestImplementation libs.espresso.core
}

关于变动想说明以下几点:

  1. 为了达到调试时可以作为单独运行,打包时就会变成一个arr文件配合app使用,这时:
java 复制代码
if(rootProject.ext.isDebug){
    apply plugin: 'com.android.application'
}
else{
    apply plugin: 'com.android.library'
}
  1. 判断是不是出于调试模式,如果是的话, 'com.android.application'
    如果不是apply plugin: 'com.android.library'
  2. applicationId : app运行需要这个标识符来启动login的运行,所以如果是调试模式,我们需要定义;
  3. sourceSets:用于指定安卓项目的源集,用于构建app所需要的项目源代码或者资源等的配置;
  4. Main: sourceSets内的源集;
  5. 条件语句:根据不同模式来决定使用哪一个清单文件;
  6. "/debug/" : **表示匹配任意数量的目录,总的表示移除任何存在debug的路径
  7. 引入基础模块: implementation project(':modulesBase:libBase')

搭建App层

java 复制代码
app的build.gradle:
plugins {
    alias(libs.plugins.android.application)
}
def swy  = rootProject.ext
android {
    namespace swy.applicationId.app
    compileSdk swy.android.compileSdkVersion

    defaultConfig {
        if(swy.isDebug){
            applicationId swy.applicationId.login
        }
        minSdk swy.android.minSdkVersion
        targetSdk swy.android.targetSdkVersion
        versionCode swy.android.versionCode
        versionName swy.android.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        buildConfigField("boolean","isDebug",String.valueOf(isDebug))
    }
buildFeatures{
    buildConfig true
}
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
}

dependencies {


    implementation project(':modulesBase:libBase')
    if(!swy.isDebug){
        implementation project(":modulesCore:login")
    }
    testImplementation libs.junit
    androidTestImplementation libs.ext.junit
    androidTestImplementation libs.espresso.core
}
  1. buildConfigField("boolean","isDebug",String.valueOf(isDebug))
    它可以把gradle数据映射到Java类里面,可以在Java类中使用gradle数据;
java 复制代码
 if(!swy.isDebug){
        implementation project(":modulesCore:login")
    }
  1. 启动 buildConfigField功能
java 复制代码
buildFeatures{
    buildConfig true
}

搭建成果

如果Debug是tue:

如果Debug是false:

改:把所有的swy.isDebug改成isDebug.toBoolean()

在gradle.properties中的;

isDebug = false 修改isDebug值;

相关推荐
xiangpanf2 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx5 小时前
安卓线程相关
android
消失的旧时光-19435 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon6 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon6 小时前
VSYNC 信号完整流程2
android
dalancon6 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013847 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android8 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才8 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶9 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle