HarmonyOS 6.1 开发者盛宴|《灵犀厨房》实战(二十):【元服务】一键烹饪推荐原子化服务——免安装直达美味

HarmonyOS 6.1 开发者盛宴|《灵犀厨房》【元服务】一键烹饪推荐原子化服务------免安装直达美味

摘要 :前面的篇章《HarmonyOS 6.1 开发者盛宴|灵犀厨房APP【通知系统】延时烹饪提醒------让通知不再错过关键步骤》中,我们已为《灵犀厨房》装上了通知系统------延时提醒 + WantAgent 回到应用。但这里有一个产品层面的断层:用户只是想"看看今天吃什么",却必须打开完整 App------加载登录、加载首页、等待推荐引擎计算。能不能更轻?本篇,我们将深入 HarmonyOS 6.1.0(API 23)的原子化服务(Atomic Service)能力,为《灵犀厨房》构建一个免安装的一键烹饪推荐元服务 :用户通过全局搜索即可直达"今天吃什么"推荐页,3 秒出结果,用完即走。元服务通过 HSP 共享包复用现有 RecommendEngine,零重复代码。严格遵循 API 23 规范。

🔗 配套工程集成篇 :本篇侧重于元服务的 UI 设计与业务逻辑。元服务与主应用的工程整合(三模块架构、HSP 共享包搭建、Want 跳转参数桥梁)请阅读下一篇《【元服务】三模块一体化工程集成------打通免安装跳转的最后一公里》


一、引言与系列定位

经过前面多篇文章的积累,《灵犀厨房》已经是一个功能完备的应用:AI 推荐、语音播报、声控操作、健康分析、厨电模拟、分布式流转、通知提醒......但每次用户想用它的核心功能------"今天吃什么"------都需要:

步骤 耗时 用户心理
找到并点开灵犀厨房图标 2s "我就想看看吃啥,至于吗"
等登录页加载 → 自动跳转 3s "快点......"
首页推荐引擎计算 → 渲染 2s "等的就是这几张卡片"
总计 ~7s 焦虑感:7 秒在"午餐焦虑"中漫长得像 70 秒

而"今天吃什么"恰恰是最适合原子化服务的场景------需求单一、流程极短、用完即走。

设计决策:什么是原子化服务(Atomic Service)?

原子化服务是 HarmonyOS 独有的轻量级服务形态。它的核心特征:免安装、即点即用 。用户不需要下载完整 App、不需要注册登录------通过全局搜索、桌面卡片、扫码、NFC 碰一碰等方式即可直达服务页面。从技术角度,它是一个与主应用共享 bundleName 的独立模块,module.json5 中设置 installationFree: true 即可启用。

本篇的设计原则:

  • 复用现有能力,零重复代码 :元服务通过 HSP 共享包(shared 模块)引用 RecommendEngine,不重复实现推荐逻辑
  • 极致轻量:元服务模块只有 1 个 Ability + 1 个页面 + 配置文件,总共约 3 个文件
  • 3 秒体验:用户进入 → 推荐引擎计算 → 卡片展示,全链路 < 3 秒

📌 阅读提示:本篇与下一篇是"设计→落地"的配套关系。

  • 本篇:回答"元服务怎么设计"------UI、推荐逻辑、用户交互
  • 下一篇:回答"元服务怎么集成"------工程配置、模块划分、跨模块跳转

建议先阅读本篇理解元服务的业务逻辑,再阅读下一篇完成工程搭建。


二、核心原理与底层机制深度解读

2.1 原子化服务的三种分发路径

HarmonyOS 6.1.0(API 23)为原子化服务提供了三条用户触达路径:

图一解读 :用户通过三条路径触发元服务------全局搜索(输入"今天吃什么")、桌面卡片(固定在负一屏)、NFC 碰一碰(碰厨房标签)。系统 Atomic Service 框架识别 bundleNamemoduleName,加载对应的元服务模块,最终由 AtomicServiceAbility 渲染推荐页面。

路径 触发方式 用户体验 适用场景
A: 全局搜索 桌面下拉搜索"今天吃什么" 关键词匹配 → 直达服务 日常使用最高频
B: 桌面卡片 左滑负一屏添加卡片 固定在桌面,抬手即看 每日查看推荐
C: NFC 碰一碰 手机碰厨房 NFC 标签 物理世界触发数字服务 智能厨房场景

