One of the problems you face in componentized development is debugging components.

That is, the component and the main project are not in the same project directory. The main project relies on the AAR package released by the component. When a component develops new functionality, a new AAR package is released and introduced in the main project.

The problem with this approach is that it can be inconvenient if the component is buggy or needs to be debugged. Specifically, if a problem is fixed, publish an AAR for the component and verify in the main project that the problem has been successfully fixed. Since aar packages are frequently published and debugging is inefficient, is there a way to reference the component Module directly during development rather than using the aar package? The answer, of course, is some, the following to introduce a specific implementation plan.

Preparations:

Assume that the main project path: / Users/mei/WorkSpace/AndroidProjects/TestModuleDep

Component engineering path: / Users/mei/WorkSpace/AndroidProjects/module – the user/user

Components of maven path: com. Mei. The module: user: 1.0.0

In the build.gradle file of the main project, introduce the user component:

dependencies {
    implementation 'com. Mei. The module: user: 1.0.0'
}
Copy the code

A component module(source) dependency


As you can see from the above, the main project relies on the User component through an AAR package that relies on the User component. If you want to debug locally, you can rely on component Modules instead. Specific operations are as follows:

1. Include module

In the settings.gradle file of the main project, add the component module to the compilation, namely include component module. Components are not in the same project directory as the main project, so component modules include different methods:

include ":user"
project(":user").projectDir = file("/Users/mei/WorkSpace/AndroidProjects/module-user/user")
Copy the code

Add settings.gradle to the main project to include the module, as shown in the code above.

2. Depend on component Module

Build. Gradle = build. Gradle = build. Gradle = build. Gradle = build. Gradle = build.

dependencies {
    / / implementation 'com. Mei. The module: user: 1.0.0'
    implementation project(':user') // Rely on components as component modules
}
Copy the code

After the above two steps, you can rely directly on the source code of the component, rather than the AAR package of the component, and it is very easy to debug without having to publish an AAR package for every change.

Through the above way, it is possible to rely on the source code, but every time you need to debug such a change, it is very troublesome, but also need to comment out the AAR dependent way, if accidentally submitted code, it may lead to remote packaging problems.

Is there a way to use module dependencies during development without changing app gradle files? Here’s a quick way to switch between AAR dependencies and source dependencies.

Fast switch between AAR dependency and source dependency


In the build.gradle file of the main project, add the following code:

allprojects {// All components are added
    configurations.all {
        resolutionStrategy {
            dependencySubstitution {
            		/ / module, the groupId: artifactId
            		// project, component module name
                substitute module( "com.mei.module:user") with project(':user')}}}}Copy the code

The code above means that if you replace the AAR package with module, only module code will be compiled, and aar code will not be compiled.

Of course, you can also add the above code to the build.gradle file of your app without calling the AllProjects method. For example:

configurations.all {
  resolutionStrategy {
      dependencySubstitution {
          / / module, the groupId: artifactId
          // project, component module name
          substitute module( "com.mei.module:user") with project(':user') / / comment 1}}}Copy the code

If you don’t want to use module dependencies, you can comment out the code in comment 1 and continue using AAR dependencies.

Component dependency encapsulation


After the operation of quick switch between AAR dependency and source dependency, we can realize the quick switch between AAR dependency and Module dependency without commenting out aar dependency of component. The settings.gradle and build.gradle files of the main project still need to be modified.

If I put all of my operations into a gradle file, I can do all of the above operations in settings.gradle file of the main project. If I import this file, I can do all of the above operations without causing the compilation process to fail. Wouldn’t that solve the problem of missubmission?

Here’s how to encapsulate it.

1, in module project, add module dependency file

In the Module project, add the user_dependency. Gradle file (full path: / Users/mei/WorkSpace/AndroidProjects/module – user/user_dependency. Gradle), in the file, the introduction of the implementation component module and aar depend on dynamic switching function. Note that this file does not need to be added to Git management.

1-1. Component Module dependency

include ":user"
project(":user").projectDir = file("/Users/mei/WorkSpace/AndroidProjects/module-user/user")
Copy the code

1-2. Dynamic switch between AAR dependency and component Module dependency

In the user_dependency. Gradle file, add the following listener:

gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {

    @Override
    void beforeEvaluate(Project projectObj) {
        try {
          	// Add extended attributes
            if(! projectObj.rootProject.extensions.hasProperty("kotlin_version")) {
                projectObj.rootProject.extensions.add("kotlin_version"."1.4.32")}}catch (Exception e) {
            e.printStackTrace()
        }
      	// Global configuration file for the application component project
        projectObj.rootProject.apply from: "/Users/mei/WorkSpace/AndroidProjects/module-user/mavenConfig.gradle"

        println "beforeEvaluate project.configurations=${projectObj.configurations}"
    }

    @Override
    void afterEvaluate(Project projectObj, ProjectState state) {
        println "project name is $projectObj"
        println "afterEvaluate project.configurations=${projectObj.configurations}"
        if(projectObj.name ! ="app") {
            return
        }
      	// Switch aar dependencies with component Module dependencies
        projectObj.configurations.all { Configuration ->
            resolutionStrategy {
                dependencySubstitution {
                    substitute module( "com.mei.module:user") with project(':user')}}}}})Copy the code
  1. Add ProjectEvaluationListener listening to gradle object, event

  2. In ProjectEvaluationListener beforeEvaluate method, add some components need to rely on additional configuration, if not, don’t have to add.

  3. In ProjectEvaluationListener afterEvaluate methods, object to the specified project, increase the configuration information, such as: to app project, increase the dynamic switching aar depend on the configuration and the module to rely on.

    Note:

    • Rename afterEvaluate’s Project argument, otherwise calling the Project () method will fail in the dependencySubstitution closure.
    • Only in ProjectEvaluationListener afterEvaluate method to increase the configuration information on a project, because in afterEvaluate method, project configurations configuration object is not null, In the beforeEvaluate method, the engineering configurations object is an empty object and cannot add configuration information.

1-3, completeuser_dependency.gradleThe code is as follows:

// 1. Include component module, note that absolute path is used
include ":user"
project(":user").projectDir = file("/Users/mei/WorkSpace/AndroidProjects/module-user/user")

// 2. Aar dependencies and Module dependencies are dynamically switched
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {

    @Override
    void beforeEvaluate(Project projectObj) {
        try {
          	// Add extended attributes
            if(! projectObj.rootProject.extensions.hasProperty("kotlin_version")) {
                projectObj.rootProject.extensions.add("kotlin_version"."1.4.32")}}catch (Exception e) {
            e.printStackTrace()
        }
      	// Global configuration file for the application component project
        projectObj.rootProject.apply from: "/Users/mei/WorkSpace/AndroidProjects/module-user/mavenConfig.gradle"

        println "beforeEvaluate project.configurations=${projectObj.configurations}"
    }

    @Override
    void afterEvaluate(Project projectObj, ProjectState state) {
        println "project name is $projectObj"
        println "afterEvaluate project.configurations=${projectObj.configurations}"
        if(projectObj.name ! ="app") {
            return
        }
      	// Switch aar dependencies with component Module dependencies
        projectObj.configurations.all { Configuration ->
            resolutionStrategy {
                dependencySubstitution {
                    substitute module( "com.mei.module:user") with project(':user')}}}}})Copy the code

2. In settings.gradle of the main project, apply dependency files

In the settings.gradle file of the main project, apply user_dependency. Gradle:

include ":app"

try {
    apply from:"/Users/mei/WorkSpace/AndroidProjects/module-user/user_dependency.gradle"
} catch (Exception e) {
    e.printStackTrace()
}
Copy the code

Apply the user_dependency. Gradle file as an absolute path. The purpose of adding a try catch here is that even if the user_dependency. Gradle file is not found, it will not affect the overall compilation process. That is, you can use AAR dependencies even if you don’t reference a component Module.

In this way, you can dynamically switch aar dependencies to component Modules by modifying settings.gradle files in the main project, and changes to settings.gradle can be committed without affecting the online packaging process.

When debugging, you can comment out the code that applies the user_dependency. Gradle file if you want to use aar dependency.

Of course, you can also add a switch in the user_dependency. Gradle file that indicates whether to use module dependencies, thereby controlling the dynamic switch between module and AAR packages.

Such as:

.def useModule = true

// 2. Aar dependencies and Module dependencies are dynamically switched
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {

    @Override
    void beforeEvaluate(Project projectObj) {
     	.... 
    }

    @Override
    void afterEvaluate(Project projectObj, ProjectState state) {
        if(projectObj.name ! ="app") {
            return
        }
      	// Switch aar dependencies with component Module dependencies
        projectObj.configurations.all { Configuration ->
            resolutionStrategy {
                dependencySubstitution {
                		if(useModule){ Module dependencies are used only when the switch is on
                				substitute module( "com.mei.module:user") with project(':user')}}}}}})Copy the code

Thinking and expanding:

Can the above operations be encapsulated in a plug-in, so that the dynamic switch between AAR dependencies and component Module dependencies can be dynamically controlled only by providing a configuration information in the main project? Local debugging is also easier and faster.

If you have time, come back to try to implement this plug-in, stay tuned!!