羽球场边工具 HarmonyOS 元服务实战(01):元服务工程与 installationFree 配置
一、先确认元服务能力属于模块而不是首页按钮
场边临时组局时,用户需要快速打开计分、排阵或费用计算,而不是先理解一套完整应用的导航。这里的低摩擦入口并不是在页面上加一个“极速启动”文案,而是由模块配置声明交付形态。把这一层写进 module.json5,运行时首页只负责工具选择,工程边界才清晰。
],
"deliveryWithInstall": true,
"installationFree": true,
"metadata": [
{
"name": "client_id",
"value": "6917606123842596563"
}
],
"querySchemes": [
"https"
],
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
二、installationFree 与 deliveryWithInstall 表达什么
entry 模块同时声明 deliveryWithInstall 与 installationFree。前者描述模块随安装交付,后者允许系统按元服务能力处理入口;两项都位于 module 级配置,而不在 Index.ets 内部。若把它们误写成页面变量,即使卡片仍能渲染,也无法改变包的交付语义。
| 参与者 | 输入 | 输出或约束 |
|---|---|---|
| 模型或配置 | 稳定标识、模式或模块字段 | 给出可追溯的工程事实 |
| 服务或系统能力 | 经过归一化的请求 | 返回明确结果或失败原因 |
| 页面 | 回读后的结果 | 只渲染,不保存第二份事实 |
"tablet"
],
"deliveryWithInstall": true,
"installationFree": true,
"metadata": [
{
"name": "client_id",
"value": "6917606123842596563"
}
],
"querySchemes": [
"https"
],
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
三、首页工具如何避免承担分发判断
Index 页展示“羽球场边工具”、主应用工具箱、计分器等内容,并把点击分派到对应页面。它不判断安装包类型,也不拼装安装请求。这样计分状态、配对结果和费用输入仍是本地工具功能,分发和安装能力则由工程配置、签名及系统环境共同决定。
const MAIN_APP_LINK: string = 'https://kuqideharmonyos.drcn.agconnect.link/2m4d';
@Entry
@Component
struct Index {
@State recommendationExpanded: boolean = false;
@State showJumpFailure: boolean = false;
@State jumpFailureMessage: string = '主应用链接暂不可用,请稍后重试';
openMainApp(): void {
const context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
const owner: Index = this;
this.showJumpFailure = false;
const completionHandler: CompletionHandler = {
onRequestSuccess(elementName: bundleManager.ElementName, message: string): void {
hilog.info(DOMAIN, JUMP_TAG, 'OpenLink completion success, message: %{public}s, element: %{public}s',
message, JSON.stringify(elementName));
},
onRequestFailure(elementName: bundleManager.ElementName, message: string): void {
hilog.error(DOMAIN, JUMP_TAG, 'OpenLink completion failure, message: %{public}s, element: %{public}s',
message, JSON.stringify(elementName));
owner.jumpFailureMessage = '主应用链接暂不可用,请稍后重试';
owner.showJumpFailure = true;
四、构建结果能验证哪些边界
本次对当前工程执行 assembleHap 已成功,说明配置能通过资源、ArkTS、打包与签名链路。构建成功并不等同于每个分发入口都在任意设备上可用:实际系统入口还会受到设备支持、账号和平台配置影响。文章只把源码配置与构建结果作为工程事实,不夸大为线上分发已完成。
| 情况 | 容易出现的错误 | 本文采用的处理 |
|---|---|---|
| 数据或配置缺项 | 伪造默认成功状态 | 停在可解释的失败或空态 |
| 页面重进 | 使用上一页残留对象 | 从模型、服务或系统重新回读 |
| 重复动作 | 再写一遍相同业务事实 | 由稳定入口或回调收敛 |
import { AppColors, AppSizes, AppText } from '../common/Theme';
@Component
@Entry
struct QuickScoringPage {
@State playerA: string = 'A队';
@State playerB: string = 'B队';
@State scoreA: number = 0;
@State scoreB: number = 0;
@State history: ScoreMatch[] = [];
@State finishedText: string = '';
addScore(team: string, delta: number): void {
if (team === 'A') {
this.scoreA = Math.max(0, this.scoreA + delta);
} else {
this.scoreB = Math.max(0, this.scoreB + delta);
}
}
reset(): void {
this.scoreA = 0;
this.scoreB = 0;
五、从入口到工具卡片的检查项
检查时先读取打包后的 module.json 中 installationFree 是否保留,再安装或启动正确 bundle,确认首页展示计分、排阵、费用三类工具入口;随后依次进入一个本地工具并返回首页,确认页面导航没有承担安装判断。配图只展示可控设备中的主页,不把它当作平台分发成功的证明。
| 验收阶段 | 实际动作 | 回读重点 |
|---|---|---|
| 前置确认 | 启动正确 bundle 或打开目标页 | 标题、入口与模块身份 |
| 主题操作 | 执行搜索、切换、完成或跳转 | 服务/系统返回的结果 |
| 重进检查 | 返回、重启或切换范围后再进入 | 事实没有依赖旧页面残留 |
六、实现边界与维护顺序
元服务入口的安装形态由模块配置决定;主页专注计分、排阵和费用工具,不把分发属性藏进页面点击逻辑。 新增需求时应先补齐模型、配置或服务合同,再调整页面入口;把同一个判断复制到多个组件,短期看似方便,后续会使结果无法回读。ArkTS 状态管理的基础机制可参考 HarmonyOS 官方文档。
七、继续扩展时的约束
元服务工程最容易混淆的是能构建与能被目标系统入口识别。前者由当前工程的依赖、资源和签名流程决定,后者还依赖设备能力和平台配置。把两层分别写入验收记录,既不贬低成功构建的价值,也不会凭一个首页截图宣称所有分发条件已经成立。
首页的角色是把用户带到计分、排阵和费用计算,不应该顺便记录安装、分发或账户状态。场边操作通常节奏快,导航层越少越好;业务模块各自管理输入和结果,用户从工具返回时才能保留清晰的上下文。
新增原子服务能力时,先检查模块声明、入口路由和打包产物,再决定是否需要修改首页卡片。这个顺序把平台能力与产品功能隔离开,能减少一次分发配置调整误伤比赛工具的风险。
配置检查不要依赖文件名猜测
是否为元服务要看实际 module.json5 的 module 声明和打包产物,而不是目录名、图标名或首页文案。重命名项目不会改变 installationFree 的真实值,复制模板也可能留下不匹配的配置。把配置字段列入构建前检查,能在发布前发现这种表面一致、语义错误的问题。
本地工具的启动验收
启动后先确认 bundle 身份和主页标题,再点击一个明确的工具卡片,例如计分器。进入、操作、返回三个动作能证明路由与主页集成仍可用;它不证明聚合链接或平台上架状态。不同结论使用不同证据,是避免元服务文章夸大范围的关键。

更多推荐



所有评论(0)