今天這個題目很難取,組件化範疇的內容,又是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包還不支持。
本文也是組件化的一部份內容,後面會再更新一些在大廠中用到的組件化知識,歡迎關注。
完。