DEV Community

ZHZL-m
ZHZL-m

Posted on

【Journey of HarmonyOS Next】DevEco Studio User Guide (35) -> Configuration and Build (2)

Image description

1-> Customized HAP multi-objective construction products

Each Entry/Feature module supports customization of different targets, and by implementing differentiated customization in the build-profile.json5 file in the module, it currently supports HAP package name, device type (deviceType), source code set (source), resource (resource), buildOption configuration items (such as C++ dependent .so, obfuscated configuration, abi type, cppFlags, etc.), distribution rules (distributionFilter) customization.

Define the target product

Each target corresponds to a customized HAP, so you should plan the target name that needs to be customized in advance before customizing the HAP multi-target construction product. For example, if you use the ArkTS Stage model as an example, you can define a free version and a paid version, and the module-level build-profile.json5 file is as follows:

{ 
  "apiType": 'stageMode', 
  "buildOption": {   
  }, 
  "targets": [  //定义不同的target 
    { 
      "name": "default",  //默认target名称default 
    }, 
    { 
      "name": "free",  //免费版target名称 
    }, 
    { 
      "name": "pay",  //付费版target名称 
    } 
  ] 
}
Enter fullscreen mode Exit fullscreen mode

According to the definition of the target above, three different HAPs of default, free and pay will be generated at the same time during compilation and construction.

1.1 -> Define the HAP package name of the product

Each target can be named with a product.

{ 
  "apiType": "stageMode", 
  "buildOption": { 
  }, 
  "targets": [ 
    { 
      "name": "default", 
      "output": { 
        "artifactName": "customizedTargetOutputName-1.0.0"  //产物名称为customizedTargetOutputName-1.0.0
      } 
    }, 
    { 
      "name": "free", 
      "output": { 
        "artifactName": "customizedTargetOutputName1-1.0.0"  //产物名称为customizedTargetOutputName1-1.0.0
      } 
    }, 
    { 
      "name": "pay", 
      "output": { 
        "artifactName": "customizedTargetOutputName2-1.0.0"  //产物名称为customizedTargetOutputName2-1.0.0
      } 
    } 
  ] 
}
Enter fullscreen mode Exit fullscreen mode

If a signature is configured, the HAP package name corresponding to the target product is the name customized by the developer. If no signature is configured, the HAP package name of the target product is the name customized by the developer + unsigned.

1.2 -> Define the deviceType of the product

Each target can be specified with or without deviceType. If it is not defined, the target supports the device type defined in config.json or module.json5 by default.

At the same time, when defining the deviceType of each target, the supported device types must have been defined in config.json or module.json5. For example, in the three targets defined above, default supports all device types by default, and the free and pay versions support only phone devices.

{ 
  "apiType": 'stageMode', 
  "buildOption": { 
  }, 
  "targets": [ 
    { 
      "name": "default",  //未定义deviceType,默认支持config.json或module.json5中定义的设备类型 


    }, 
    { 
      "name": "free", 
      "config": { 
        "deviceType": [  //定义free支持的设备类型为phone 
          "phone" 
        ] 
      } 
    }, 
    { 
      "name": "pay", 
      "config": { 
        "deviceType": [  //定义pay支持的设备类型为phone 
          "phone" 
        ] 
      } 
    } 
  ] 
}
Enter fullscreen mode Exit fullscreen mode

1.3 -> Define the distributionFilter of the product

If the distribution rule of the target is not defined, the distroFilter/distributionFilter distribution rule of the module configuration shall prevail.

If multiple targets have the same device type, you need to specify the distributionFilter distribution rule for targets of the same device type.

If the project is an FA project, replace the distributionFilter field with distroFilter.

