HarmonyOS鸿蒙Next中同一个har包兼容元服务和应用两种场景解决方案-差异化构建

HarmonyOS鸿蒙Next中同一个har包兼容元服务和应用两种场景解决方案-差异化构建 开发中经常遇到一种场景,同一个har包,原本是作为二方或三方sdk,可支持所有项目使用,但是某些场景元服务和应用可能会存在一些区别。比如元服务不能使用常规Web组件,虽然使用时看效果没问题,但是元服务上架审核会被打回,要求使用AtomicServiceWeb组件。

AtomicServiceWeb组件能力相比Web组件会少一些,所以大概率要选择应用中依然使用Web组件实现所有相关能力,元服务中使用AtomicServiceWeb组件实现部分能够支持的能力,就会出现这个har包需要根据元服务和应用两种构建目标来使用不同代码资源打包的问题。

又或者是元服务中不能使用数据库等API,只要有,编译就会报错,或者编译不会报错,但是上架审核会被打回,说你的元服务使用了某些不支持的API要求修改,这些场景也是需要差异化构建的。

我们可以通过开发工具构建流程中,可配置多目标产物能力,也就是可定义产物的source源码集-sourceRoots,来区分不同构建目标的打包构建代码集。

那么怎么进行差异化构建,官方文档说的算是比较清楚了,具体参考官方配置文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-customized-multi-targets-and-products-guides#section13344184411593

以下举例中,默认已存在的har模块为webcomponent,也就是需要差异化构建的har模块,entry模块依赖了webcomponent模块,并使用了其中导出的WebView组件。

第一步:项目级build-profile.json5文件中,配置需要的不同products目标app和atomicservice,此处简单距离,直接复制了默认的default配置修改了以下name,具体如下:

{
    "app": {
        "signingConfigs": [ ], 
        "products": [
            {
                "name": "default", 
                "signingConfig": "default", 
                "targetSdkVersion": "5.0.5(17)", 
                "compatibleSdkVersion": "5.0.0(12)", 
                "runtimeOS": "HarmonyOS", 
                "buildOption": {
                    "strictMode": {
                        "caseSensitiveCheck": true, 
                        "useNormalizedOHMUrl": false
                    }
                }
            }, 
            {
                "name": "app", 
                "signingConfig": "default", 
                "targetSdkVersion": "5.0.5(17)", 
                "compatibleSdkVersion": "5.0.0(12)", 
                "runtimeOS": "HarmonyOS", 
                "buildOption": {
                    "strictMode": {
                        "caseSensitiveCheck": true, 
                        "useNormalizedOHMUrl": false
                    }
                }
            }, 
            {
                "name": "atomicservice", 
                "signingConfig": "default", 
                "targetSdkVersion": "5.0.5(17)", 
                "compatibleSdkVersion": "5.0.0(12)", 
                "runtimeOS": "HarmonyOS", 
                "buildOption": {
                    "strictMode": {
                        "caseSensitiveCheck": true, 
                        "useNormalizedOHMUrl": false
                    }
                }
            }
        ],
        ******
    },
    ******
}

配置完products以后查看项目product配置就已经可以看到我们添加的两种构建目标了:

配置完products以后查看项目product配置就已经可以看到我们添加的两种构建目标了:

第二步:还是项目级build-profile.json5文件中,要同时在modules中对entry和webcomponent配置对应的targets,只配置webcomponent是不行的,webcomponent是har包,不是hsp或者feature,编译时har的targets配置会根据上层依赖者的targets配置来确定:

{
  "app": {
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        },
        {
          "name": "app",
          "applyToProducts": [
            "app"
          ],
        },
        {
          "name": "atomicservice",
          "applyToProducts": [
            "atomicservice"
          ]
        }
      ]
    },
    {
      "name": "webcomponent",
      "srcPath": "./webcomponent",
      "targets": [
        {
          "name": "app",
          "applyToProducts": [
            "app"
          ],
        },
        {
          "name": "atomicservice",
          "applyToProducts": [
            "atomicservice"
          ]
        }
      ]
    }
  ]
}

第三步:entry模块的build-profile.json5文件中配置entry模块的targets,新增对应的app和atomicservice:

{
  "apiType": "stageMode",
  "buildOption": {
  },
  "buildOptionSet": [
  ],
  "targets": [
    {
      "name": "default"
    },
    {
      "name": "app"
    },
    {
      "name": "atomicservice"
    }
  ]
}

配置完成后,当我们选择不同的构建目标product,entry就会同步变化,比如选择构建目标为app时,entry也会自动变为app:

第四步:webcomponent模块中创建app和atomicservice的代码文件夹和文件:

app.ets.WebComponent.ets代码如下:

import { webview } from "@kit.ArkWeb";

