今天这个题目很难取,组件化范畴的内容,又是EventBus的相关内容,可是经过gradle插件化的形式来作,简单就说成组件化下EventBus的消息类型自动编译,有更好主意的小伙伴能够推荐。先说下背景,组件化过程当中确定涉及到数据的传递问题,EventBus这个库是比较流行的方式,用过EventBus的小伙伴都知道须要先定义一个消息类型。在组件化工程里面通常都会把消息类型定义到公共模块,这样跨组件才能传递。这样作能实现目的,可是有两个弊端:java
因此咱们的目的是,组件须要接受或者发送的消息类型直接在本身组件范围内定义,不须要去修改组件外的任何代码,修改越少,bug就越少,就能越早下班不是吗?android
先看下整个项目结构 git
ADisplay
用于显示接收到的消息,一个
ModuleaMsg
用于定义消息类型。
看下 ADisplay
中的代码,要接受的是ModuleaMsg
消息:github
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ModuleaMsg msg) {
System.out.println("Module A received msg = " + msg.msg);
EventBus.getDefault().unregister(this);
}
复制代码
ModuleaMsg
就是消息类型?在a组件中登记,写一个以.event
结尾的文件,在里面写入代码就可bash
这样就完成了组件须要完成的所有工做了,彻底不须要修改其余的组件。app
在发送的地方,咱们这里直接在app组件中发送消息,组件化
ModuleaMsg moduleaMsg = new ModuleaMsg();
moduleaMsg.msg = "send from app";
EventBus.getDefault().post(moduleaMsg);
ModulebMsg modulebMsg = new ModulebMsg();
modulebMsg.num = 10086;
EventBus.getDefault().post(modulebMsg);
复制代码
modulea和moduleb接收到消息:post
Module A received msg = send from app
Module B received msg = 10086
复制代码
上面就是所有的使用方式了,若是还有兴趣的小伙伴接着往下看实现原理了。gradle
其实就是经过gradle插件的方式实现,须要了解怎么定义gradle插件的能够参考我以前的一步步自定义Gradle插件,这里就再也不赘述,咱们直接看下插件里面的代码, 主要任务都在project.afterEvaluate中完成,ui
project.afterEvaluate {
def eventModule = project.rootProject.childProjects.get(project.EventPluginExt.eventModuleName)
if (eventModule == project) {
throw new GradleException('event module should not be itself!')
}
if (eventModule == null || !eventModule.projectDir.exists()) {
throw new GradleException('event module is not exists')
}
def cleanEventTask = project.task("eventClean", type: Delete) {
delete("${project.rootProject.projectDir}/${eventModule.name}/src/main/java")
}
project.tasks.getByName("clean").dependsOn cleanEventTask
...
}
复制代码
首先判断工程中是否有project.EventPluginExt.eventModuleName (= event
)这个模块,在第一张图中能够看到有个event这个模块,里面包含了全部的消息类型
而后定义一个清除组件下旧的.event
后缀的文件,优先于gradle clean
task。
接着往下看,接着会拿到全部构件体,分红两种,lib
模块或者application
模块
getVariants().all { variant ->
def variantName = Utils.captureName(variant.name)
System.out.println("variantName is " + variantName)
if (isLibrary()) {
} else {
}
}
private boolean isLibrary() {
return project.android.hasProperty('libraryVariants')
}
复制代码
先看下lib
模块下面的代码,分红三部分,先看下第一部分:
def intoAsset
def assetDir = Utils.getOneAssetDir(variant)
if (assetDir == null) {
intoAsset = "${project.projectDir}/src/main/assets/$eventFolder"
} else {
intoAsset = assetDir.absolutePath + "/$eventFolder"
}
def intoEventSdk = "${project.rootProject.projectDir}/${eventModule.name}/src/main/java"
List list = new ArrayList()
variant.sourceSets.each { sourceSet ->
sourceSet.java.srcDirs.each { file ->
list.add(file)
}
}
def javaSrcList = list as String[]
复制代码
首先拿到lib里面的assets
目录,是为了后面把全部lib中的.event
文件都保存到apk中的assets
目录中的eventFolder
文件夹;而后定义根目录下event
组件下的文件位置,最后拿到lib
下的全部代码文件。
接着看下第二部分,主要是定义任务task
:
eventLibCopyTask
是拷贝任务,把前面拿到的javaSrcList
中.event
后缀的文件复制到event
模块下,而且修改后缀名为.java
, 在执行preBuild前生成- 拿到build过程的第一个
task
---preBuild
- 定义拷贝任务
eventAssetsCopyTask
,负责负责src/javasrc//.event->assets/cocoFolder//.event- 获取generateAssets任务
- 获取mergeAssets任务
- 获取当前variant编译任务——如assembleDebug/assembleRease
- 定义删除任务-删除的是lib下assets中的delete assets/cocoFolder//.event文件
Task eventLibCopyTask = project.task("eventLibCopyTaskFor" + variantName, type: Copy) {
includeEmptyDirs = false
from javaSrcList
into intoEventSdk
include "**/*.${project.EventPluginExt.postFix}"
rename "(.*)${project.EventPluginExt.postFix}", '$1java'
}
Task preBuildTask = project.tasks.getByName("pre" + variantName + "Build")
Task eventAssetsCopyTask = project.task("eventAssetsCopyTaskFor" + variantName, type: Copy) {
includeEmptyDirs = false
from javaSrcList
into intoAsset
include "**/*.${project.EventPluginExt.postFix}"
}
Task generateAssetsTask = project.tasks.getByName("generate" + variantName + "Assets")
Task mergeAssetsTask = variant.mergeAssets
Task assembleTask = variant.assemble
Task eventAssetsDeleteTask = project.task("eventAssetsDeleteFor" + variantName, type: Delete) {
delete intoAsset
}
复制代码
第三部分就是定义上面几个任务的执行顺序,第一步确定是要拷贝.event
文件到event
模块下面,几个任务顺序:
1) 拷贝lib中event到event中
2) preBuild
3) 拷贝lib中event到assets中
4) generateAssets
5) mergeAssets
6) 删除assets中的event文件
7) assemble
复制代码
preBuildTask.dependsOn eventLibCopyTask
generateAssetsTask.dependsOn eventAssetsCopyTask
mergeAssetsTask.finalizedBy eventAssetsDeleteTask
assembleTask.finalizedBy eventAssetsDeleteTask
// 添加event的预编译依赖,避免event模块在编译完成以后再执行当前project的event拷贝任务,致使类查找不到的问题
def preEventBuildTask = null
try{
preEventBuildTask = eventModule.tasks.getByName("preBuild")
} catch (Exception ignored) {
}
if(preEventBuildTask != null) {
preEventBuildTask.mustRunAfter eventLibCopyTask
}
复制代码
上面就是lib
模块的代码逻辑,接下来看下application
模块的相关逻辑,application
模块会有依赖的aar,aar里面可能有.event
的文件,因此须要从依赖中循环拿到这些文件拷贝到event
模块中
分红两个步骤,先看下第一个步骤,就是从aar依赖中把.event
后缀的文件移动到项目目录的event
模块中
Task appUnpackTask = null
if (variant.hasProperty("compileConfiguration")) {
// For Android Gradle plugin >= 2.5
Attribute artifactType = Attribute.of("artifactType", String)
FileCollection classPathConfig = variant.compileConfiguration.incoming.artifactView {
attributes {
it.attribute(artifactType, "aar")
}
}.files
System.out.println("classPathConfig = " + classPathConfig)
appUnpackTask = project.task("eventAppUnpack" + variantName, type: Copy) {
includeEmptyDirs = false
classPathConfig.each {
from(project.zipTree(it))
}
into "${project.rootProject.projectDir}/${eventModule.name}/src/main/java"
include "**/$eventFolder/**/*.${project.EventPluginExt.postFix}"
rename "(.*)${project.EventPluginExt.postFix}", '$1java'
eachFile {
it.path = it.path.replaceFirst(".*$eventFolder", '')
}
}
}
复制代码
第二个步骤就是把app模块下的后缀文件拷贝到event
模块中,逻辑和前面lib模块的逻辑同样的,实现效果就是javasrc/*.event->event/src/javasrc/*/*.java
就不重复介绍了
List list = new ArrayList()
variant.sourceSets.each { sourceSet ->
sourceSet.java.srcDirs.each { file ->
list.add(file)
}
}
def javaSrcList = list as String[]
System.out.println("javaSrcList is " + javaSrcList)
def intoEventSdk = "${project.rootProject.projectDir}/${eventModule.name}/src/main/java"
Task eventAppCopyTask = project.task("eventAppCopyTaskFor" + variantName, type: Copy) {
includeEmptyDirs = false
from javaSrcList
into intoEventSdk
include "**/*.${project.EventPluginExt.postFix}"
rename "(.*)${project.EventPluginExt.postFix}", '$1java'
}
if (appUnpackTask != null) {
Task preBuildTask = project.tasks.getByName("pre" + variantName + "Build")
preBuildTask.dependsOn(appUnpackTask)
preBuildTask.dependsOn(eventAppCopyTask)
eventModule.tasks.getByName("preBuild").mustRunAfter appUnpackTask
eventModule.tasks.getByName("preBuild").mustRunAfter eventAppCopyTask
}
复制代码
上面就是这个插件的所有内容了,主要就是完成消息类型的自动编译,能够辅助组件化更好的解耦,组件开发人员不须要去约定或者修改基础库才能达到数据传输的目的。有个须要注意的地方就是目前只支持模块是aar的包,jar包还不支持。
本文也是组件化的一部份内容,后面会再更新一些在大厂中用到的组件化知识,欢迎关注。
完。