1为什么采用组件化开发

理由很简单, 提高团队开发速度.特别是业务模块繁琐的项目,主要体现在一下几点

  1. 解耦
  2. 每个功能模块都可单独运行, 开发期,只编译一个模块即可(这是组件独有的亮点)
  3. 有利于单元测试
  4. 代码迭代便捷
举个栗子

android 组件化打包原理 android组件化开发_集成模式


上图是常见的普通项目的架构,主工程依赖各业务模块, 各业务模块都依赖相同的支持库,例如日志库,工具类库等,当A业务改一行代码, 编译看效果时,要都编译,这样效率相当慢. 当然有人会选择单元测试,当然为了一行代码单独写个单元测试有点没必要,如果还设计其他模块可能会更复杂 如下图

android 组件化打包原理 android组件化开发_android 组件化打包原理_02

上图单一工程模型下的业务关系,总的来说就是:你中有我,我中有你,相互依赖,无法分离。
然而随着产品的迭代,业务越来越复杂,随之带来的是项目结构复杂度的极度增加,此时我们会面临如下几个问题:

1、实际业务变化非常快,但是单一工程的业务模块耦合度太高,牵一发而动全身;
2、对工程所做的任何修改都必须要编译整个工程;
3、功能测试和系统测试每次都要进行;
4、团队协同开发存在较多的冲突.不得不花费更多的时间去沟通和协调,并且在开发过程中,任何一位成员没办法专注于自己的功能点,影响开发效率;
5、不能灵活的对业务模块进行配置和组装;

为了满足各个业务模块的迭代而彼此不受影响,更好的解决上面这种让人头疼的依赖关系,就需要整改App的架构。

2 组件化的介绍

android 组件化打包原理 android组件化开发_集成模式_03


业务组件之间是相互独立的,但是又都被APP壳工程依赖,这样app壳工程可以调用组件,当时有个问题,组件之间怎么通信呢??? 这个问题就要交给路由协议了,(例如: ActivityRouter, ARouter)

很详细我就不介绍了 文末参考文章都写的很详细,直接撸代码

开始实践

1)组件模式和集成模式的转换
  1. 首先介绍项目 今天我们新建一个app 壳工程 和 两个逻辑模块 main(即主工程,但是他只负责用户登录等相关操作) 和keepAlive(保活工程) , app壳文件依赖这两个组件工程, 如下图

android 组件化打包原理 android组件化开发_集成模式_04


2.在项目的根目录中生成一个文件 gradle.properties加入 一个变量isModule

# 每次更改“isModule”的值后,需要点击 "Sync Project" 按钮
# true  是组件模块,说明是单独的App
# false 是集成模式,说明是依赖Lib
isModule=false
  1. 在逻辑模块的 build.gradle 中加入如下配置
if (isModule.toBoolean()) {
    apply plugin: com.android.application
} else {
    apply plugin: com.android.library
}
  1. 同步下项目 此时项目还没有任何变化
  2. 把isModule 的值改成 true 然后同步项目,这时候项目就傻眼了,壳项目找不库, 两个组件虽然变成了独立的应用,但是不能直接运行,会报错,
  3. 解决壳文件出错, 在文件的依赖里添加如下判断代码, 然后同步, 此时壳文件没有问题了
if (isModule.toBoolean()) {
    // 可以写一下基类库
    } else {
        implementation project(path: ':module_main')
        implementation project(path: ':module_keepAlive')
    }
  1. 两个组件不能运行 因为表单文件不完整, 为了后期合并时不影响整体项目,所以 在main下创建一个module文件夹,并创建 AndroidManifest.xml 可以按照壳文件 添加完整 主要是application 标签, package 名就不要改了
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.zhf.keepalive">

    <application
        android:name=".debug.App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
    </application>

</manifest>

android 组件化打包原理 android组件化开发_集成模式_05


8. 在组件的build.gradle 文件的 android 标签里填加如下判断代码

sourceSets {
        main {
            if (isModule.toBoolean()) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                //集成开发模式下排除debug文件夹中的所有Java文件
                java {
                    exclude 'debug/**'
                }
            }
        }
    }
  1. 非完美CV工程师会发现 在集成模式时 有这么一个配置 exclude ‘debug/**’,
  2. 在 项目包名下创建 debug文件夹 主意这里面的文件只有在组件模式下才会运行,配置在第8步中已经添加
  3. 在debug文件夹下创建一个activity , 记得在module目录下的配置文件注册并设置为入口页面,如下
<activity android:name=".debug.SplashActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
其实到了这里你的两个功能模块就可以单独运行了,如果到这里没有问题那就在模块工程里(非debug文件下 )创建一些页面吧

android 组件化打包原理 android组件化开发_xml_06


我项目中 splashActivty 只有是组件模式时才会调用, keepMainActiviyty 则什么模式下都可以调用,

2) 模块路由配置

上图中我们说了 keepMainActiviyty 什么模式下都能调用, 我们知道在集成模式下 很简单,写个intent 就可以开启了,但是在集成模式下(合并成一个完整项目)怎么办呢,这事就要引入 路由框架了 这里以 ARouter为例

  1. 现在我们再创建一个库 lib_common 所有组件都依赖他,是所有组件基础库
  2. 只在lib_common库 中引入下面依赖
api 'com.alibaba:arouter-api:1.5.0'
  1. 在app壳 .main库 和keepAlive库 中引入下面依赖
annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
implementation project(path: ':lib_common')
  1. 在所有组件build.gradle在android 标签里添加如下
javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
     compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
  1. 配置完成 接下来就开始使用, 我有个需求 想跨组件跳转到module_keepAlive 组件中的 keepMainActivity 页面 要在这个activity上面加上 @Route 注释 其中path 的值 必须是两级目录, 也就是要有两个 反斜杠 这是 " 亀腚 "
@Route(path = "/keepalive/KeepMainActivity")
public class KeepMainActivity extends BaseActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}
  1. 在要跳转的地方直接调用如下代码就可以了 , 加try catch 是怕蹦沙卡拉卡
try {
                ARouter.getInstance().build("/keepalive/KeepMainActivity").navigation();
            } catch (Exception e) {
                e.printStackTrace();
            }
别忘了在项目的两个AndroidManifest.xml 表单文件中都注册 上activity ,debug 文件夹下的除外,这样合成完成项目时, 表单文件也会合并,最好不要出现重名和资源冲突问题.
别忘了把 isModule 的值改成 false 并同步项目, 到此基本完成了组件化项目
3 全局的 application 说明
  1. 在lib_commom 创建一个 BaseApp 继承application
  2. 在 app壳 module_main 和module_keepAlive 中继承 BaseApp, 注意两个module的 BaseApp的实现直接放在debug下,
  3. 别忘了表单文件中注册 application ,同样的注意两个module的只在module文件下的表单文件中注册就可以了.