鸿蒙中 元服务开发流程(二)

本文同步发表于微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、元服务工程创建

1.1 创建工程步骤

1.1.1 启动创建
  • 首次打开:选择 Create Project

  • 已有工程File > New > Create Project

1.1.2 选择模板

选择 Atomic Service(元服务) 开发,支持模板:

模板类型适用设备主要功能说明
Empty AbilityPhone、Tablet基础 Hello World 功能标准元服务开发模板
[CloudDev]Empty Ability跨设备端云一体化开发集成云开发能力
Embeddable Ability支持嵌入的应用嵌入式运行可被其他应用嵌入的元服务

注意:元服务不支持 Native 开发方式,无法选择 Native 工程模板。

1.1.3 账号登录
  • 华为开发者账号登录:正式开发必须登录

  • 访客模式:仅用于体验开发功能

    • 在真机运行时需在 app.json5 中补充真实存在的包名

1.1.4 APP ID 配置
  1. 选择 APP ID:从已登录账号下的 APP ID 列表中选择

  2. 注册新 APP ID:如未注册,点击 Register APP ID

    • 应用类型必须选择"元服务"

  3. 刷新列表:注册后点击 Refresh 显示新 APP ID

1.1.5 Bundle Name 规则
  • 固定格式com.atomicservice.[appid]

  • 自动生成:开发者无法手动修改

  • 命名规范:不符合规范的包名不会在列表中显示

1.1.6 工程配置
  • Project name:填写工程名称

  • 其他参数:保持默认设置

  • 点击 Finish:自动生成示例代码和资源

1.2 元服务工程目录结构

元服务工程/
├── AppScope/
│   └── app.json5                 # 元服务全局配置信息
├── entry/                        # HarmonyOS工程模块(编译生成HAP)
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/
│   │   │   │   ├── entryability/  # 元服务入口
│   │   │   │   └── pages/        # 元服务页面
│   │   │   ├── resources/        # 资源文件(图形、字符串、布局等)
│   │   │   └── module.json5      # 模块配置文件
│   │   └── build-profile.json5  # 模块级编译配置
│   └── hvigorfile.ts            # 模块级构建脚本
├── oh_modules/                  # 三方库依赖信息
├── build-profile.json5         # 工程级配置(签名、产品配置)
└── hvigorfile.ts              # 工程级构建脚本
1.2.1 文件说明
  • app.json5:元服务的全局配置信息

  • module.json5:模块配置文件,包含HAP配置、设备配置等

  • build-profile.json5:编译构建配置

  • hvigorfile.ts:编译构建任务脚本,支持自定义

二、构建元服务页面

2.1 页面基本结构

2.1.1 默认页面(Index.ets)
import { hilog } from '@kit.PerformanceAnalysisKit';
import { router } from '@kit.ArkUI';

@Entry
@Component
struct MainPage {
  @State welcomeText: string = '欢迎使用';
  
  build() {
    Row() {
      Column() {
        // 文本组件
        Text(this.welcomeText)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          
        // 按钮组件
        Button('进入详情')
          .type(ButtonType.Capsule)
          .margin({ top: 40 })
          .backgroundColor('#007DFF')
          .width('60%')
          .height(55)
          .fontSize(20)
          .fontWeight(FontWeight.Medium)
          .onClick(() => {
            // 页面跳转逻辑
            router.pushUrl({ url: 'pages/DetailPage' });
          })
      }
      .width('100%')
    }
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
  
  aboutToAppear() {
    // 页面显示时的初始化逻辑
    hilog.info(0x0000, 'pageTag', '主页面准备显示');
  }
}
2.1.2 布局组件选择
布局场景推荐组件特点
线性排列RowColumn简单直观的线性布局
复杂对齐RelativeContainer灵活的相对位置控制
层叠显示Stack元素重叠显示
网格布局Grid规整的网格排列

2.2 创建第二个页面

2.2.1 新建页面文件
  1. 右键 pages 文件夹 → New > ArkTS File

  2. 输入文件名:如 DetailPage

  3. 自动生成文件结构

快捷方式:选择 New > Page 可自动配置路由

2.2.2 配置页面路由

main_pages.json 配置:

{
  "src": [
    "pages/MainPage",
    "pages/DetailPage",
    "pages/SettingPage"  // 可继续添加更多页面
  ]
}
2.2.3 第二个页面实现
import { router } from '@kit.ArkUI';

@Entry
@Component
struct DetailPage {
  @State detailInfo: string = '详情页面';
  @State dataCount: number = 0;
  