{ 
  "apiType": "stageMode", 
  "buildOption": { 
  }, 
  "targets": [ 
    { 
      "name": "default", 


    }, 
    { 
      "name": "free", 
      "config": { 
        "distributionFilter": {  // 具体请参考distributionFilter标签
          "screenShape": { // 屏幕形状枚举 
            "policy": "include", 
            "value": ["circle"] 
          } 
        } 
      } 
    }, 
    { 
      "name": "pay", 
      "config": { 
        "distributionFilter": { 
          "screenShape": { 
            "policy": "include", 
            "value": ["rect"] 
          } 
        } 
      } 
    } 
  ] 
}
Enter fullscreen mode Exit fullscreen mode

1.4 -> Define the subcontracting of product preloads

For metaservices, each target can specify the subcontracting of preloads, or it may not be defined. If not, the configuration in module.json5 prevails.

{ 
  "apiType": 'stageMode', 
  "showInServiceCenter": true, 
  "buildOption": { 
  }, 
  "targets": [   
    { 
      "name": "default",   
    },
    { 
      "name": "free",   
    },
    { 
      "name": "pay",   
      "config": { 
        "atomicService": { 
          "preloads": [  //指定preloads的分包 
            { 
              "moduleName": "preloadSharedLibrary"
            } 
          ] 
        } 
      } 
    } 
  ] 
}
Enter fullscreen mode Exit fullscreen mode

1.5 -> Define the source set of the product -pages

For source code set customization, due to the differences between the Stage model and the FA model, the Stage model supports customization of the page page in the pages source code directory, and the FA model supports the customization of the page page in the Ability source code directory.

For example, for a project in the Stage model, three pages are defined in the pages directory of the module: Index.ets, Page1.ets, and Page2.ets. The Index.ets page is used for default, the Index.ets and Page1.ets pages are used for free, and the Index.ets and Page2.ets pages are used for pay.

{ 
   "apiType": 'stageMode', 
   "buildOption": { 
   }, 
   "targets": [ 
     { 
       "name": "default", 
       "source": {  //定义Stage模型中默认版target的pages源码文件
         "pages": [ 
           "pages/Index" 
         ] 
       } 
     }, 
     { 
       "name": "free", 
       "config": { 
         "deviceType": [ 
           "phone" 
         ] 
       }, 
       "source": {  //定义Stage模型中免费版target的pages源码文件
         "pages": [ 
           "pages/Index", 
           "pages/Page1" 
         ] 
       } 
     }, 
     { 
       "name": "pay", 
       "config": { 
         "deviceType": [ 
           "phone" 
         ] 
       }, 
       "source": {  //定义Stage模型中付费版target的pages源码文件
         "pages": [ 
           "pages/Index", 
           "pages/Page2" 
         ] 
       } 
     } 
   ] 
 }
Enter fullscreen mode Exit fullscreen mode

For example, in the FA model, index.ets, page1.ets, and page2.ets are defined in the MainAbility of the module, where the index.ets page is used for default. free uses the index.ets and page1.ets pages, and pay uses the index.ets and page2.ets pages.

{ 
   "apiType": 'faMode', 
   "buildOption": { 
   }, 
   "targets": [ 
     { 
       "name": "default", 
       "source": {  //定义FA模型中默认版target的pages源码文件
         "abilities": [ 
           { 
             "name": ".MainAbility", 
             "pages": [ 
               "pages/index" 
             ] 
           } 
         ], 
       } 
     }, 
     { 
       "name": "free", 
       "config": { 
         "deviceType": [ 
           "phone" 
         ] 
       }, 
       "source": {  //定义FA模型中免费版target的pages源码文件
         "abilities": [ 
           { 
             "name": ".MainAbility", 
             "pages": [ 
               "pages/index", 
               "pages/page1" 
             ] 
           } 
         ], 
       } 
     }, 
     { 
       "name": "pay", 
       "config": { 
         "deviceType": [ 
           "phone" 
         ] 
       }, 
       "source": {  //定义FA模型中付费版target的pages源码文件
         "abilities": [ 
           { 
             "name": ".MainAbility", 
             "pages": [ 
               "pages/index", 
               "pages/page2" 
             ] 
           } 
         ], 
       } 
     } 
   ] 
 }
Enter fullscreen mode Exit fullscreen mode

