📖 鸿蒙NEXT开发实战系列 | 第26篇 | 进阶篇 🎯 适合人群:有鸿蒙基础的开发者 ⏰ 阅读时间:约15分钟 | 💻 开发环境:DevEco Studio 5.0+


上一篇鸿蒙常用API速查表 下一篇:敬请期待...


目录


一、什么是元服务

元服务(Atomic Service)是鸿蒙生态中最具创新性的应用形态,它打破了传统App需要下载安装的限制,实现了"服务直达"的全新体验。

1.1 核心特征

特征

说明

免安装

用户无需下载安装,点击即可使用

即点即用

通过扫码、搜索、分享等方式直接打开

卡片化展示

核心功能以卡片形式在桌面上呈现

跨设备流转

支持手机、平板、手表等多设备无缝切换

轻量化体积

包体大小限制在10MB以内

1.2 元服务的本质

元服务本质上是一种轻量级的应用形态,它基于HarmonyOS的Ability框架构建,每个元服务由一个或多个Ability组成。与传统App相比,元服务更强调服务的原子化——将应用的核心功能拆分成独立的服务单元,用户可以根据需要直接使用特定功能,而不是被迫安装整个应用。

// 元服务的核心结构
// 一个元服务可以包含多个Ability
// EntryAbility - 主入口
// FormAbility - 卡片服务
// ServiceAbility - 后台服务

二、元服务 vs 传统App vs 小程序

很多开发者对元服务、传统App和小程序的概念容易混淆,下面我们通过对比表格来清晰理解它们的区别:

对比维度

元服务

传统App

小程序

安装方式

免安装

需要下载安装

依托宿主App

包体大小

≤10MB

无严格限制

≤2-4MB

运行环境

HarmonyOS系统层

独立沙箱

宿主App沙箱

系统能力

完整系统API

完整系统API

受限的系统API

桌面展示

支持服务卡片

仅图标

不支持

跨设备

原生支持

需要适配

依赖宿主

开发语言

ArkTS

ArkTS/Java/C++

WXML/WXSS/JS

分发渠道

华为应用市场

各应用商店

微信生态

2.1 什么场景适合开发元服务?

  • 工具类应用:计算器、翻译、扫码等高频轻量工具

  • 生活服务:点餐、购票、快递查询等即时性服务

  • 内容展示:新闻资讯、天气、股票行情等信息卡片

  • 营销活动:限时优惠、活动推广等短期运营活动


三、元服务开发环境准备

3.1 环境要求

  1. DevEco Studio 5.0 或更高版本

  2. HarmonyOS SDK API 12 或更高版本

  3. 华为开发者账号(需要实名认证)

3.2 开通元服务开发权限

登录华为开发者联盟,在"管理" -> "应用管理"中开通元服务开发权限。


四、创建第一个元服务项目

4.1 创建项目

  1. 打开DevEco Studio,选择 File -> New -> Create HarmonyOS Project

  2. 在模板选择页面,选择 Atomic Service 模板

  3. 填写项目信息:

    • Project name: MyFirstAtomicService

    • Bundle name: com.example.myatomicservice

    • Compile SDK: API 12

4.2 项目结构解析

创建完成后,项目结构如下:

MyFirstAtomicService/
├── entry/                          # 主模块
│   ├── src/
│   │   └── main/
│   │       ├── ets/               # ArkTS源码
│   │       │   ├── entryability/
│   │       │   │   └── EntryAbility.ets    # 主Ability
│   │       │   ├── pages/
│   │       │   │   └── Index.ets           # 主页面
│   │       │   └── widget/                 # 卡片目录
│   │       │       └── pages/
│   │       │           └── WidgetCard.ets  # 卡片页面
│   │       ├── resources/         # 资源文件
│   │       └── module.json5       # 模块配置
│   └── oh-package.json5
└── oh-package.json5

4.3 关键配置文件

module.json5 - 模块配置文件:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": true,    // 关键:设置为true表示元服务
    "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,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      }
    ],
    "extensionAbilities": [
      {
        "name": "FormExtensionAbility",
        "srcEntry": "./ets/widget/FormExtensionAbility.ets",
        "label": "$string:FormExtensionAbility_label",
        "icon": "$media:icon",
        "type": "form",            // 卡片扩展能力
        "metadata": [
          {
            "name": "ohos.extension.form",
            "resource": "$profile:form_config"  // 卡片配置
          }
        ]
      }
    ]
  }
}

form_config.json - 卡片配置文件(位于resources/base/profile/目录下):