  build() {
    Row() {
      Column({ space: 15 }) {
        Text(this.detailInfo)
          .fontSize(45)
          .fontWeight(FontWeight.Bold)
          .fontColor('#1A1A1A')
        
        Text(`数据数量: ${this.dataCount}`)
          .fontSize(18)
          .fontColor('#666666')
          .margin({ top: 10 })
        
        Button('增加数据')
          .type(ButtonType.Normal)
          .backgroundColor('#34C759')
          .width('70%')
          .height(48)
          .fontSize(18)
          .onClick(() => {
            this.dataCount++;
          })
        
        Button('返回首页')
          .type(ButtonType.Capsule)
          .margin({ top: 30 })
          .backgroundColor('#007DFF')
          .width('50%')
          .height(48)
          .fontSize(18)
          .onClick(() => {
            router.back();
          })
      }
      .width('100%')
      .padding(20)
    }
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}

2.3 页面间跳转实现

2.3.1 导入路由模块
import { router } from '@kit.ArkUI';
2.3.2 页面跳转方法
// 1. 普通跳转(推入堆栈)
router.pushUrl({ 
  url: 'pages/DetailPage' 
});

// 2. 替换当前页面
router.replaceUrl({ 
  url: 'pages/NewPage' 
});

// 3. 跳转并清空堆栈
router.clearStackAndPushUrl({ 
  url: 'pages/HomePage' 
});

// 4. 带参数跳转
router.pushUrl({
  url: 'pages/DetailPage',
  params: {
    userId: 'user123',
    productId: 'p456',
    timestamp: Date.now()
  }
});

// 5. 返回上一页
router.back();

// 6. 返回指定页面
router.back({ 
  url: 'pages/MainPage' 
});
2.3.3 接收页面参数
@Entry
@Component
struct DetailPage {
  @State productId: string = '';
  @State userId: string = '';
  
  aboutToAppear() {
    // 获取传递的参数
    const params = router.getParams() as Record<string, any>;
    this.productId = params['productId'] || '';
    this.userId = params['userId'] || '';
    
    // 使用参数加载数据
    this.loadProductDetail(this.productId);
  }
  
  private loadProductDetail(id: string) {
    // 根据ID加载商品详情
    console.info(`加载商品 ${id} 的详情信息`);
  }
}

三、新建元服务卡片

3.1 创建卡片步骤

3.1.1 创建卡片
  1. 右键 entry 模块 → New > Service Widget > Dynamic Widget

  2. 选择模板Hello World 卡片模板

  3. 点击 Next 进入配置页面

3.1.2 卡片配置参数
配置项说明要求/限制
Service widget name卡片名称同应用内不能重复,仅含字母、数字、下划线
Display name预览面板显示的名称API 11+ Stage 工程支持
Description卡片描述信息可选
Language开发语言元服务只支持 ArkTS,不支持 JS
Support dimension支持的卡片规格可多选,首次创建生成 EntryCard 目录
Default dimension默认卡片规格下拉选择
Ability name挂靠的 Form Ability选择已有或新建
Module name所属模块默认当前模块
3.1.3 完成创建
  • 点击 Finish 完成卡片创建

  • 生成卡片文件和快照目录

3.2 卡片开发实现

3.2.1 基础卡片代码
@Entry
@Component
struct ServiceCard {
  @State scaleValue: number = 1.0
  @State cardTitle: string = '快捷入口'
  
  build() {
    Column({ space: 12 }) {
      // 卡片标题
      Text(this.cardTitle)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#1A1A1A')
        .width('100%')
        .textAlign(TextAlign.Center)
      
      // 功能按钮
      Button('快速启动')
        .width('85%')
        .height(45)
        .backgroundColor('#007DFF')
        .fontColor(Color.White)
        .fontSize(16)
        .onClick(() => {
          // 点击动画效果
          this.scaleValue = 1.15
        })
        .scale({ x: this.scaleValue, y: this.scaleValue })
        .animation({
          curve: Curve.EaseInOut,
          playMode: PlayMode.AlternateReverse,
          duration: 180,
          onFinish: () => {
            this.scaleValue = 1.0
          }
        })
      
      // 状态信息
      Text('点击上方按钮体验')
        .fontSize(12)
        .fontColor('#666666')
        .width('100%')
        .textAlign(TextAlign.Center)
        .margin({ top: 8 })
    }
    .padding(16)
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
    .borderRadius(16)
    .shadow({ radius: 8, color: '#1A000000', offsetX: 0, offsetY: 2 })
  }
}
3.2.2 卡片点击跳转到元服务
@Entry
@Component
struct ServiceCard {
  @State scaleValue: number = 1.0
  