1.6 -> Define the source source set of the product -sourceRoots

In the main code space (src/main) of the module, the public code written by the developer is hosted. If developers need to implement differentiated logic between different targets, they can use the differentiated codespace (sourceRoots). Combined with the ability of differentiated code space, you can compile the corresponding code into the final product for different targets under the condition that the code in the main code space remains unchanged.

Concept note

packageName: the value of the name field in oh-package.json5 of the current module.
sourceRoot: | where the is src/main, is customizable, and the addressing priority is > .
sourcePath: the directory of the code structure in sourceRoot.
sourceFileName: the name of the ets file in the code directory.
For example, the following project catalog:

entry
|--src
|----main
|------ets
|--------code
|----------test.ets
|----target
|------util
|--------util.ets
|--index.ets

packageName is entry.
sourceRoot is src/main and src/target.
sourcePath is set to ets/code and util.
sourceFileName is test.ets and util.ets.
Specification limitations

  1. import xxx from '/sourcePath/sourceFileName': By using packageName, sourceRoot can be omitted to achieve differentiated construction under different targets.

  2. Support hap, hsp, har (please note: the har module that enables file/folder name confusion needs to use -keep-file-name to specify sourceRoot, sourcePath, and the file/folder names corresponding to sourceFileName are not confused).

  3. Cross-module references are not supported.

  4. Dynamic import is not supported.

Description of the priority of module target selection at compile time

During the compilation of a module, the sourceRoots used by the module is determined by the target at the time of compilation of the current module. The priority of selecting target during the compilation of the current module is as follows: explicitly specify the > direct reference target > default on the command line.

For example:

hap -> hsp -> har (-> indicates dependency)

Among them, HAP and HSP have three targets: Default, Custom, and Static, while HAR has two targets: Default and Static.

Run the compilation command: hvigorw -p module=hap@custom assembleHap, hap specifies the target as custom for compilation, then the targets of the three modules are as follows:
hap: custom, explicitly specified by the command line;

hsp: custom, if the command line is not explicitly specified, the search is based on the direct referrer, the direct referrer of hsp is hap, the target of hap is custom, and the target of hsp exists, then the target of hsp is custom;

har: default, if the command line does not explicitly specify it, then the search is based on the direct referrer, the direct referrer of har is hsp, the target of hsp is custom, and the target of har does not exist, then the target of har is default;

Run the compilation command: hvigorw -p module=hap@custom, hsp@static assembleHap assembleHsp, hap specifies target as custom, hsp specifies target as static for compilation, then the targets of the three modules are as follows:
hap: custom, explicitly specified by the command line;

hsp: static, explicitly specified by the command line;

har: static, if the command line does not explicitly specify it, the search is based on the direct referrer, the direct referrer of har is hsp, the target of hsp is static, and the target of har is static.

On top of the current dependency, add the dependency: hap -> har. Run the compilation command: hvigorw -p module=hap@custom, hsp@static assembleHap assembleHsp. Since the HAR does not display the specified target, and there are two direct references to different targets (HAP and HSP, corresponding targets are custom and static, respectively), you can only choose one of the targets of HAR during the compilation process. Based on this scenario, it is recommended that developers display the target of the specified module for compilation: hvigorw -p module=hap@custom, hsp@static, har@static assembleHap assembleHsp assembleHar.
example

  1. Add sourceRoots to build-profile.json5 of the entry module:
{
  "apiType": "stageMode",
  "buildOption": {},
  "targets": [ 
    { 
      "name": "default", 
      "source": { 
        "sourceRoots": ["./src/default"] // 配置target为default的差异化代码空间
      } 
    }, 
    { 
      "name": "custom", 
      "source": { 
        "sourceRoots": ["./src/custom"] // 配置target为custom的差异化代码空间
      } 
    } 
  ]
}
Enter fullscreen mode Exit fullscreen mode
  1. Add default/Test.ets and custom/Test.ets to the src directory, and add the following module directory structure:

entry
|--src
|--main
|--ets
|--pages
|--index.ets
|--default
|--Test.ets // added
|--custom
|--Test.est // New

  1. Write the code in default/Test.ets:
export const getName = () => "default"

Enter fullscreen mode Exit fullscreen mode
  1. Write the code in custom/Test.ets:
export const getName = () => "custom"

Enter fullscreen mode Exit fullscreen mode
  1. Modify the code of src/main/ets/pages/Index.ets:
import { getName } from 'entry/Test'; // 其中entry为模块级的oh-package.json5中的name字段的值
@Entry
@Component
struct Index { 
  @State message: string = getName(); 
  build() { 
    RelativeContainer() { 
      Text(this.message) 
    } 
    .height('100%') 
    .width('100%') 
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Configure targets in project-level build-profile.json5:
{
  "app": {
    "signingConfigs": [],
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "compatibleSdkVersion": "5.0.2(14)",
        "runtimeOS": "HarmonyOS",
      },
      {
        "name": "custom",
        "signingConfig": "default",
        "compatibleSdkVersion": "5.0.2(14)",
        "runtimeOS": "HarmonyOS",
      }
    ],
    "buildModeSet": [
      {
        "name": "debug",
      },
      {
        "name": "release"
      }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        },
        {
          "name": "custom",
          "applyToProducts": [
            "default"
          ]
        }
      ]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode
  1. After Sync is complete, select the target of the entry as default, click Run, and the interface will display default. Set the target of entry to custom and click Run to display custom.

1.7 -> Define the resources of the product

There may be differences in the resource files used by each target, and developers can store the resources used by each target in different resource directories during the development process. Among them, the ArkTS project supports customization of the resource file directory in the main directory. JS projects support customization of the resource file directory in the main directory and the resource file directory (res) in the ability directory. The following is an example of customizing the resource file directory of an ArkTS project:

{ 
  "apiType": 'stageMode', 
  "buildOption": { 
  }, 
  "targets": [ 
    { 
      "name": "default", 
      "source": { 
        "pages": [ 
          "pages/Index" 
        ] 
      }, 
      "resource": {  //定义默认版target使用的资源文件目录 
        "directories": [ 
          "./src/main/resources_default" 
        ] 
      } 
    }, 
    { 
      "name": "free", 
      "config": { 
        "deviceType": [ 
          "phone" 
        ] 
      }, 
      "source": {   
        "pages": [ 
          "pages/Index", 
          "pages/Page1" 
        ] 
      }, 
      "resource": {  //定义免费版target使用的资源文件目录 
        "directories": [ 
          "./src/main/resources_default", 
          "./src/main/resources_free" 
        ] 
      } 
    }, 
    { 
      "name": "pay", 
      "config": { 
        "deviceType": [ 
          "phone" 
        ] 
      }, 
      "source": {   
        "pages": [ 
          "pages/Index", 
          "pages/Page2" 
        ] 
      }, 
      "resource": {  //定义付费版target使用的资源文件目录,该功能在API 9及以上版本的工程中生效 
        "directories": [ 
          "./src/main/resources_default", 
          "./src/main/resources_pay" 
        ] 
      } 
    } 
  ] 
}
Enter fullscreen mode Exit fullscreen mode

Note that if there are resources with the same name in multiple resource file directories referenced by target, the resource file directories will be selected in the order of the configured resource file directories during the build and packaging process. For example, if there are resource files with the same name in the resource_default and resource_pay of the resources referenced by the target of the preceding paid edition, the resources in the resource_default are packaged into HAP.

1.8 -> Define the icon, label, and launchType of the product

For each target's ability, different icons, labels, and launchTypes can be customized. If not defined, the target uses the icon and label configured in module.json5, and the launchType is singleton by default. An example is shown below:

{ 
   "apiType": 'stageMode', 
   "buildOption": { 
   }, 
   "targets": [ 
     { 
       "name": "default", 
       "source": {
        "abilities": [
          {
            "name": "EntryAbility",
            "icon":"$media:layered_image",
            "label":"$string:EntryAbility_label",
            "launchType": "singleton"
          }
        ]
      }
     }, 
     { 
       "name": "free", 
       "source": {
        "abilities": [
          {
            "name": "EntryAbility",
            "icon":"$media:layered_image",
            "label":"$string:EntryAbility_label",
            "launchType": "multiton"
          }
        ]
      }
     }
   ] 
 }
Enter fullscreen mode Exit fullscreen mode

1.9 -> Define the C++ engineering dependencies on the . SO file

In a C++ project, you can customize the .so files that each target depends on. For example, a module depends on the function1.so, function2.so, and function3.so files, and the product with target is default depends on the function1.so and function2.so. If the target is a product of VIP and depends on function1.so and function3.so, the sample code is as follows:

{
  "apiType": 'stageMode',
  "buildOption": {
    "externalNativeOptions": {
      "path": "./src/main/cpp/CMakeLists.txt",
      "arguments": [],
      "abiFilters": [
        "arm64-v8a",
        "x86_64"
      ],
      "cppFlags": "",
    }
  },
  "targets": [  //定义不同的target 
    {
      "name": "default",
      "config": {
        "buildOption": {
          "nativeLib": {
            "filter": {
              //按照.so文件的优先级顺序,打包最高优先级的function1.so文件 
              "pickFirsts": [
                "**/function1.so"
              ],
              //排除不打包的function3.so文件 
              "excludes": [
                "**/function3.so"
              ],
              //允许当.so中资源重名冲突时,使用高优先级的.so文件覆盖低优先级的.so文件 
              "enableOverride": true
            }
          }
        }
      }
    },
    {
      "name": "vip",
      "config": {
        "buildOption": {
          "nativeLib": {
            "filter": {
              //按照.so文件的优先级顺序,打包最高优先级的function1.so文件 
              "pickFirsts": [
                "**/function1.so"
              ],
              //排除不打包的function2.so文件 
              "excludes": [
                "**/function2.so"
              ],
              //允许当.so中资源重名冲突时,使用高优先级的.so文件覆盖低优先级的.so文件 
              "enableOverride": true
            }
          }
        }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

2-> Construct a defined target product

Each target corresponds to a HAP, and each product corresponds to an APP package.

Click in the top right corner

Image description

icon to specify the product and target to be packaged, and then click Apply to save. For example, if you select ProductA, the free" target corresponding to the entry module is selected.

Product: Select the app package to be built.
Build Mode: Select the build mode.
Product Info: the BundleName and SigningConfig of the app package.
Target Select: Select the target of each module, which needs to be included in the defined Product to be selected, if it is not included, "No Target to apply" is displayed.

Image description

Then perform the task of compiling and building the APP/HAP:

Click Build > Build Hap(s)/APP(s) > Build APP(s) in the menu bar to build the app corresponding to the specified product. For example, following the above settings, DevEco Studio will build an APP package that generates ProductA. Neither default nor ProductB apps will be generated.
Click Build > Build Hap(s)/APP(s) > Build Hap(s) in the menu bar to build the HAPs that are generated by all targets under the specified product. For example, according to the above configuration, DevEco Studio will build the default and free HAPs that generate the entry module.
If you want to package a specified target under a module to generate HAP, you can click the module name in the project directory, and then click Build > Make Module 'Module Name', and DevEco Studio will build the package corresponding to the specified target under the build module. For example, according to the preceding configuration, DevEco Studio will build the free HAP under the entry module, but will not generate the default HAP.

Image description

3 -> Debug and run the specified Target
When using DevEco Studio to debug or run an application/meta service, each module can only select one of the targets to run, which can be run by clicking in the upper right corner

Image description

icon to specify the corresponding Module Target under the Product to be debugged or run, and then click Apply to save.

illustrate

When you select a target that needs to be debugged or run, you need to select the Product to which the target belongs, otherwise you will not find a target that can be debugged and run.

Image description

Top comments (0)