{
  "forms": [
    {
      "name": "widget",
      "description": "$string:widget_desc",
      "src": "./ets/widget/pages/WidgetCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "isDefault": true,
      "colorMode": "auto",
      "supportDimensions": [
        "2*2",
        "2*4",
        "4*4"
      ],
      "defaultDimension": "2*2",
      "updateEnabled": true,
      "scheduledUpdateTime": "10:30",
      "updateDuration": 1,
      "formConfigAbility": "ability://EntryAbility"
    }
  ]
}

五、元服务卡片开发实战

5.1 创建卡片页面

entry/src/main/ets/widget/pages/目录下创建WidgetCard.ets

// WidgetCard.ets - 元服务卡片页面
// 用于在桌面上展示的2x2卡片

@Entry
@Component
struct WidgetCard {
  // 使用LocalStorage存储卡片数据
  @StorageProp('formId') formId: string = ''
  @StorageProp('cityName') cityName: string = '北京'
  @StorageProp('temperature') temperature: string = '26°C'
  @StorageProp('weatherDesc') weatherDesc: string = '晴'

  build() {
    Column() {
      // 顶部标题栏
      Row() {
        Text('天气服务')
          .fontSize(14)
          .fontColor('#666666')
          .fontWeight(FontWeight.Medium)

        Blank()

        Image($r('sys.media.ohos_ic_public_refresh'))
          .width(16)
          .height(16)
          .fillColor('#999999')
      }
      .width('100%')
      .padding({ left: 12, right: 12, top: 8 })

      // 主要内容区域
      Column() {
        // 天气图标和温度
        Row() {
          Image($r('app.media.weather_sunny'))
            .width(48)
            .height(48)

          Column() {
            Text(this.temperature)
              .fontSize(32)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')

            Text(this.weatherDesc)
              .fontSize(14)
              .fontColor('#666666')
              .margin({ top: 2 })
          }
          .alignItems(HorizontalAlign.Start)
          .margin({ left: 12 })
        }
        .justifyContent(FlexAlign.Center)

        // 城市信息
        Text(this.cityName)
          .fontSize(16)
          .fontColor('#333333')
          .margin({ top: 12 })
      }
      .layoutWeight(1)
      .justifyContent(FlexAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
    .borderRadius(16)
  }
}

5.2 创建卡片扩展Ability

entry/src/main/ets/widget/目录下创建FormExtensionAbility.ets

// FormExtensionAbility.ets - 卡片扩展能力
// 处理卡片的创建、更新、销毁等生命周期

import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG = 'FormExtensionAbility'

export default class FormExtension extends FormExtensionAbility {
  // 卡片创建时调用
  onAddForm(want: Want): formBindingData.FormBindingData {
    hilog.info(0x0000, TAG, 'onAddForm called')

    // 获取卡片ID
    const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string
    hilog.info(0x0000, TAG, `Form created: ${formId}`)

    // 初始化卡片数据
    const formData: Record<string, string> = {
      'formId': formId,
      'cityName': '北京',
      'temperature': '26°C',
      'weatherDesc': '晴'
    }

    // 返回卡片绑定数据
    return formBindingData.createFormBindingData(formData)
  }

  // 卡片更新时调用
  onUpdateForm(formId: string): void {
    hilog.info(0x0000, TAG, `onUpdateForm called: ${formId}`)

    // 更新卡片数据
    const formData: Record<string, string> = {
      'cityName': '北京',
      'temperature': '28°C',    // 模拟更新温度
      'weatherDesc': '多云'
    }

    const formBindingData = formBindingData.createFormBindingData(formData)

    // 调用updateForm更新卡片
    formProvider.updateForm(formId, formBindingData).then(() => {
      hilog.info(0x0000, TAG, 'Form updated successfully')
    }).catch((err: BusinessError) => {
      hilog.error(0x0000, TAG, `Failed to update form: ${err.message}`)
    })
  }

  // 卡片销毁时调用
  onRemoveForm(formId: string): void {
    hilog.info(0x0000, TAG, `onRemoveForm called: ${formId}`)
    // 清理卡片相关资源
  }

  // 卡片事件触发时调用
  onFormEvent(formId: string, message: string): void {
    hilog.info(0x0000, TAG, `onFormEvent called: ${formId}, message: ${message}`)
    // 处理卡片传递的事件
    const event = JSON.parse(message)
    if (event.action === 'refresh') {
      this.onUpdateForm(formId)
    }
  }
}

六、卡片数据绑定与交互

6.1 卡片数据更新

卡片支持定时更新和主动更新两种方式:

// 定时更新 - 在form_config.json中配置
// "scheduledUpdateTime": "10:30"  每天10:30更新
// "updateDuration": 1             每1小时更新

// 主动更新 - 在FormExtensionAbility中调用
import { formProvider } from '@kit.FormKit'

async function updateFormData(formId: string) {
  // 获取最新数据(例如从网络请求)
  const weatherData = await fetchWeatherData()

  // 创建新的绑定数据
  const formData = formBindingData.createFormBindingData({
    'cityName': weatherData.city,
    'temperature': weatherData.temp,
    'weatherDesc': weatherData.desc
  })

  // 更新卡片
  try {
    await formProvider.updateForm(formId, formData)
    console.info('Form update success')
  } catch (err) {
    console.error(`Form update failed: ${err}`)
  }
}

6.2 卡片点击事件

卡片支持通过postCardAction向Ability发送事件:

// 在WidgetCard.ets中添加点击事件
@Component
struct WidgetCard {
  // ... 其他代码

  build() {
    Column() {
      // ... 其他组件

      // 添加刷新按钮
      Button('刷新天气')
        .width(120)
        .height(36)
        .fontSize(14)
        .backgroundColor('#007DFF')
        .borderRadius(18)
        .onClick(() => {
          // 向FormExtensionAbility发送消息
          postCardAction(this, {
            'action': 'message',
            'params': {
              'action': 'refresh'
            }
          })
        })
        .margin({ top: 12 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
    .borderRadius(16)
    .onClick(() => {
      // 点击卡片打开元服务
      postCardAction(this, {
        'action': 'router',
        'abilityName': 'EntryAbility',
        'params': {
          'message': 'from_widget'
        }
      })
    })
  }
}

6.3 跳转到元服务详情页

// 在EntryAbility的主页面中处理来自卡片的参数
@Entry
@Component
struct Index {
  @State message: string = '欢迎使用天气元服务'

  aboutToAppear() {
    // 获取来自卡片的参数
    const params = this.getUIContext().getRouter().getParams()
    if (params && params['message'] === 'from_widget') {
      this.message = '您从桌面卡片进入'
    }
  }

  build() {
    Column() {
      Text(this.message)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 40 })

      // 天气详情页面
      WeatherDetailView()
    }
    .width('100%')
    .height('100%')
  }
}

七、元服务上架流程

7.1 开发完成检查清单

在上架前,请确认以下事项:

检查项

说明

包体大小

不超过10MB

卡片功能

至少一个可用的服务卡片

启动速度

冷启动时间不超过3秒

隐私政策

已配置隐私政策链接

权限申请

仅申请必要的系统权限

7.2 签名打包

  1. 在DevEco Studio中选择 Build -> Build Hap(s)/APP(s) -> Build APP(s)

  2. 选择签名配置(需要提前配置签名证书)

  3. 等待打包完成,生成.app文件

7.3 上架华为应用市场

  1. 登录华为应用市场Connect

  2. 进入"我的应用" -> "HarmonyOS应用"

  3. 点击"HarmonyOS元服务" -> "新建"

  4. 填写应用信息:

    • 应用名称

    • 应用分类(选择"元服务")

    • 应用图标和截图

    • 隐私政策URL

  5. 上传签名后的.app

  6. 提交审核(通常1-3个工作日)

7.4 审核注意事项

  • 功能完整性:确保所有功能可正常使用,无明显Bug

  • 用户体验:卡片展示清晰,交互流畅

  • 内容合规:不包含违规内容

  • 隐私合规:明确告知用户数据收集用途


八、总结与展望

通过本文的学习,我们掌握了鸿蒙元服务开发的完整流程:

  1. 理解概念:元服务是免安装、即点即用的轻量级应用形态

  2. 创建项目:使用DevEco Studio创建Atomic Service项目

  3. 开发卡片:使用FormKit框架开发桌面服务卡片

  4. 数据交互:实现卡片数据绑定和事件处理

  5. 应用上架:完成签名打包并提交华为应用市场审核

元服务的发展前景

随着鸿蒙生态的快速发展,元服务正在成为连接用户与服务的重要桥梁:

  • 2025年底:鸿蒙设备装机量突破10亿

  • 2026年:元服务预计覆盖超过100个生活服务场景

  • 未来趋势:元服务将与AI深度融合,提供更智能的服务推荐

作为开发者,现在正是布局元服务开发的最佳时机。掌握元服务开发技能,不仅能为用户提供更便捷的服务体验,也能在鸿蒙生态的快速发展中抢占先机。


相关资源


系列推荐


标签元服务 鸿蒙卡片 FormKit HarmonyOS 原子化服务 ArkUI 鸿蒙开发 免安装应用


💡 写在最后:元服务是鸿蒙生态最具想象力的创新之一。如果你在开发过程中遇到任何问题,欢迎在评论区交流讨论。下一篇我们将探讨更多进阶主题,敬请期待!

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