为什么先从全局搜索入手?

全局搜索是 HarmonyOS 原子化服务最成熟的发现通道。开发者只需在元服务模块中声明 skills,系统会自动索引页面内容。用户搜索"今天吃什么""晚餐推荐""灵犀厨房"等关键词时,元服务会出现在搜索结果中------点击即跳转,无需安装。

2.2 原子化服务 vs 传统 App:一图看懂差异

图二解读 :右侧传统应用需要下载、安装、登录、加载首页四步才能看到推荐,左侧原子化服务只需搜索触发一步直达。核心差异在于免安装免登录------系统预加载机制让元服务的冷启动速度远超传统应用。

维度 传统应用 原子化服务
安装容量 50MB+(含所有资源) 0MB(免安装)
首次启动 3-5秒(冷启动) <1秒(系统预加载)
用户门槛 下载→安装→注册→登录 搜索即达
功能范围 全部功能 单一场景(推荐+点击看详情)
代码复用 --- 共享主应用的 bundleName 和业务模块

2.3 HSP 共享包设计原理:元服务如何复用推荐引擎

这是本篇最核心的设计------元服务如何复用主应用的业务逻辑。根据华为官方文档《元服务与应用可复用设计》,单团队 + 元服务分包 场景下,推荐使用 HSP(Harmony Shared Package)共享包作为代码复用方案:

图三解读 :将 RecommendEngineRecipe 模型、MockData 等可复用代码从 entry 模块迁移到独立的 shared HSP 模块。entry 和 atomicservice 通过各自的 oh-package.json5 声明对 shared 的依赖------编译时 hvigor 自动解析依赖关系,构建产物中 shared 模块只打包一次,两个消费者共享引用。

📌 HSP 共享包的实际搭建过程(创建 shared 模块、配置 oh-package.json5、声明依赖)已记录在下一篇《工程集成篇》的 Step 2-4 中,含完整的配置文件代码。本篇仅阐述设计原理,不再重复配置代码。

维度 跨模块直接 import HSP 共享包
路径稳定性 依赖文件系统相对路径,模块移动即失效 通过 oh-package.json5 声明依赖,路径稳定
编译产物 两份完整副本(各自打包) 单份共享产物,两个模块引用同一份
官方推荐度 非标准用法 ✅ 官方推荐方案

三、架构设计 / 核心逻辑图解

3.1 元服务模块的四层架构

图四解读 :元服务 UI 层(绿色区)只有 1 个 Ability + 1 个页面,通过 import from 'shared' 引用共享的推荐引擎和数据模型。主应用的首页推荐和菜谱详情页同样引用 shared 模块。注意元服务模块不包含任何业务逻辑------所有算法都在 shared 中,元服务只负责 UI 渲染和用户交互。

设计原则

  1. HSP 集中共享RecommendEngineRecipeMockDataUserPreference 均位于 shared HSP 模块
  2. UI 轻量化:元服务模块只放 UI 代码(1 个 Ability + 1 个页面),不含业务逻辑
  3. 独立入口 :元服务有自己的 AtomicServiceAbility,不依赖主应用的 EntryAbility
  4. 点击跳转 :推荐卡片点击后通过 Want 拉起主应用的菜谱详情页

3.2 完整时序图:从搜索到详情页

图五解读 :用户从全局搜索"今天吃什么"到看到菜谱详情,经历了六个阶段:(1)系统匹配元服务索引并加载模块;(2)元服务调用推荐引擎计算推荐;(3)渲染 4 张菜谱卡片;(4)用户点击卡片;(5)元服务通过 Want 拉起主应用;(6)主应用显示详情页。整个链路的核心优势在于免安装------前三步不需要下载完整应用。


四、实战:搭建一键烹饪推荐原子化服务

场景确认 :按照华为官方《元服务与应用可复用设计》指南,本系列属于单团队、元服务分包 + 应用支持 场景。主应用(entry)和元服务(atomicservice)通过 HSP 共享包(shared 模块) 复用推荐引擎和数据模型。

Step 1:元服务模块目录结构

元服务模块的内部结构如下(完整的工程目录见下一篇《工程集成篇》):

