【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值;

相关推荐
7ioik2 小时前
Explain关键字?
android
海盗12342 小时前
MySQL主从复制的配置方式
android·mysql·adb
liang_jy5 小时前
Android 事件分发机制(二)—— 点击事件透传
android·面试·源码
圆号本昊8 小时前
Flutter Android Live2D 2026 实战:模型加载 + 集成渲染 + 显示全流程 + 10 个核心坑( OpenGL )
android·flutter·live2d
冬奇Lab9 小时前
ANR实战分析:一次audioserver死锁引发的系统级故障排查
android·性能优化·debug
冬奇Lab9 小时前
Android车机卡顿案例剖析:从Binder耗尽到单例缺失的深度排查
android·性能优化·debug
ZHANG13HAO10 小时前
调用脚本实现 App 自动升级(无需无感、允许进程中断)
android
圆号本昊10 小时前
【2025最新】Flutter 加载显示 Live2D 角色,实战与踩坑全链路分享
android·flutter
小曹要微笑11 小时前
MySQL的TRIM函数
android·数据库·mysql