For the first time to read dry goods, you can pay attention to my public number: program ape cultivation center
This topic is very difficult to answer today. The content of componentization category is related to EventBus. However, by using the form of Gradle plug-in, we can simply say that the message type of EventBus is automatically compiled under componentization.
The EventBus library is a popular way to define a message type. If you have used EventBus, you need to define a message type.
In componentized projects, message types are defined in common modules so that they can be passed across components. This works, but there are two drawbacks:
- The need to manually change the public library, which brings certain risks to the public library, more and more code added to the public library will be difficult to maintain later, the componentization boundary is difficult to define, the public library needs to be stable
- The split between the components is not very clean, if the modification of component communication content at the same time need to modify the content in the public library, if the development of component module A can not see the source code in the public library? Just catch blind
So our goal is that the types of messages a component needs to receive or send are defined directly within its own component scope, without having to modify any code outside of the component. The less you change, the less bugs you will have, and the sooner you can leave work, right?
Results 1.
Let’s take a look at the overall project structure
Divided into app/event/modulea moduleb four parts Send a message in the app, a and b can be received, the contents of the a and b the same, just looking at the code in under a a ADisplay used to display the received message, a ModuleaMsg used to define the message type.
Take a look at the code in ADisplay and accept the ModuleaMsg message:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ModuleaMsg msg) {
System.out.println("Module A received msg = " + msg.msg);
EventBus.getDefault().unregister(this);
}
Copy the code
ModuleaMsg is the message type? Check in with component A, write a file that ends with.event, and write code in it
This does all the work the component needs to do, without modifying any other components at all.
In the send place, we’re sending messages directly in the app component here,
ModuleaMsg moduleaMsg = new ModuleaMsg();
moduleaMsg.msg = "send from app";
EventBus.getDefault().post(moduleaMsg);
ModulebMsg modulebMsg = new ModulebMsg();
modulebMsg.num = 10086;
EventBus.getDefault().post(modulebMsg);
Copy the code
Modulea and ModuleB received the following message:
Module A received msg = send from app
Module B received msg = 10086
Copy the code
Above is all the way to use, if there are still interested partners then go down to see the implementation principle.
2. Implementation method
AfterEvaluate is a plugin for gradle. After evaluating is a plugin for gradle. After evaluating is a plugin for Gradle.
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
...
}
Copy the code
First determines whether there is a project in engineering. EventPluginExt. EventModuleName (= the event) this module, you can see in the first picture there is a event this module, which contains all the message type
Then define a file that clears the old.event suffix under the component, taking precedence over Gradle Cleantask.
And then you go down, and then you get all the components, divided into two types,lib modules or application modules
getVariants().all { variant ->
def variantName = Utils.captureName(variant.name)
System.out.println("variantName is " + variantName)
if (isLibrary()) {
} else{}}private boolean isLibrary(a) {
return project.android.hasProperty('libraryVariants')}Copy the code
Take a look at the code below the lib module, divided into three parts, first part:
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[]
Copy the code
The assets folder in lib is stored in the eventFolder folder in assets folder in APK. Then define the file location of the Event component in the root directory, and finally get all the code files in the lib directory.
Then look at part 2, which defines tasks:
eventLibCopyTask
It’s a copy task. Get what you got earlierjavaSrcList
In the.event
Suffix of the file copied toevent
Module, and modify the suffix name.java
, before preBuild is executed- Get the first one in the build process
task
—preBuild
- Defining a Copy Task
eventAssetsCopyTask
SRC /javasrc//.event->assets/cocoFolder//.event- Get the generateAssets task
- Get the mergeAssets task
- Gets the current variant compilation tasks – such as assembleDebug/assembleRease
- Define the delete task – Delete assets/cocoFolder/ in assets under lib/The event file
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
}
Copy the code
The third part is to define the execution sequence of the above tasks. The first step is definitely to copy the. Event file to the event module.
2) preBuild 3) Copy lib events to Assets 4) generateAssets 5) mergeAssets 6) Delete events from Assets 7) assembleCopy the code
preBuildTask.dependsOn eventLibCopyTask
generateAssetsTask.dependsOn eventAssetsCopyTask
mergeAssetsTask.finalizedBy eventAssetsDeleteTask
assembleTask.finalizedBy eventAssetsDeleteTask
// Add the precompiled dependency of event to avoid the problem that the class cannot be found when the event module executes the event copy task of the current project after the compilation is completed
def preEventBuildTask = null
try{
preEventBuildTask = eventModule.tasks.getByName("preBuild")}catch (Exception ignored) {
}
if(preEventBuildTask ! =null) {
preEventBuildTask.mustRunAfter eventLibCopyTask
}
Copy the code
The application module will have a dependent AAR, which may contain. Event files, so you need to loop these files from the dependency to the Event module
The first step is to move the.event file from the AAR dependency to the Event module in the project directory
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".' ')}}}Copy the code
The second step is to copy the app module suffix file to the event module, the logic is the same as the previous lib module, the implementation effect is javasrc/*. Event ->event/ SRC /javasrc/*/*. Java will not be introduced again
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
}
Copy the code
3. Summary
That’s all. The main purpose of this plug-in is to enable automatic compilation of message types, which can aid in better decoupling of components, and component developers do not need to contract or modify the base library to achieve data transfer purposes. One thing to note is that currently only aar modules are supported, jar packages are not supported. This article is also part of the componentization content, and will be updated later with some componentization knowledge used in large factories.
Because the level is limited, have wrong place unavoidable, rather misdirect others, welcome big guy to point out! Code word is not easy, thank you for your attention!
🙏 If you are studying with me, you can follow my official account — ❤️ Program ape Development Center ❤️. Every week, we will share the technology of Android regularly.