When the project starts to swell

How do you maintain a huge Android project as it gets bigger, more complex, and has more and more members?

In the first stage, everyone will extract the common modules, encapsulate them into aar, and then introduce them through Maven.

In the second phase, you import routing and SPI, break the project up into sub-modules, and then each person is responsible for one or two modules or something, so that you can develop in parallel.

Phase three is when the project is bloated to the point where compilation is getting slower and slower. At this time, a shell project will be abstracted first, and then all the subitem modules will be introduced into the shell by means of AAR. After that, each business will be put in a warehouse, so that there will be no code conflicts between multiple businesses.

This is where other, more troubling issues arise.

  1. Shell engineering is not all business warehouses need to have a, then shell engineering code synchronization how to do?
  2. Aar version problems with various repositories? How to manage aar in a unified manner if different branch versions need to be used?
  3. What if I have to debug someone else’s warehouse?

Never look for the wheel

So are there any ready-made wheels that can solve these engineering problems?

Gradle Repo will allow me to give you an Amway project. This is the wheel we are using for our current project. Making portal

The author describes the warehouse as follows.

Gradle Repo is a plugin written based on Gradle. It is used to manage multiple Git repositories and supports easy and quick branch switching. In the root project, there is a configuration manifest, repo. XML, that describes the module source, the project structure, and the dependencies.

Three main things have been done:

Clone code from each remote repository to the specified directory path. Use Git exclude instead of subModule. Include modules dynamically and switch dependencies between modules to the specified branch.

The text description may not be clear enough, so let’s analyze this function through a picture of the author.

Then I wrote my own mock repo.xml file, and let’s use the XML to briefly describe what we did.

<?xml version='1.0' encoding='UTF-8'? >
<manifest>
 
    <substitute project=":module" targetModule="com.a.b:c"/>

    <module name="RouterLib"
        origin="https://github.com/Leifzhang/Router-Android.git"
        srcBuild="false" 
        substitute="com.github.leifzhang:routerLib" />
        
</manifest>
Copy the code

This is a highly similar template that I generated from within the project.

  1. The SUBSTITUTE tag represents the project name inside the setting under the current project, where the targetModule represents the AAR version that we need to replace.
  2. Module represents the remote module we want to clone, Origin represents the repository address, srcBuild represents whether the dependencies are currently open, and Substitute represents the project where the remote implementation is replaced.

Once the project has been adjusted using Gradle Repo, we can plug and plug the modules we need, combine multiple repositories and compile at the same time. At the same time in ci, we still rely on the implementation of the warehouse, we will not affect the development of other lines of business during the development, at the same time in different because each warehouse is an independent Gitlab, so there will be a natural advantage in branch management.

But is the plan perfect?

In fact, it is not, so because the project is scattered in different warehouses, so there must be a problem, how to manage the AAR version of the project ??????

I don’t know if any of you noticed that a guy called JakeWharton wrote an article a while ago saying that my code was like whack-a-mole? . If you want to keep your configurations, you need to keep your configurations.

gradle configurations.all

Configurations. All is used to force you to flatten the MAVEN AAR version within your project. If a project introduces a different version of an AAR through implementation dependency, the version defined in configurations. All takes precedence, ignoring the different versions used within the project.

configurations.all {
    resolutionStrategy {
        force "Com. Android. Support: appcompat - v7:28.0.0"}}Copy the code

The code above means to force the supportV7 version in the project to 28.0.0.

Upgrade this capability with the Gradle Plugin

Configurations If you simply use configurations, you will not be able to pack the capability into a box that every business module needs to handle. If you do, you can consider expanding the capability by defining a task with a Gradle plugin.

Define the DEP version configuration

First we need to define a remote Gradle file related to the branch version. This file will define the version of the Maven repository we are familiar with in the project directory.

  dep = [
            fastjson                 : "com.alibaba:fastjson:${fastjsonVersion}".// Three-party control
            androidSupportV4         : "com.android.support:support-v4:${androidSupportV4Version}",
            androidSupportV7         : "com.android.support:appcompat-v7:${androidSupportV7Version}",
            androidLifecycle         : "android.arch.lifecycle:runtime:${androidLifecycleVersion}",
            androidLifecycleCommon         : "android.arch.lifecycle:common:${androidLifecycleVersion}",
            androidLifecycleCommonJava8    : "android.arch.lifecycle:common-java8:${androidLifecycleVersion}",
            androidLifecycleCompiler : "android.arch.lifecycle:compiler:${androidLifecycleVersion}",
            androidLifecycleExtensions:"android.arch.lifecycle:extensions:${androidLifecycleVersion}",
            recyclerview             : "com.android.support:recyclerview-v7:${recyclerviewVersion}",
            androidSupportAnnotations: "com.android.support:support-annotations:${androidSupportVersion}"
            ]

Copy the code

Customize Gradle Task

If you want to update your gradle, you need to update your gradle configurations. If you want to update your gradle, you need to update your Gradle configurations. If you want to update your Gradle, you need to update your Gradle configurations. Flatten the AAR version within the project.

classAATask: DefaultTask() {@taskAction fun Apply () {## pseudocode pulls Dep configuration from remote// Forcibly replace the configuration in the item
        forceConfigVersion(project)
    }
    
    fun forceConfigVersion(project: Project) {
        project.subprojects {
            val depModuleSelectorNotations = mutableListOf<String>()

            project.extensions.extraProperties.properties.forEach { key, any ->

                if (any! =null&& key! =null&&key.endsWith("dep")) {if (any is Map<*, *>){
                        collectDepModuleVersionSelectorNotations(depModuleSelectorNotations, any)
                    }
                }
            }

            it.configurations.all { configuration ->
                configuration.resolutionStrategy.force(depModuleSelectorNotations)
            }
        }


    }

Copy the code

Specific details of the content involved in the company code is not everyone detailed expansion, the core of the idea is that all the three party library version of the remote branch as a standard.

conclusion

This article is just a popular science article, does not involve any code analysis, if there is something offended, you can not call me.