HarmonyOS Multi-Target Artifact Construction Best Practices
Background
In Android or iOS development, there is often a need to create "Vest" packages (reskinned apps) from a single codebase for different themes or user groups. For example, Douyin has domestic and international versions, while Didi has personal and enterprise editions. Similarly, the HarmonyOS platform has similar requirements. This article discusses multi-artifact construction for HarmonyOS.
HarmonyOS Project Configuration File Description
Below is a screenshot of the simplest HarmonyOS project:
Project build-profile.json5
In a standard Android project, modules are declared in setting.gradle
. For HarmonyOS, module configurations are in build-profile.json5
:
{
"app": {
"signingConfigs": [],
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "5.0.0(12)",
"runtimeOS": "HarmonyOS",
}
],
"buildModeSet": [
{
"name": "debug",
},
{
"name": "release"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}
The modules
list declares modules with:
-
name
: Module name -
srcPath
: Module path -
targets
: Build targets
Notes: Differences from Android:
- Only one
entry
module is allowed per project (e.g., creating two demo modules in an SDK project is prohibited). -
srcPath
can only point to the project root or subdirectories (e.g., source dependency on modules from another project is not allowed).
Module build-profile.json5
{
"apiType": "stageMode",
"buildOption": {
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest",
}
]
}
-
apiType
: API model type-
stageMode
: Long-term evolution model (official recommendation) -
faMode
: FA model
-
-
buildOptionSet
: Compilation configuration (e.g., obfuscation rules) -
targets
: Build targets
module.json5
Example in module/main/module.json5
:
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
],
}
]
}
}
Similar to AndroidManifest, it declares module information and device types:
-
name
: Unique module identifier (≤31 bytes, no Chinese) -
type
: Module type (e.g.,entry
,feature
,har
,shared
) -
srcEntry
: Code path (≤127 bytes) -
deviceTypes
: Supported device categories -
deliveryWithInstall
: Whether to install with the app (true/false) - For more details, refer to: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/module-configuration-file-V5
Official Recommended Module Structure
Flat directory module management has two drawbacks:
- Messy project logic structure
- Unclear dependency relationships
The official recommends a three-layer structure:
/application
├── common # Common features directory
│
├── features # Functional modules directory
│ ├── feature1 # Sub-feature 1
│ ├── feature2 # Sub-feature 2
│ └── ... # Sub-feature n
│
└── product # Product layer directory
├── wearable # Wearable devices directory
├── default # Default devices directory
└── ...
Introduction to Product and Target
Before discussing multi-target artifact construction, understand target
and product
:
- Target: Each Entry/Feature module in a project, with build artifacts as HAPs (runnable on devices). A module can define multiple targets for customized HAPs (e.g., different functions/resources for the same module).
- Product: The build artifact of a HarmonyOS project is an APP package (for app market release). A project can define multiple products for customized APP packages.
Best Practices
Objective
Develop an SDK with two encapsulated sub-SDKs for ToB and ToC businesses. The three SDKs need to be debugged via three separate Demo projects in one workspace.
Solutions
Since only one runnable entry
module is allowed per HarmonyOS project, creating three separate demo modules is infeasible:
"modules": [
{
"name": "app",
"srcPath": "./app",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
},
{
"name": "app_c",
"srcPath": "./app_c",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
},
{
"name": "app_b",
"srcPath": "./app_b",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
Only the first module can run, even with three declared modules.
Solution 1
Comment/uncomment modules for debugging. Drawback: Requires code modifications for each debug switch.
Solution 2
Combine Biz2B and Biz2C into one module with two targets (2B/2C) via different code paths. Drawback: Incompatible with independent SDK requirements.
Solution 3
Define separate targets for Biz2B and Biz2C, configuring source paths in module-level build_profile.json5
with sourceRoots
. For example, the 2C target of the Biz2B module points to an empty path, ensuring no Biz2B code is included in 2C debugging.
Top comments (0)