DEV Community

Cover image for HarmonyOS Multi-Target Artifact Construction Best Practices
kouwei qing
kouwei qing

Posted on • Edited on

HarmonyOS Multi-Target Artifact Construction Best Practices

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"  
          ]  
        }  
      ]  
    }  
  ]  
}
Enter fullscreen mode Exit fullscreen mode

The modules list declares modules with:

  • name: Module name
  • srcPath: Module path
  • targets: Build targets

Notes: Differences from Android:

  1. Only one entry module is allowed per project (e.g., creating two demo modules in an SDK project is prohibited).
  2. 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",  
    }  
  ]  
}
Enter fullscreen mode Exit fullscreen mode
  • 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"  
          }  
        ],  
      }  
    ]  
  }  
}
Enter fullscreen mode Exit fullscreen mode

Similar to AndroidManifest, it declares module information and device types:

Official Recommended Module Structure

Flat directory module management has two drawbacks:

  1. Messy project logic structure
  2. 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
     └── ...
Enter fullscreen mode Exit fullscreen mode

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"  
        ]  
      }  
    ]  
  }
]
Enter fullscreen mode Exit fullscreen mode

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.

Reference Documents

  1. https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-customized-multi-targets-and-products-guides-0000001731595144-V5#section2554174114463
  2. https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-using-V5

Top comments (0)