复制代码
atomicservice/                   ← ★ 新增元服务模块
├── src/main/
│   ├── ets/
│   │   ├── entryability/
│   │   │   └── AtomicServiceAbility.ets
│   │   └── pages/
│   │       └── Index.ets
│   ├── module.json5
│   └── resources/
├── build-profile.json5
├── hvigorfile.ts
└── oh-package.json5

说明 :元服务通过 HSP 共享包(shared 模块)复用 RecommendEngineRecipe 模型、MockData。HSP 共享包的创建与配置详见下一篇《工程集成篇》的 Step 2-3

Step 2:实现 AtomicServiceAbility ------ 入口 Ability

这是元服务的唯一入口 ,负责加载推荐页面。与主应用的 EntryAbility 不同,元服务的入口 Ability 极简------不需要初始化通知渠道、不需要权限请求、不需要登录状态检查:

typescript 复制代码
// atomicservice/src/main/ets/entryability/AtomicServiceAbility.ets
// 所属层:原子化服务入口
// 职责:Atomic Service 的 UIAbility 入口
// API Level: 23

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0001;
const TAG = 'AtomicServiceAbility';

export default class AtomicServiceAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.debug(DOMAIN, TAG, 'AtomicServiceAbility onCreate');
    // 元服务不需要复杂初始化------无登录、无持久化
    // 唯一的事:设置颜色模式跟随系统
    try {
      this.context.getApplicationContext().setColorMode(0);
    } catch (err) {
      hilog.warn(DOMAIN, TAG, '设置颜色模式失败: %{public}s', JSON.stringify(err));
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.debug(DOMAIN, TAG, 'AtomicServiceAbility onWindowStageCreate');

    // ★ 加载推荐页(唯一的页面)
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, TAG,
          '元服务页面加载失败, code: %{public}d, msg: %{public}s',
          err.code, err.message);
        return;
      }
      hilog.debug(DOMAIN, TAG, '元服务推荐页加载成功');
    });
  }

  onDestroy(): void {
    hilog.debug(DOMAIN, TAG, 'AtomicServiceAbility onDestroy');
  }
}

核心点解读onCreate 中只做了一件事------设置颜色模式跟随系统。没有初始化通知渠道(元服务不支持通知)、没有权限请求、没有登录状态检查。onWindowStageCreate 中直接加载推荐页------这是元服务唯一需要渲染的页面。

Step 3:构建推荐页面 Index.ets ------ 「一键推荐」核心 UI

这是元服务的唯一页面,用户体验的最终落地处:

typescript 复制代码
// atomicservice/src/main/ets/pages/Index.ets
// 所属层:原子化服务 UI 层
// 职责:一键烹饪推荐页面
// API Level: 23
// 依赖: shared HSP 模块(RecommendEngine, Recipe, UserPreference)

import { common, Want } from '@kit.AbilityKit';
// ★ HSP 共享包导入 ------ 通过 shared 模块名引用,不依赖文件路径
import { Recipe } from 'shared';
import { recommendEngine } from 'shared';
import { UserPreference } from 'shared';

@Entry
@ComponentV2
struct AtomicRecommendPage {
  @Local recommendations: Recipe[] = [];
  @Local isLoading: boolean = true;
  @Local errorMsg: string = '';

  aboutToAppear(): void {
    this.loadRecommendations();
  }

  /**
   * 一键加载推荐
   * 复用主应用的 recommendEngine,传入默认偏好
   */
  private loadRecommendations(): void {
    this.isLoading = true;
    this.errorMsg = '';

    try {
      // 使用默认偏好(用户未登录时,推荐引擎返回通用推荐)
      const defaultPref: UserPreference = {
        favoriteTags: [],     // 无偏好标签 → 所有菜谱参与评分
        allergies: [],        // 无忌口
        maxCalories: 0        // 0 表示不限卡路里
      };

      // ★ 调用共享的推荐引擎
      this.recommendations = recommendEngine.getRecommendations(
        defaultPref, [], 4
      );
      this.isLoading = false;

    } catch (err) {
      this.errorMsg = '推荐加载失败,请下拉刷新';
      this.isLoading = false;
      console.error(`[AtomicRecommend] 推荐失败: ${JSON.stringify(err)}`);
    }
  }

