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