Modularization

What is componentization

Componentization is to divide an APP into different components, and each component is an independent module.

Meaning of componentization

Componentization can reduce coupling, while low coupling can improve maintainability.

At the same time, because components are independent, the coupling between components is low, so we can take components as the unit of team development, so as to improve the development efficiency.

How to componentize

Componentization is implemented using Gradle. So those who don’t know Gradle have to learn basic grammar. Of course, you can also not learn, just say that read other people write code to see half understand.

The first step is to create Module

The starting point is a brand new Project

There are several ways to create a Module.

  • Right-click on the new Module

    We should pay attention to the location of this, otherwise it is not very good that all the new will come out under the APP package, usually our Module is the same level as the APP. That is, under the big project.

    In my demo it’s below Modularization

  • Click File New for a Module

Here I create 3 modules and a lib

Note the naming, module is module_ module name, lib is lib__ library name.

A simple distinction is made between the following modules: lib is a module that does not display pages, and module is a collection of page modules.

Configure the version information into a Gradle file

Tips:
    fileName :app_versions.gradle

//applicationIds
def appIds = [:]
appIds.module_main = "com.example.module_main"
appIds.module_one = "com.example.module_one"
appIds.module_two = "com.example.module_two"
appIds.app = "com.example.modularization"
ext.appIds = appIds
Copy the code

Configure the gradle file to build. Gradle in project

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    apply from: 'app_versions.gradle'
    ext{
        app_configs = "$rootDir/app_config.gradle"
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "Com. Android. Tools. Build: gradle: 7.0.0." "
        classpath "Org. Jetbrains. Kotlin: kotlin - gradle - plugin: 1.5.20"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
Copy the code

Configure gradle build plug-ins

In gradle.properties, add a variable to determine if it is published

There are two states in componentization, one is debug state and one is release state,

  • Debug state is the development phase. In this phase, each module is an independent app and can run independently
  • Release: In this state, only the APP module can run independently, and other modules are lib, relying on the APP module.

An app_config.gradle file is then created

Write code so that module_XX can switch states between lib and app.

One thing to note here is that in gradle.propergies we write an isRelease bool, but gradle gets a string. Use toBoolean() to convert it.

if (isRelease.toBoolean()){
    if(project.name ! ='app')  apply plugin: 'com.android.library'
    else apply plugin: 'com.andorid.application'
}
else{
    if (project.name.matches('module_.+') || project.name == 'app') apply plugin: 'com.android.application'
    else if (project.name.matches('lib_.+')) apply plugin: 'com.android.library'
}
Copy the code

Then add the necessary dependencies

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
Copy the code

Configuring the Manifest File

android{
`````

sourceSets{
    main{
        if (isRelease.toBoolean()){
            manifest.srcFile "src/main/AndroidManifest.xml"
        }else {
            if (project.name.matches('module_.+')){
                manifest.srcFile "src/main/manifest/AndroidManifest.xml"
            }else if (project.name.matches('lib_.+') || project.name == 'app'){
                manifest.srcFile "src/main/AndroidManifest.xml"}}}} `````}Copy the code

Then make a small change to the Module manifest file

Create the manifest folder in the main folder and place the debug manifest file in it.

Debug file (the compiled file in this state is APK, so you need to configure the startup page and some application options)


      
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.module_main">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Modularization">
        <activity
            android:name=".MainMainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Copy the code

The manifest file in the release state (the compile file in this state is an AAR file so only one activity needs to be registered, none of the rest is required)


      
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.module_main">

    <application>
        <activity
            android:name=".MainMainActivity"
            android:exported="true" />
    </application>

</manifest>
Copy the code

The rest of the module_XX modules are also changed in the same way.

Configuration applicationId

Since application has an applicationId, lib has no applicationId, and Module switches wildly between Application and Module, so it is necessary to set it.

if (isRelease.toBoolean()) {
    applicationId "com.example.modularization"
}else {
    if (project.name.matches('module_.+') || project.name == 'app') {
        applicationId appIds[project.name]
    }
}
Copy the code

Add a variable to your project build.gradle to make it easier for your gradle file to access app_config.gradle.

buildscript {
    ext{
        app_config = "$rootDir/app_config.gradle"
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "Com. Android. Tools. Build: gradle: 7.0.0." "
        classpath "Org. Jetbrains. Kotlin: kotlin - gradle - plugin: 1.5.20"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files}}Copy the code

The module reference app_config. Gradle

before

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 30

    defaultConfig {
        applicationId "com.example.module_main"
        minSdk 21
        targetSdk 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    implementation 'androidx. Core: the core - KTX: 1.3.2'
    implementation 'androidx. Appcompat: appcompat: 1.2.0'
    implementation 'com. Google. Android. Material: material: 1.3.0'
    implementation 'androidx. Constraintlayout: constraintlayout: 2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx. Test. Ext: junit: 1.1.2'
    androidTestImplementation 'androidx. Test. Espresso: espresso - core: 3.3.0'
}
Copy the code

after

apply from: app_configs

dependencies {

    implementation 'androidx. Core: the core - KTX: 1.3.2'
    implementation 'androidx. Appcompat: appcompat: 1.2.0'
    implementation 'com. Google. Android. Material: material: 1.3.0'
    implementation 'androidx. Constraintlayout: constraintlayout: 2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx. Test. Ext: junit: 1.1.2'
    androidTestImplementation 'androidx. Test. Espresso: espresso - core: 3.3.0'
}
Copy the code

This is true for the rest of the Lib and Module

Extract some properties from the Android closure


def android_versions = [:]
android_versions.sdk_version = 30
android_versions.min_version = 21
android_versions.target_version = 30
android_versions.version_code = 1
android_versions.version_name = "1.0"

def kotlin_options = [:]
kotlin_options.jvm_target = '1.8'
android_versions.kotlin_options = kotlin_options

ext.android_versions = android_versions
Copy the code

The content of the app_config. Gradle

if (isRelease.toBoolean()){
    if(project.name ! ='app')  apply plugin: 'com.android.library'
    else apply plugin: 'com.andorid.application'
}
else{
    if (project.name.matches('module_.+') || project.name == 'app') apply plugin: 'com.android.application'
    else if (project.name.matches('lib_.+')) apply plugin: 'com.android.library'
}

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

android {
    compileSdk android_versions.sdk_version

    defaultConfig {
        if (isRelease.toBoolean()) {
            applicationId "com.example.modularization"
        }else {
            if (project.name.matches('module_.+') || project.name == 'app') { applicationId appIds[project.name] } } minSdk android_versions.min_version targetSdk android_versions.target_version  versionCode android_versions.version_code versionName android_versions.version_name testInstrumentationRunner"androidx.test.runner.AndroidJUnitRunner"
    }

    sourceSets{
        main{
            if (isRelease.toBoolean()){
                manifest.srcFile "src/main/AndroidManifest.xml"
            }else {
                if (project.name.matches('module_.+')){
                    manifest.srcFile "src/main/manifest/AndroidManifest.xml"
                }else if (project.name.matches('lib_.+') || project.name == 'app'){
                    manifest.srcFile "src/main/AndroidManifest.xml"
                }
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = android_versions.kotlin_options.jvm_target
    }
}
Copy the code