  /**
   * 点击菜谱卡片 → 通过 Want 拉起主应用的 RecipeDetailPage
   */
  private handleRecipeClick(recipe: Recipe): void {
    try {
      const ctx = this.getUIContext().getHostContext() as common.UIAbilityContext;
      const want: Want = {
        bundleName: 'com.annan.lingxikitchen',
        abilityName: 'EntryAbility',
        parameters: {
          recipeId: recipe.id,
          recipeName: recipe.name,
          recipeIngredients: recipe.ingredients
        }
      };
      ctx.startAbility(want);
      console.log(`[AtomicRecommend] 跳转主应用 → ${recipe.name}`);
    } catch (err) {
      console.error(`[AtomicRecommend] 跳转主应用失败: ${JSON.stringify(err)}`);
    }
  }

  build() {
    Column() {
      // ── 顶部标题区 ──
      Row() {
        Text('🍳').fontSize(32)
        Column({ space: 2 }) {
          Text('今天吃什么?')
            .fontSize(22).fontWeight(FontWeight.Bold).fontColor('#333')
          Text('灵犀厨房 · 一键推荐')
            .fontSize(12).fontColor('#999')
        }
        .margin({ left: 12 })
        .alignItems(HorizontalAlign.Start)

        Blank()

        // 刷新按钮
        Button({ type: ButtonType.Circle }) {
          SymbolGlyph($r('sys.symbol.arrow_clockwise'))
            .fontSize(20).fontColor(['#FF6B35'])
        }
        .width(40).height(40).backgroundColor('#FFF0E6')
        .onClick(() => this.loadRecommendations())
      }
      .width('100%')
      .padding({ left: 20, right: 20, top: 16, bottom: 12 })

      // ── 分割线 ──
      Divider().color('#F0F0F0').width('90%')

      // ── 内容区:三态渲染 ──
      if (this.isLoading) {
        // 加载中
        Column({ space: 12 }) {
          LoadingProgress().width(40).height(40).color('#FF6B35')
          Text('正在为你推荐...').fontSize(14).fontColor('#999')
        }
        .width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)

      } else if (this.errorMsg.length > 0) {
        // 错误状态
        Column({ space: 12 }) {
          Text('😅').fontSize(40)
          Text(this.errorMsg).fontSize(14).fontColor('#999')
          Button('重新加载')
            .fontSize(14).height(36)
            .backgroundColor('#FF6B35').fontColor(Color.White)
            .borderRadius(18)
            .onClick(() => this.loadRecommendations())
        }
        .width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)

      } else {
        // 推荐卡片列表
        List({ space: 12 }) {
          ForEach(this.recommendations, (recipe: Recipe, index: number) => {
            ListItem() {
              this.buildRecipeCard(recipe, index)
            }
            .onClick(() => this.handleRecipeClick(recipe))
          }, (recipe: Recipe) => recipe.id.toString())
        }
        .width('100%').layoutWeight(1)
        .padding({ left: 16, right: 16 })
      }
    }
    .width('100%').height('100%')
    .backgroundColor('#FFF8F0')
  }

  /**
   * 菜谱卡片 @Builder
   */
  @Builder
  buildRecipeCard(recipe: Recipe, index: number) {
    Row({ space: 12 }) {
      // 序号
      Text(`${index + 1}`)
        .fontSize(20).fontWeight(FontWeight.Bold)
        .fontColor('#FF6B35')
        .width(32).height(32).borderRadius(16)
        .backgroundColor('#FFF0E6')
        .textAlign(TextAlign.Center)

      // 菜谱信息
      Column({ space: 4 }) {
        Text(recipe.name)
          .fontSize(16).fontWeight(FontWeight.Medium).fontColor('#333')
          .maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })

        Row({ space: 8 }) {
          Text(`${recipe.calories} kcal`)
            .fontSize(11).fontColor('#FF6B35')
            .padding({ left: 6, right: 6, top: 2, bottom: 2 })
            .backgroundColor('#FFF0E6').borderRadius(4)

          if (recipe.tags && recipe.tags.length > 0) {
            Text(recipe.tags.slice(0, 2).join(' · '))
              .fontSize(11).fontColor('#999')
              .maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
          }
        }

        Text(recipe.ingredients.slice(0, 3).join('、'))
          .fontSize(11).fontColor('#999')
          .maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      // 箭头
      SymbolGlyph($r('sys.symbol.chevron_right'))
        .fontSize(16).fontColor(['#CCC'])
    }
    .width('100%').padding(14)
    .backgroundColor(Color.White).borderRadius(12)
    .shadow({ radius: 4, color: '#10000000', offsetY: 2 })
  }
}

