一种app模块化实现方案

模块化的优势有很多,一代码分离,结构清晰;二多任务协同开发,而且自己模块单独运行也更轻量。等等。最近在调研各种实现方案,这是我的自己想出来的一种。

话不多说,直接分享我的操作步骤,然后我可能会与其他实现方式做个对比。

原有项目结构

为了实现模块化,前期我们已经根据应用功能场景,进行了module拆分,为实现模块化靠拢。项目简化结构如下图

APP是应用的入口module,我把他做得很简单,里边可以说就一个欢迎页Activity。BaseModule是一些跟基本封装。ModuleA、B、C是期望单独运行的Module。模块间的跳转我用的是ARouter,这块暂不多介绍。

我们知道,每一个Project都是由多个module组成,而settings.gradle中通过include方式引入这些module,所以一开始就在想如果能在编译时动态的引入module那不就是很简单了吗。

操作步骤

一 gradle.properties配置

在项目根目录的gradle.properties中定义一个变量,为了做到变量值的见名知意,我用的String类型的

	# ↓全量编译模式
	#DEVELOP_MODE="all"
	#
	# ↓单ModuleA模块编译模式
	DEVELOP_MODE="module-a"
	#
	# ↓单ModuleB模块编译模式
	#DEVELOP_MODE="module-b"
	#
	# ↓单ModuleC模块编译模式
	#DEVELOP_MODE="module-c"
	#
	...
复制代码

二 settings.gradle区分

根据gradle.properties中配置的不同运行模式,在settings中做简单的if else 判断,include不同的module

	include ':APP', 'BaseModule'
	if (DEVELOP_MODE == "\"module-a\"") {
	    include ':ModuleA'
	} else if (DEVELOP_MODE == "\"module-b\"") {
	    include ': ModuleB'
	} else if (DEVELOP_MODE == "\"module-c\"") {
	    include ': ModuleC'
	} else {
	    include ': ModuleA', ': ModuleB', ': ModuleC'
	}
复制代码

在这里有个写法上需要注意的是String类型的module-a需要加\转义,甚至调用startsWith这样的API都要这样写DEVELOP_MODE.startsWith("\"module")

有人说这里不需要区分,直接include所有module即可。我尝试后发现确实可以,但仍会执行多余module的gradle编译,徒增编译时间,所以最好区分。

三 APP的gradle配置

上面的module关系依赖图中我们看到,APP依赖了A、B、C这三个module。在这里,我们也是需要根据gradle.properties中配置的不同运行模式,动态引入依赖

	if (DEVELOP_MODE == "\"module-a\"") {
	    implementation project(':ModuleA')
	} else if (DEVELOP_MODE == "\"module-b\"") {
	    implementation project(':ModuleB')
	} else if (DEVELOP_MODE == "\"module-c\"") {
	    implementation project(':ModuleC')
	} else {
	    implementation project(':ModuleA')
	    implementation project(':ModuleB')
	    implementation project(':ModuleC')
	}
复制代码

好了,一个简单的模块化就实现了,如果想单独运行ModuleA,就将gradle.properties中的DEVELOP_MODE="module-a"这一行解开,其他注释掉,sync Now完后直接运行就OK了

拓展

一个正常的商业项目,肯定不像我前面的项目图一样简单,只有1个APP、1个Base、2个Module。我项目真实情况是类似中间的模块ABC这层就有20多个,而且不止一层;Base这层module也有五六个。不使用JIMU(积木)那种Android组件化框架的原因之一就是项目不是简简单单,关系整齐的这种依赖关系。

而且,在我们应用里,要想使用ModuleB,必须带着ModuleA的结果数据。要想B模块化后能使用,这该怎么做?需要的数据可能有:数据库、SharedPreferences、File文件,网络请求及合理的参数。

我们的做法是,为这种非正式的模块化运行添加一个,专门初始化假数据的module。在APP的欢迎页中跳转时判断,如果是模块化运行,直接往这个假数据Module跳,通过这个Module初始化好所有的数据后,再往真正的目标Module跳。

而需要准备的数据中,网络请求及合理的参数的准备,也有很多实现方案。比如就用真实的请求,比如本机运行服务。对于我做这个调研,没有找后端支持,也想过自己搭后台服务器,但是一想,搭好了服务器,也是简单的返回造好的假json串数据。所以干脆,本地处理算了,这时候okhttp的拦截器就是一个很好的应用了。我直接在拦截器中,判断请求的path,返回假的json串不就行了。

当然,还有很多模块化需要用到的小技术点,那就需要见招拆招了。

与其他模块化方式对比

(1)有一种模块化是这样写的,在ModuleA的gradle文件中
	if(isBuildModule.toBoolean()){
	    apply plugin: 'com.android.application'
	}else{
	    apply plugin: 'com.android.library'
	}
	...
	    sourceSets {
	        main {
	            if (isBuildModule.toBoolean()) {
	                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
	            } else {
	                manifest.srcFile 'src/main/release/AndroidManifest.xml'
	            }
	        }
	    }
	 
	 
	//isBuildModule是在gradle.properties中声明
	isBuildModule=false
复制代码

这样写的繁琐之处是

  • 需要在每个Module的gradle.properties中声明这样一个区分application还是library。
  • 准备两套Manifest。
  • 要想单独运行某个模块还得每次去改动settings的include,和APP的gradle中的依赖。
(2)使用JIMU(积木)这种Android组件化框架

它集成好之后的使用,虽然也很简单。但是框架的接入也是需要添加很多东西,比如每个module的properties中都需要进行配置。而且框架的一个缺点就是我们开发人员不知道它怎么实现的,遇到的编译问题也更不好查。

(3)我这样写的优缺点

优点

  • 条理清晰,定义的每个地方是什么作用都很清楚
  • 不修改原有module内的业务逻辑,在外边准备好所需数据有点沙盒似的设计。
  • 不只能单模块运行。也可能,多个模块组成一个业务线,整体运行这个业务线也很好实现。
  • 切换运行模块时,只开关gradle.properties里的配置就行。

缺点

  • 新配置一个模块化需要在gradle.properties、settings.gradle、APP的gradle,这3个地方都做响应的配置。需要配的模块化运行多了,if else 类的判断也会增多,代码行数也会增加,略显繁琐。但相对于切换模块的简便,这些是值得的。

最后求助各位道友,如果,您们有其他什么好的思路,欢迎你们和我一起交流

转载于:https://juejin.im/post/5cc27008f265da038c0219ab

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值