  build() {
    Column({ space: 12 }) {
      // 卡片内容...
    }
    .onClick(() => {
      // 点击整个卡片跳转到元服务
      postCardAction(this, {
        "action": "router",
        "abilityName": "EntryAbility",
        "params": {
          "source": "card",
          "timestamp": Date.now(),
          "targetPage": "MainPage"
        }
      });
    })
  }
}
3.2.3 卡片动作处理
事件类型触发目标使用场景核心限制
router跳转至指定 UIAbility页面跳转、参数传递非系统应用仅支持同应用内跳转
message通知 FormExtensionAbility消息通知、卡片内容更新需在静态卡片中使用 FormLink
call后台运行 UIAbility后台任务(如音乐播放、数据同步)需单实例模式 + 后台权限
// 支持多种卡片动作类型
postCardAction(this, {
  "action": "router",           // 路由跳转
  "abilityName": "EntryAbility",
  "params": { /* 参数 */ }
});

postCardAction(this, {
  "action": "message",          // 发送消息
  "params": { "type": "refresh" }
});

postCardAction(this, {
  "action": "call",             // 调用服务
  "params": { "service": "update" }
});

3.3 卡片快照自定义

3.3.1 快照文件位置
EntryCard/
└── entry/
    └── base/
        └── snapshot/
            ├── widget-2x2.png    # 2x2规格快照
            ├── widget-2x4.png    # 2x4规格快照
            └── widget-4x4.png    # 4x4规格快照
3.3.2 替换快照图片
  1. 准备图片:符合尺寸要求的PNG图片

  2. 替换文件:覆盖对应规格的快照文件

  3. 保持命名:确保文件名一致

  4. 刷新预览:重新编译查看效果

3.4 卡片规格与适配

3.4.1 常用卡片规格
规格尺寸(vp)适用场景
2x2120×120小工具、快捷入口
2x4120×255信息展示、简单列表
4x4255×255详细视图、复杂交互
3.4.2 响应式卡片设计
@Entry
@Component
struct AdaptiveCard {
  @Prop cardSize: { width: number, height: number } = { width: 120, height: 120 }
  
  build() {
    // 根据卡片尺寸调整布局
    const isSmall = this.cardSize.width <= 120;
    
    Column() {
      if (isSmall) {
        // 小尺寸布局
        Text('简版')
          .fontSize(14)
      } else {
        // 大尺寸布局
        Column({ space: 8 }) {
          Text('完整版')
            .fontSize(18)
          Text('更多信息')
            .fontSize(12)
        }
      }
    }
  }
}

四、开发注意事项

4.1 账号与认证

// 华为账号静默登录示例(Index页面中)
private loginWithHuaweiID() {
  const loginRequest = new authentication.HuaweiIDProvider()
    .createLoginWithHuaweiIDRequest();
  
  loginRequest.forceLogin = false;  // 非强制登录
  
  const controller = new authentication.AuthenticationController();
  controller.executeRequest(loginRequest)
    .then((data) => {
      const response = data as authentication.LoginWithHuaweiIDResponse;
      const authCode = response.data?.authorizationCode;
      // 将 authCode 发送到后端换取 unionID
    })
    .catch((error: BusinessError) => {
      if (error.code === authentication.AuthenticationErrorCode.ACCOUNT_NOT_LOGGED_IN) {
        // 华为账号未登录,建议跳转到登录引导页
        console.warn('华为账号未登录');
      }
    });
}

审核要求:如果元服务有账号系统,必须提供华为账号登录选项

4.2 开发规范

  1. 语言限制:只支持 ArkTS,不支持 JS

  2. 模型限制:只支持 Stage 模型

  3. API限制:只能使用元服务 API 集

  4. 版本要求:需要 HarmonyOS NEXT 及以上系统

4.3 性能优化

  1. 卡片轻量化:避免复杂计算和大量数据

4.4 调试

  1. 预览器调试:使用预览器实时查看效果

  2. 真机测试:配置签名后在真机运行

五、完整开发流程

发布准备

  1. 完善应用信息:图标、名称、描述

  2. 配置签名证书:申请发布证书

  3. 测试兼容性:多设备、多场景测试

  4. 准备素材:截图、演示视频、文档

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值