核心点解读

  • HSP 导入import { recommendEngine } from 'shared'------通过 oh-package.json5 声明的依赖名引用共享模块,路径简洁且不依赖文件系统层级
  • Want 拉起主应用handleRecipeClick 中构造 Want 对象,指定 bundleName: 'com.annan.lingxikitchen'abilityName: 'EntryAbility'。系统收到此 Want 后,如果主应用已安装则直接跳转,如果未安装则引导下载
  • 默认偏好 :元服务不依赖用户登录,使用空偏好调用 recommendEngine.getRecommendations()。推荐引擎在偏好为空时返回通用高质量菜谱
  • 三态渲染:加载中(LoadingProgress + 提示文字)、错误状态(Emoji + 错误信息 + 重试按钮)、结果列表(4 张菜谱卡片),覆盖全部 UI 状态
  • 刷新机制:顶部刷新按钮让用户重新计算推荐,去重历史自动避免重复推荐

四、代码增删改清单

文件 新增/修改 职责
atomicservice/src/main/ets/entryability/AtomicServiceAbility.ets 新增 元服务入口 Ability,极简初始化 + 加载推荐页
atomicservice/src/main/ets/pages/Index.ets 新增 一键推荐 UI:三态渲染 + Want 跳转 + HSP 导入
atomicservice/src/main/resources/base/profile/main_pages.json 新增 页面路由声明
atomicservice/src/main/resources/base/element/string.json 新增 模块描述、Ability 标签等字符串资源
atomicservice/build-profile.json5 新增 声明 atomicService 编译类型
atomicservice/hvigorfile.ts 新增 模块编译入口
atomicservice/oh-package.json5 新增 声明 shared HSP 依赖

📌 以下配置文件的完整代码见下一篇《工程集成篇》

  • atomicservice/src/main/module.json5type: "feature"installationFree: trueskills 搜索索引)
  • shared/Index.ets(HSP 导出入口)
  • shared/oh-package.json5(HSP 模块声明)
  • entry/oh-package.json5(新增 shared 依赖)
  • 根目录 build-profile.json5(modules 数组新增 shared + atomicservice)

五、设计决策

决策 选择 理由
元服务入口 单一 Ability + 单一页面 原子化服务的核心价值是"轻",一个推荐场景不需要多页面路由
代码复用 HSP 共享包(shared 模块) 按官方指南单团队场景推荐,编译产物收敛,路径不依赖文件系统
用户偏好 元服务使用空偏好(默认推荐) 免登录场景下无法获取用户偏好数据,空偏好 + 季节加权保证推荐质量
点击跳转 Want.startAbility 拉起主应用 元服务只负责"推荐",不负责"详情"。点击后由主应用接力
刷新机制 顶部刷新按钮 原子化服务不支持下拉刷新手势(与系统导航手势冲突)
卡片数量 4 道菜 与主应用首页推荐保持一致,移动端一屏可见 3-4 张卡片

六、运行与结果验证

6.1 前置条件

  • 已完成三模块工程搭建(见下一篇《工程集成篇》)
  • 使用自动签名或手动签名(元服务签名配置与主应用相同)

6.2 操作步骤

  1. DevEco Studio 中 Run atomicservice 模块到模拟器或真机
  2. 元服务加载推荐页 → 显示 4 道推荐菜谱卡片
  3. 点击刷新按钮 → 重新计算推荐,卡片内容可能变化
  4. 点击某道菜 → 系统拉起主应用 → 跳转到 RecipeDetailPage

6.3 预期日志

复制代码
[AtomicServiceAbility] AtomicServiceAbility onCreate
[AtomicServiceAbility] AtomicServiceAbility onWindowStageCreate
[AtomicServiceAbility] 元服务推荐页加载成功
[RecommendEngine] 偏好: , 食材: , 季节: 春季
[RecommendEngine] 推荐结果: 红烧肉、清蒸鲈鱼、番茄炒蛋、酸辣汤
[AtomicRecommend] 跳转主应用 → 红烧肉

七、注意事项

