My Journey of Developing Android Apps#
Series#
2022-01-06#
android#
article/done/published#
Journey#
Phase One: Single App, Single Module#
The initial requirement was simple, only one app was needed, and all the functionalities were directly placed in one module.
component app
Phase Two: Single App, Multiple Feature Modules#
As the project progressed, there were independent feature modules that required customization. One solution was to use DynamicFeature.
component app
component dynamic_feature_a
component dynamic_feature_b
component dynamic_feature_n
dynamic_feature_a --> app
dynamic_feature_b --> app
dynamic_feature_n --> app
DynamicFeature requires support from the app market.
It is not commonly used for cases that require independent deployment. Of course, there is also https://github.com/iqiyi/Qigsaw, which allows you to deploy an app market that supports dynamic features. However, the deployment process is too complex.
Another solution is pluginization, which can be done at runtime or compile time.
Compile-time pluginization is relatively simple to implement, as it only requires dynamically modifying the app's dependencies. At runtime, all plugin implementations are obtained through reflection and the corresponding methods are called.
component app
component feature_a
component feature_b
component feature_n
app --> feature_a
app --> feature_b
app --> feature_n
Compile different plugin modules
build.gradle
dependencies{
if(useFeature("feature_a")){
implementation ":feature_a"
}
if(useFeature("feature_b")){
implementation ":feature_b"
}
}
Phase Three: Single App, Multiple Feature Modules, Single Common Module#
As the number of feature modules increased, there were a lot of duplicated library dependencies among different modules, and there could be version conflicts.
To unify the version and usage of utility libraries, encapsulation was needed.
Therefore, a common library was introduced.
In principle, all dependencies related to core functionalities of non-feature modules should be placed in the common library, such as network requests, image processing, key-value storage, and databases.
Additionally, feature modules should not directly depend on third-party libraries; they should go through the common library for encapsulation, to facilitate future upgrades and migrations.
component app
component feature_a
component feature_b
component feature_n
app --> feature_a
app --> feature_b
app --> feature_n
component common
feature_a --> common
feature_b --> common
feature_n --> common
Phase Four: Interdependent Feature Modules#
As the number of feature modules increased, there was a need for inter-module communication. However, feature modules belong to the same layer from a hierarchical perspective, and direct dependencies between the same layer should be avoided to prevent circular dependencies.
Therefore, a common feature module (services) or service bus was introduced, where all feature modules provide services to other modules by implementing interfaces in the services module.
The common module and common feature module are collectively referred to as the Framework.
package apps{
component app
}
package features{
component feature_a
component feature_b
component feature_n
}
app --> feature_a
app --> feature_b
app --> feature_n
package framework{
component common
component services {
component feature_a_service
component feature_b_service
component feature_n_service
}
}
features --> common
feature_a --> feature_a_service
feature_b --> feature_b_service
feature_n --> feature_n_service
There is another way to handle service calls between modules, which is to define a separate component for each feature module to provide public services to other modules. However, this can lead to exponentially complex dependency relationships, so it is better to manage all modules' public services in a unified manner.
component feature_a
component feature_a_service
feature_a --|> feature_a_service
component feature_b
component feature_b_service
feature_b --|> feature_b_service
component feature_n
component feature_n_service
feature_n --|> feature_n_service
feature_a --> feature_b_service
feature_b --> feature_a_service
feature_n --> feature_a_service
feature_n --> feature_b_service
Phase Five: Focus on Functionality#
Register functionalities in the market, and the app automatically discovers them.
package framework{
package apps{
component app
}
component common
component services {
component feature_a_service
component feature_b_service
component feature_n_service
}
}
package features{
component feature_a
component feature_b
component feature_n
}
features --> common
app --> feature_a
app --> feature_b
app --> feature_n
feature_a --> feature_a_service
feature_b --> feature_b_service
feature_n --> feature_n_service