@Component
export struct WebComponent {
  build() {
    Column() {
      Text("App Web").width("100%").textAlign(TextAlign.Center)
      Web({
        src: "https://m.baidu.com/s?pd=note&word=%E7%BE%8E%E5%A5%B3&sa=vs_tab&lid=8604505960788238529&ms=1&tab_se=1&atn=index&from=1019311v",
        controller: new webview.WebviewController()
      }).width("100%").height("100%")
    }
  }
}

atomicservice.ets.WebComponent.ets代码如下:

import { AtomicServiceWeb, AtomicServiceWebController } from "@kit.ArkUI";

@Component
export struct WebComponent {
  @State controller: AtomicServiceWebController = new AtomicServiceWebController();

  build() {
    Column() {
      Text("AtomicService Web").width("100%").textAlign(TextAlign.Center)
      AtomicServiceWeb({
        src: "https://m.baidu.com/sf/vsearch?pd=image_content&word=%E9%AB%98%E8%BE%BE&tn=vsearch&sa=vs_tab&lid=8425942635192265082&ms=1&from=1019311v&atn=page&fr=tab",
        controller: this.controller
      }).width("100%").height("100%")
    }
  }
}

第四步:webcomponent模块的build-profile.json5文件中配置对应targets,相比entry的targets配置,这里要多出对应的代码集目标配置,实现不同product构建目标打包使用不同代码集的目标,default不能删,默认使用app代码集,具体配置如下:

{
  "apiType": "stageMode",
  "buildOption": {
  },
  "buildOptionSet": [
  ],
  "targets": [
    {
      "name": "default",
      "source": {
        "sourceRoots": [
          "./src/app"
        ]
      }
    },
    {
      "name": "app",
      "source": {
        "sourceRoots": [
          "./src/app"
        ]
      }
    },
    {
      "name": "atomicservice",
      "source": {
        "sourceRoots": [
          "./src/atomicservice"
        ]
      }
    }
  ]
}

第七步,webcomponent模块的main.ets.component.WebView.ets组件代码中,引用WebComponent组件,引用方式注意使用模块名+路径的方式,如下:

import { WebComponent } from "webcomponent/ets/WebComponent";

@Component
export struct WebView {
  build() {
    WebComponent()
  }
}

至此所有配置已完成,选择不同的构建目标查看效果:

选择product为app,配置以及运行结果:

通过text组件文本可以确定使用的代码集为app,差异化构建成功。

选择product为atomicService,配置以及运行结果:

通过text组件文本可以确定使用的代码集为atomicservice,差异化构建成功。剩下的就是我们针对不同场景选择不同的product构建webcomponent模块的har包了。

代码以及资源、so等基本都可以进行差异化配置,具体可以查看官方文档。目前唯一觉得美中不足的是不能根据选择的构建目标差异化配置不同dependencies引用,不同dependencies引用只能使用parameterFile等,使用上个人感觉跟每次注释和放开不同dependencies引用代码块没区别。


更多关于HarmonyOS鸿蒙Next中同一个har包兼容元服务和应用两种场景解决方案-差异化构建的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中,可通过配置差异化构建实现har包同时支持元服务和应用场景。在module.json5中使用"buildMode"字段区分构建模式:"module"对应元服务,"entry"对应应用。定义不同构建变体,通过条件编译和资源隔离实现功能差异化。使用oh-package.json5管理依赖,通过"buildProfile"指定不同构建配置。在ArkTS中使用动态导入和运行时API检测判断当前运行环境。构建时通过--mode参数指定构建目标,如hvigor build --mode module

更多关于HarmonyOS鸿蒙Next中同一个har包兼容元服务和应用两种场景解决方案-差异化构建的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对HarmonyOS Next中同一个har包兼容元服务和应用的差异化构建需求,解决方案已非常清晰。关键步骤如下:

  1. 在项目级build-profile.json5中配置多目标products(app和atomicservice),并同步配置modules的targets映射关系。注意har模块的targets必须与上层entry模块保持一致。

  2. 在har模块中创建不同场景的代码目录(如app/和atomicservice/),分别实现WebComponent组件:

  • app场景使用@kit.ArkWeb的Web组件
  • 元服务场景使用@kit.ArkUI的AtomicServiceWeb组件
  1. 关键配置点在har模块的build-profile.json5中,通过sourceRoots指定不同target对应的源码路径:
"targets": [
  {
    "name": "app",
    "source": {"sourceRoots": ["./src/app"]}
  },
  {
    "name": "atomicservice", 
    "source": {"sourceRoots": ["./src/atomicservice"]}
  }
]
  1. 组件导出时需使用完整模块路径(如"webcomponent/ets/WebComponent")

该方案已验证可正常运行,通过构建目标切换会自动选择对应源码目录。对于依赖库差异化问题,目前确实需要通过parameterFile或手动注释等方式处理,期待后续工具链增强该能力。

回到顶部