Componentization of JD.com App for HarmonyOS: Architecture, Challenges, and Implementation
This article details the evolution of JD.com’s HarmonyOS app from a monolithic project to a modular componentized architecture, describing the existing structure, encountered build and resource issues, the Android plugin reference solution, the proposed HarmonyOS componentization scheme, implementation steps, and release packaging.
In June 2021 JD.com released the first HarmonyOS version of its app using a hybrid package approach, and to date has published 13 versions covering features such as search, product details, activity center, coupon center, payment code, and live streaming. Many more business units are planning to adopt HarmonyOS atomic features.
The current project structure follows the official recommendation: a single Entry module with multiple Feature modules, each of which can be compiled and run independently or packaged together. An illustration of this structure is shown in the original article.
As more business modules are added, several problems arise: increasingly long compilation times, configuration or compilation failures in one module affecting the whole app, heterogeneous development languages and environment configurations, the need for full regression testing when adding or removing modules, and code conflicts due to lack of repository isolation. These issues mirror those previously encountered in Android projects, leading to the adoption of Android componentization and plugin solutions.
The Android plugin solution used in JD.com’s app is built on the Aura platform, which provides a plugin framework, a compilation platform, and a backend management platform. Key concepts include a shared library (aar), independent plugin projects, and a host application. The standard plugin project layout is:
bundle-demoA
├── application // Android Application module
│ └── build.gradle
├── library // Android Library module
│ └── build.gradle
├── build.gradle
├── gradle.properties
├── local.properties
└── settings.gradlePlugins are built as APKs, uploaded to a Maven repository, and the host retrieves the appropriate versions during its own build.
Inspired by this, a HarmonyOS componentization approach was explored. In Debug mode, a HarmonyOS app consists of one entry.hap and multiple feature.hap files; in Release mode it is packaged as an .app containing the same HAPs plus pack.info and pack.res .
Two possible schemes were considered:
Extract Feature modules into separate code projects, compile them into .har packages, and let the main project depend on them. This loses HarmonyOS’s atomic installation advantage.
Extract Feature modules into independent projects, compile them into .hap packages that retain atomic installation, then aggregate the HAPs in the main project. This scheme was chosen.
The implementation steps include:
Separate the Search and Activity Calendar modules into independent projects and upload their HAPs to a private Maven repository.
Create a custom Gradle task to download and copy the HAPs into the main project. Example code:
def downloadDep(String artifact) {
def map = [:]
//1 Create dependency object from Maven coordinates
Dependency dependency = project.dependencies.create(artifact)
//2 Create a detached configuration without adding it to the project
Configuration configuration = project.configurations.detachedConfiguration(dependency)
//3 Disable transitive dependencies for HAP files
configuration.setTransitive(false)
//4 Download the artifact files
configuration.files.each { file ->
if (file.isFile()) {
map['depFile'] = file
map['depName'] = dependency.getName()
} else {
println "Could not find the file corresponding to the artifact '$artifact'"
}
}
return map
}
def copyToTarget(File depFile, String depName) {
project.copy {
from depFile
into hapsDir
}
}
ohoshap_dependencies {
artifact 'xxx.xxx.xxx:searchfeature:1.0.0'
artifact 'xxx.xxx.xxx:activityfeature:1.0.0'
}After configuring these tasks, running assembleDebug pulls the component HAPs into the build directory, and they can be installed via hdc . An initial UI issue (resource ID conflict) was discovered and resolved by adjusting resource IDs.
Resource ID handling is critical. In Android, a resource ID consists of PackageId, TypeId, and EntryId. To avoid conflicts, the Aura plugin modifies each plugin’s PackageId. For HarmonyOS, the team decompiled the build plugin and found the method setFeaturePackageId in com.huawei.ohos.build.utils.FeatureUtils , which sets a starting PackageId (e.g., 0x80 ) for each feature. A Gradle task was added to print and modify these IDs, e.g.:
task test {
doLast {
com.huawei.ohos.build.data.GlobalDataManager.featurePackageId.each {
println "${it.key} ==> ${it.value}"
}
}
}By assigning unique PackageIds (e.g., 0xA6 for Search, 0xA5 for Activity Calendar) before compilation, the UI displayed correctly.
For Release builds, the signReleaseApp command generates an .app file containing multiple HAPs, pack.info , and pack.res . The pack.info JSON aggregates module metadata, while pack.res is created by the hmos_app_packing_tool.jar using the command:
java -jar /xxx/harmony/SDK/toolchains/lib/hmos_app_packing_tool.jar \
--mode res \
--pack-info-path /xxx/build/outputs/app/release/pack.info \
--entrycard-path /xxx/EntryCard \
--out-path /xxx/build/outputs/app/release/pack.res --force trueThe final unsigned app is assembled with:
java -jar /xxx/harmony/SDK/toolchains/lib/hmos_app_packing_tool.jar \
--mode app \
--hap-path a.hap,b.hap,c.hap,... \
--pack-info-path /xxx/pack.info \
--pack-res-path /xxx/pack.res \
--out-path /xxx/release-unsigned.app --force trueSigning is performed using the same tool in app mode. The complete Release component integration flow is illustrated in the article’s diagram.
In summary, the original monolithic structure required over three minutes to build 11 modules, whereas the componentized approach reduces build time to about 35 seconds. The modularization aligns JD.com’s release process with standard Android practices, allowing independent component development and timely integration. Future work includes collaborating with Huawei DevEco to obtain official tooling for resource‑ID configuration, ensuring a robust multi‑repository componentization solution.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.