7.1 原子化服务的冷启动优化

  • 元服务模块不引入任何不必要的 Kit(如 @kit.NotificationKit@kit.HealthKit
  • 页面只渲染首屏可见内容,不做预加载
  • AtomicServiceAbility.onCreate 中不做任何网络请求或文件 I/O

7.2 原子化服务不支持的 API

在 API 23 中,原子化服务模块不支持以下能力:

  • @kit.NotificationKit(通知发送)
  • @kit.BackgroundTasksKit(后台任务)
  • ServiceExtensionAbility(后台服务)
  • DataShareExtensionAbility(数据共享)

如果需要通知能力,应引导用户下载完整应用。

7.3 Want 拉起主应用的 fallback

如果用户设备上未安装主应用,startAbility(want) 会失败。生产环境中应使用 startAbility(want, {}) 的二参数版本,或通过 @kit.AbilityKitopenLink 跳转到 AppGallery 引导下载。


八、本阶段总结与下篇预告

今天,我们为《灵犀厨房》构建了一键烹饪推荐原子化服务------实现了"免安装、即点即用"的极致轻量体验:

  • HSP 共享包架构 :遵循华为官方指南,shared HSP 模块集中管理推荐引擎和数据模型,entry 和 atomicservice 共享引用
  • 极致精简AtomicServiceAbility 不做任何复杂初始化,onCreate 只设颜色模式,onWindowStageCreate 只加载页面
  • 3 秒体验:用户搜索 → 系统加载元服务 → 推荐引擎计算 → 卡片展示,全链路 < 3 秒
  • Want 无缝衔接 :点击菜谱卡片通过 Want 拉起主应用,元服务"种草"、主应用"成交"

但元服务要和主应用真正打通,还需要解决工程配置、模块划分、参数传递等一系列问题------这就是下一篇的主题。

下篇预告 :下一篇 《【元服务】三模块一体化工程集成------打通免安装跳转的最后一公里》 。我们将把元服务模块主应用整合到同一工程中,完成 HSP 共享包搭建、EntryAbility 路由改造、RecipeBridge 参数桥梁实现,覆盖冷启动/热启动/后台唤起全部场景。


📚 本系列持续更新中:下一篇将完成元服务的工程集成,打通 Want 跳转参数桥梁。

🔗 专栏入口《HarmonyOS6.1全场景实战》合集
📦 获取基线版本源码包包括第1-15篇代码 + 架构文档 + Flask 后端

如果你觉得这篇文章对你有帮助,请不要吝啬你的点赞 👍、收藏 ⭐ 和评论 💬。你的支持,是我继续输出高质量技术内容的全部动力。

纯血鸿蒙,免安装直达美味。我们下一篇见!

相关推荐
若兰幽竹10 小时前
HarmonyOS 6.1 开发者盛宴|《灵犀厨房》实战(十九):【通知系统】延时烹饪提醒——让通知不再错过关键步骤
华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹6 天前
HarmonyOS 6.1 全场景实战|《灵犀厨房》实战(十八):【手表协同】烹饪计时器流转至智能手表——手腕掌控烹饪节奏
智能手表·华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹9 天前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战(十七):【语音识别】免提声控启动播报——动口不动手
语音识别·华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹10 天前
【HarmonyOS6.1全场景实战】基线版本:我用了15篇文章,造出了一个能登录、能推荐、带后台的鸿蒙全栈App
华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹11 天前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战(十五)之【超级设备模拟器实战】多设备交互调试:像上帝一样俯瞰整个智能厨房
华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹11 天前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战(十四)之【分布式流转】让菜谱“飞”:手机选、平板看、智慧屏播的全场景秘诀
分布式·华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹11 天前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战(十三)之【智能厨电模拟】用代码“凭空”创造智能厨房:《灵犀厨房》的全场景前奏
华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹11 天前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战(十二)之【营养分析引擎】计算个性化卡路里建议:给《灵犀厨房》装上“营养大脑”
华为鸿蒙系统·harmonyos6.1.0·灵犀厨房
若兰幽竹13 天前
【HarmonyOS 6.1 全场景实战】《灵犀厨房》实战之补充【架构进化】灵犀厨房四层分层设计:给鸿蒙 App 搭一副坚不可摧的骨架
架构·鸿蒙系统·harmonyos6.1.0·灵犀厨房