DEV Community

HarmonyOS
HarmonyOS

Posted on

Development Setup Design: Structuring Build Variants for Multi-Device HarmonyOS Applications

Read the original article:Development Setup Design: Structuring Build Variants for Multi-Device HarmonyOS Applications

Context

HarmonyOS enables developers to build applications that seamlessly adapt across a wide range of devices, from phones to tablets, smart screens, wearables, and more. A key part of this development strategy involves structuring build variants to efficiently manage different device configurations and deployment environments. This approach ensures optimized performance and consistent user experience across the HarmonyOS ecosystem.

Description

Creating build variants for multi-device HarmonyOS applications involves defining configurations that can adapt to different hardware capabilities, resource availability, and user experience requirements. This process typically includes setting up build profiles, defining device-specific resources, and utilizing HarmonyOS tools such as Hvigor for efficient build customization. The goal is to maintain a single codebase that can be compiled into device-specific packages, ensuring optimal resource usage and performance.

Solution

To effectively structure build variants for multi-device HarmonyOS applications, developers should follow these steps:

1. Define Build Profiles: Utilize the build-profile.json5 file to specify different build configurations for various environments, such as debug and release. This file allows developers to set up signing configurations, target SDK versions, and other product-level settings that are crucial for multi-device support

   {
     "app": {
       "signingConfigs": [
           {
               "name": "release",
               "type": "HarmonyOS",
               "material": {
                   "certpath": "/path/to/cert.cer",
                   "storePassword": "password",
                   "keyAlias": "alias",
                   "keyPassword": "password"
               }
           }
       ],
       "products": [
         {
           "name": "default",
           "signingConfig": "default",
           "targetSdkVersion": "5.1.0(18)",
           "compatibleSdkVersion": "5.1.0(18)",
           "runtimeOS": "HarmonyOS",
           "buildOption": {
             "strictMode": {
               "caseSensitiveCheck": true,
               "useNormalizedOHMUrl": true
             }
           }
         }
       ],
       "buildModeSet": [
         {
           "name": "debug",
         },
         {
           "name": "release"
         }
       ]
     },
     "modules": [
       {
         "name": "entry",
         "srcPath": "./entry",
         "targets": [
           {
             "name": "phone",
             "applyToProducts": ["default"]
           },
           {
             "name": "tablet",
             "applyToProducts": ["default"]
           },
           {
             "name": "wearable",
             "applyToProducts": ["default"]
           }
         ]
       }
     ]
   }
Enter fullscreen mode Exit fullscreen mode

2. Configure Device-Specific Resources: In the module.json5 file, define different resource directories for various device types. This ensures that the application can adapt its UI and functionality based on the target device’s characteristics

   // module.json5
   {
     "module": {
       "name": "entry",
       "type": "entry",
       "deviceTypes": ["phone", "tablet", "wearable"],
       "abilities": [
         {
           "name": "MainAbility",
           "srcEntry": "./ets/mainability/MainAbility.ets",
           "description": "$string:MainAbility_desc",
           "icon": "$media:icon",
           "label": "$string:MainAbility_label",
           "exported": true,
           "skills": [
             {
               "entities": ["entity.system.home"],
               "actions": ["action.system.home"]
             }
           ]
         }
       ]
     }
   }
Enter fullscreen mode Exit fullscreen mode

3. Implement Conditional Compilation: Use conditional compilation to include or exclude code based on the target device or environment. This technique helps reduce the application’s size and improve performance by only including necessary code

   {
     "apiType": "stageMode",
     "buildOption": {
       "resOptions": {
         "copyCodeResource": {
           "enable": false
         }
       }
     },
     "buildOptionSet": [
       {
         "name": "release",
         "arkOptions": {
           "obfuscation": {
             "ruleOptions": {
               "enable": false,
               "files": [
                 "./obfuscation-rules.txt"
               ]
             }
           }
         }
       }
     ],
     "targets": [
       {
         "name": "phone",
         "config": {
           "buildOption": {
             "arkOptions": {
               "buildProfileFields": {
                 "DEVICE_TYPE": "config_phone"
               }
             }
           }
         }
       },
       {
         "name": "tablet",
         "config": {
           "buildOption": {
             "arkOptions": {
               "buildProfileFields": {
                 "DEVICE_TYPE": "config_tablet"
               }
             }
           }
         }
       },
        {
         "name": "wearable",
         "config": {
           "buildOption": {
             "arkOptions": {
               "buildProfileFields": {
                 "DEVICE_TYPE": "config_wearable"
               }
             }
           }
         }
       }
     ]
   }
Enter fullscreen mode Exit fullscreen mode

Generate module build profile and make module

build1.png

Generated build profile is under build folder:

build2.png

4. Usage in ArkTS code: You can check your target build in ArkTS dynamically:

   // You can import BuildProfile after generating BuildProfile
   import BuildProfile from 'entry/BuildProfile';

   @Entry
   @Component
   struct Index {
     build() {
       RelativeContainer() {
         Text(BuildProfile.TARGET_NAME) // it will either phone or wearable accordingly the build you have chosen
           .id('HelloWorld')
           .fontSize($r('app.float.page_text_font_size'))
           .fontWeight(FontWeight.Bold)
           .alignRules({
             center: { anchor: '__container__', align: VerticalAlign.Center },
             middle: { anchor: '__container__', align: HorizontalAlign.Center }
           })
       }
       .height('100%')
       .width('100%')
     }
   }
Enter fullscreen mode Exit fullscreen mode

on Phone:

phone.png

on Wearable:

wearables-0.png

5. Test Across Devices: Regularly test the application on different devices to ensure that it performs optimally and provides a consistent user experience. This step is crucial for identifying and addressing any issues that may arise due to device-specific differences

cke_4483.png

Key Takeaways

  • Single codebase for multiple device types
  • Environment-specific configuration through build-profile.json5
  • Device adaptation via module.json5 resource definitions
  • Hvigor enables advanced build customization
  • CI/CD integration streamlines deployment

References

Written by Taskhyn Maksim

Top comments (0)