在这里插入图片描述
在这里插入图片描述

本文基于HarmonyOS NEXT平台,使用ArkTS语言和ArkUI框架,从零构建一款离线可用的智能菜谱推荐应用。文章涵盖接口设计、推荐引擎算法、声明式UI构建、AI集成预留等核心内容,适合正在学习鸿蒙原生开发的开发者阅读。


一、引言:为什么选择鸿蒙原生开发

在移动应用开发领域,跨平台方案长期占据主流地位。React Native、Flutter等框架让开发者能够用一套代码覆盖多个平台,降低了开发成本。然而,随着HarmonyOS NEXT的发布,鸿蒙生态正式迈入"纯血"时代——不再兼容Android应用,所有应用必须基于ArkTS语言和ArkUI框架进行原生开发。

这一变革带来了全新的技术栈和开发范式。对于开发者而言,掌握ArkTS语言特性、理解ArkUI声明式编程模型、熟悉鸿蒙API体系,已经成为进入鸿蒙生态的必备技能。本文将以一款"智能菜谱推荐"应用为例,完整展示HarmonyOS NEXT应用的开发全流程。

智能菜谱推荐是一个典型的需求驱动型应用。用户在日常烹饪中经常面临"不知道做什么菜"的困境,尤其是当冰箱里只有有限的食材时。本应用通过离线推荐引擎,根据用户输入的食材、偏好的菜系、可用的烹饪时间、烹饪难度和口味偏好,智能匹配最合适的菜谱,并提供详细的烹饪步骤、技巧提示和营养信息。

选择这个应用作为示例,是因为它涵盖了鸿蒙原生开发中的多个核心知识点:复杂数据模型的接口定义、基于多维评分算法的推荐引擎、声明式UI的组件化构建、状态管理机制、以及面向未来的AI集成架构设计。通过这个案例,读者可以系统性地理解ArkTS开发的全貌。


二、应用功能全景

智能菜谱推荐应用围绕"帮助用户快速找到想做的菜"这一核心目标,设计了五个维度的筛选条件和完整的结果展示体系。

2.1 五大筛选维度

菜系选择 覆盖中国八大菜系加上日料和西餐,共计十个选项:川菜、粤菜、鲁菜、苏菜、浙菜、湘菜、闽菜、徽菜、日料、西餐。用户可以选择特定菜系,也可以不选,让推荐引擎在所有菜系中寻找最佳匹配。每个菜系选项以圆角芯片(Chip)的形式呈现,选中状态采用品牌橙色高亮,未选中状态为浅灰色背景,视觉层次清晰。

食材输入 是一个自由文本输入框,支持用户输入手头现有的食材,多个食材之间用逗号、中文逗号或顿号分隔。例如输入"鸡肉、青椒、花生",推荐引擎会解析这些食材,并在菜谱库中寻找包含这些食材的菜谱。这种设计模拟了真实场景:用户打开冰箱,看到有什么食材,就输入什么食材。

烹饪时间选择 提供六个预设时间档位:15分钟、30分钟、45分钟、60分钟、90分钟、120分钟。时间匹配采用模糊评分机制——完全匹配得高分,相近时间得中等分数,差异较大得低分。这种设计考虑到用户对时间的容忍度,比如用户选择30分钟,但实际上25分钟的菜也是可以接受的。

难度选择 分为四个等级:新手、入门、进阶、大厨。这四个等级对应不同的烹饪技巧要求。新手级别的菜谱通常步骤简单、容错率高;大厨级别的菜谱则涉及复杂的技巧和较长的烹饪时间。用户可以根据自己的烹饪水平选择合适的难度。

口味偏好 包含五种选择:辣、清淡、甜、酸、咸鲜。口味是连接用户和菜谱的重要纽带。一个喜欢辣味的用户,即使食材匹配度一般,也更愿意尝试辣味菜谱。口味偏好作为推荐算法的重要加权因子。

2.2 结果展示体系

推荐结果以卡片形式呈现,包含以下信息层次:

菜名与标签:菜名以大号粗体字显示,下方四个彩色标签分别展示菜系、难度、口味和烹饪时间,让用户一目了然。

食材清单:以圆角标签列表的形式展示所有所需食材,每个食材一个标签,方便用户快速核对是否具备所有材料。

烹饪步骤:每个步骤以编号圆圈加文字描述的形式呈现,编号圆圈采用品牌橙色,形成清晰的视觉引导。用户按步骤操作即可完成烹饪。

烹饪技巧:一段简明的文字提示,包含该菜品的核心技巧和注意事项,帮助用户避免常见错误。

营养信息:以四个等宽卡片展示热量、蛋白质、脂肪、碳水化合物的含量,采用暖色背景与品牌橙色数字,视觉上温暖而专业。


三、技术架构设计

3.1 整体架构

本应用采用单文件架构,所有代码集中在Index.ets文件中。虽然单文件架构在大型项目中不常见,但对于这个规模适中的应用来说,它带来了几个明显的优势:代码导航简单、依赖关系清晰、构建速度快。整个应用分为四个逻辑层次:

数据层(Data Layer):包含接口定义和模拟数据。接口定义了菜谱、营养信息、烹饪步骤等核心数据结构。模拟数据包含10道来自不同菜系的菜谱,每道菜都有完整的食材、步骤、技巧和营养信息。

引擎层(Engine Layer):推荐引擎是整个应用的核心。它实现了基于多维加权评分的菜谱匹配算法,综合考虑菜系、食材、时间、难度和口味五个维度,为每个菜谱计算匹配分数,最终推荐得分最高的菜谱。

UI层(UI Layer):基于ArkUI声明式框架构建,使用@Builder装饰器实现组件化,@State装饰器管理页面状态。筛选区域使用可滚动布局,结果区域使用卡片式设计。

集成层(Integration Layer):预留了LLM API调用接口,以注释形式保留了完整的HTTP请求代码,开发者只需填入API Key即可激活AI增强功能。

3.2 数据模型设计

数据模型是应用的基石。本应用定义了五个核心接口:

  • NutritionInfo:营养信息,包含热量、蛋白质、脂肪、碳水化合物四个字段,全部使用字符串类型以便灵活展示(如"320千卡"、“28g”)。
  • RecipeStep:烹饪步骤,包含步骤编号和步骤描述。
  • Recipe:菜谱主模型,包含菜谱ID、名称、菜系、食材列表、烹饪时间、难度、口味、步骤列表、烹饪技巧和营养信息。
  • TimeOption:时间选项,包含显示标签和对应的分钟数值。
  • OptionItem:通用选项接口,包含标签和值。

所有接口都使用ArkTS的interface关键字定义,字段类型全部显式声明,不使用any类型,确保类型安全。这种设计在编译阶段就能发现潜在的类型错误,提高代码质量。

3.3 推荐引擎算法

推荐引擎是本应用的智能核心。它采用加权评分机制,算法流程如下:

  1. 解析用户输入的食材字符串,分割并去空白,得到食材列表。
  2. 遍历所有菜谱,对每个菜谱计算匹配分数。
  3. 菜系匹配:完全匹配加30分。
  4. 食材匹配:每个匹配的食材加15分(支持模糊匹配,如"鸡"可以匹配"鸡胸肉")。
  5. 时间匹配:时间差在10分钟内加25分,20分钟内加15分,30分钟内加5分。
  6. 难度匹配:完全匹配加20分。
  7. 口味匹配:完全匹配加20分。
  8. 选择得分最高的菜谱作为推荐结果。

这个算法的时间复杂度为O(nmk),其中n为菜谱数量,m为用户输入的食材数量,k为每个菜谱的食材数量。在10道菜谱的规模下,性能完全不是问题。当菜谱库扩展到数百道时,仍然可以在一帧内完成计算。

算法的巧妙之处在于各维度的权重设计。菜系和口味的匹配权重较高(30分和20分),因为它们反映了用户的主观偏好。食材匹配采用累加机制,输入的食材越多,匹配越精准。时间匹配采用阶梯式递减,体现了用户对时间的容忍弹性。


四、核心代码详解

4.1 接口定义

ArkTS使用interface关键字定义数据类型,这与TypeScript一致,但ArkTS对接口的使用有更严格的约束。在本应用中,所有数据模型都通过接口定义:

interface NutritionInfo { calories: string; protein: string; fat: string; carbs: string; }
interface RecipeStep { step: number; desc: string; }
interface Recipe {
  id: number; name: string; cuisine: string; ingredients: string[];
  cookingTime: number; difficulty: string; taste: string;
  steps: RecipeStep[]; tips: string; nutrition: NutritionInfo;
}

这种紧凑的接口定义风格在ArkTS中是完全合法的。每个字段都有明确的类型注解,ingredientssteps使用数组类型,steps中的元素类型为RecipeStep,形成了嵌套的接口结构。注意我们没有使用any类型,也没有使用解构赋值——这些都是在ArkTS中需要避免的模式。

4.2 模拟数据构建

模拟数据是应用离线运行的基础。我们构建了10道菜谱,覆盖了10个不同的菜系,每道菜包含5个烹饪步骤和完整的营养信息。菜谱的选择遵循以下原则:每个菜系至少一道代表性菜品,难度从入门到大厨均匀分布,口味覆盖辣、清淡、甜、咸鲜四种类型,烹饪时间从15分钟到120分钟均有覆盖。

以宫保鸡丁为例,数据结构展示了完整的菜谱信息:

{ id:1, name:'宫保鸡丁', cuisine:'川菜', difficulty:'入门', taste:'辣', cookingTime:25,
  ingredients:['鸡胸肉','花生','干辣椒','花椒','葱','姜','蒜','酱油','醋','糖','淀粉','料酒'],
  steps:[
    {step:1,desc:'鸡胸肉切丁,加料酒、酱油、淀粉腌制15分钟'},
    {step:2,desc:'调碗汁:酱油、醋、糖、淀粉、水混合均匀'},
    {step:3,desc:'小火炒花生米至金黄酥脆,盛出备用'},
    {step:4,desc:'热锅凉油,下干辣椒和花椒爆香,放入鸡丁翻炒至变色'},
    {step:5,desc:'加入葱姜蒜炒香,倒入碗汁翻炒均匀,撒入花生米出锅'}
  ],
  tips:'鸡丁需提前腌制确保嫩滑,花生米最后放入保持酥脆口感',
  nutrition:{calories:'320千卡',protein:'28g',fat:'18g',carbs:'12g'} }

这种紧凑的数据格式在保持可读性的同时,最大化了空间利用率。每个菜谱只占4行代码,10道菜谱共40行,再加上接口定义和其他代码,整个应用控制在257行以内,远低于500行的目标。

4.3 推荐引擎实现

推荐引擎的核心逻辑封装在recommendRecipe方法中。该方法首先解析用户输入的食材字符串,支持中文逗号、顿号和英文逗号作为分隔符,通过replacesplit方法进行标准化处理,然后trim去空白,filter过滤空字符串。

食材匹配采用了双向模糊匹配策略:recipe.ingredients[k].includes(uIng) || uIng.includes(recipe.ingredients[k]),这意味着用户输入"鸡"可以匹配"鸡胸肉",用户输入"豆腐"也可以匹配"嫩豆腐"。这种模糊匹配显著提升了用户体验,用户不需要记住精确的食材名称。

时间匹配采用了阶梯式评分机制,通过Math.abs计算时间差的绝对值,然后根据差值所在的区间赋予不同的分数。这种设计比简单的完全匹配更加人性化——用户说"我有30分钟",并不意味着拒绝25分钟或35分钟的菜谱。

4.4 声明式UI构建

ArkUI采用声明式编程范式,通过build方法描述UI结构。本应用使用了@Builder装饰器来实现组件化,将可复用的UI片段封装为构建器方法。

chip构建器是应用中最常用的UI组件,它封装了选择芯片的样式和行为:

@Builder
chip(label: string, selected: boolean, action: () => void): void {
  Text(label).fontSize(13).padding({left:14,right:14,top:7,bottom:7}).borderRadius(20)
    .backgroundColor(selected ? '#FF6B35' : '#F5F5F5')
    .fontColor(selected ? '#FFFFFF' : '#555555')
    .fontWeight(selected ? FontWeight.Medium : FontWeight.Normal)
    .margin({right:8,bottom:6}).onClick(action)
}

这个构建器接收三个参数:标签文本、选中状态和点击回调。选中时使用品牌橙色背景和白色文字,未选中时使用浅灰色背景和深灰色文字。通过onClick绑定点击事件,实现了芯片的切换选中逻辑。

resultCard构建器负责展示推荐结果,内部使用了taginfoBlocknutritionItem三个子构建器,形成了清晰的组件层级。这种分层设计使得代码结构清晰,每个构建器职责单一,便于维护和扩展。

4.5 状态管理

ArkTS使用@State装饰器管理组件状态。当@State修饰的变量发生变化时,ArkUI框架会自动重新渲染受影响的UI部分。本应用定义了七个@State变量:

  • selectedCuisine:当前选中的菜系
  • ingredientsText:用户输入的食材文本
  • selectedTime:当前选中的烹饪时间
  • selectedDifficulty:当前选中的难度
  • selectedTaste:当前选中的口味
  • showResult:是否显示推荐结果
  • resultRecipe:当前推荐的菜谱对象

这种方式遵循了"单一数据源"原则,所有UI状态都通过@State变量管理,UI只负责展示和触发事件,不持有任何业务逻辑。当用户点击"智能推荐菜谱"按钮时,recommendRecipe方法更新resultRecipeshowResult,ArkUI自动刷新结果卡片区域。


五、AI集成架构设计

5.1 LLM API预留方案

本应用在设计之初就考虑了AI增强的可能性。在代码中预留了完整的LLM API调用接口,以注释形式存在于callLLMAPI方法中。该方法使用HarmonyOS的@ohos.net.http模块发起HTTP请求,调用OpenAI兼容的Chat Completions API。

// private async callLLMAPI(recipe: Recipe): Promise<string> {
//   const http = require('@ohos.net.http').createHttp();
//   const body: string = JSON.stringify({
//     model:'gpt-4',
//     messages:[
//       {role:'system',content:'你是专业烹饪助手'},
//       {role:'user',content:'请为' + recipe.name + '提供额外烹饪技巧'}
//     ],
//     max_tokens:500
//   });
//   const res = await http.request('https://api.openai.com/v1/chat/completions', {
//     method:'POST',
//     header:{'Content-Type':'application/json','Authorization':'Bearer YOUR_API_KEY'},
//     extraData:body
//   });
//   http.destroy(); return res.result;
// }

5.2 激活步骤

要激活AI功能,开发者需要完成以下步骤:

  1. module.json5中确认已添加网络权限ohos.permission.INTERNET
  2. YOUR_API_KEY替换为实际的API密钥。
  3. 取消callLLMAPI方法及其调用的注释。
  4. 在推荐结果展示区域添加AI建议的显示组件。

5.3 AI增强场景

AI可以为菜谱推荐带来以下增强能力:

个性化烹饪建议:基于用户的饮食偏好、过敏信息和烹饪设备,提供定制化的烹饪建议。例如,用户没有烤箱时,AI可以建议替代的烹饪方法。

食材替换方案:当用户缺少某些食材时,AI可以智能推荐替代品。例如,没有料酒时可以用白葡萄酒替代,没有淀粉时可以用面粉替代。

营养优化建议:根据用户的健康目标(减脂、增肌、控糖等),AI可以提供营养优化方案,如减少油盐用量、替换高热量食材等。

多轮对话交互:通过多轮对话,AI可以逐步了解用户的具体需求,提供更精准的菜谱推荐。例如,用户说"我想吃鱼",AI可以进一步询问喜欢清蒸还是红烧、偏好什么口味等。


六、设计决策与权衡

在开发过程中,我们做出了若干关键的设计决策,每一项都有其特定的考量。

6.1 单文件架构 vs 多文件架构

我们选择了单文件架构,将接口定义、数据、引擎和UI全部放在一个Index.ets文件中。这个决策基于以下考量:

优势:代码导航简单,无需在多个文件之间切换;依赖关系清晰,所有引用都在同一个文件中;构建速度快,ArkTS编译器只需处理一个文件;适合应用规模较小的情况。

局限:当应用规模增长到数千行时,单文件会变得难以维护。此时应该按照功能模块拆分,例如将数据模型、推荐引擎、UI组件分别放在独立文件中。

6.2 离线推荐 vs 在线推荐

我们选择了离线推荐引擎作为核心方案,而非依赖云端API。这个决策基于以下原因:

即时响应:离线计算在本地完成,响应时间在毫秒级别,无需等待网络请求。

无网络依赖:用户在地下室、电梯等网络不佳的环境下也能正常使用。

隐私保护:用户输入的食材信息不会上传到服务器,保护隐私。

零成本:没有API调用费用,应用可以无限次使用。

当然,离线方案的局限性也很明显:菜谱库规模有限,无法获取实时数据,推荐算法相对简单。这正是我们预留AI集成接口的原因——未来可以将离线引擎与在线AI结合,实现"离线快速推荐+在线深度优化"的混合模式。

6.3 评分算法 vs 机器学习

我们选择了基于规则的加权评分算法,而非机器学习模型。评分算法的优势在于:可解释性强,用户可以理解为什么推荐了某道菜;开发成本低,不需要训练数据和模型训练;调试方便,修改权重即可调整推荐行为。当菜谱库规模较小时,评分算法的效果与机器学习模型差距不大。

6.4 品牌色选择

应用的主色调选择了暖橙色(#FF6B35),这是一个与食物和烹饪高度相关的颜色。橙色能唤起食欲,传递温暖和活力的感觉。背景色使用了浅奶油色(#FFF8F3),营造温馨舒适的视觉氛围。标签颜色采用了多色方案:菜系标签用橙色、难度用绿色、口味用琥珀色、时间用蓝色,通过颜色编码帮助用户快速区分信息类型。


七、未来路线图

7.1 短期规划(1-3个月)

菜谱库扩展:将模拟菜谱从10道扩展到50道以上,覆盖更多菜系和菜品类型。引入素食、清真等特殊饮食需求的菜谱。

收藏功能:允许用户收藏喜欢的菜谱,方便快速查找。使用HarmonyOS的Preferences API实现本地持久化存储。

历史记录:记录用户的推荐历史,方便回溯。同时为未来的个性化推荐积累数据。

食材拍照识别:集成HarmonyOS的视觉AI能力,用户拍照识别冰箱里的食材,自动填入食材输入框。

7.2 中期规划(3-6个月)

AI功能激活:正式接入LLM API,实现个性化烹饪建议、食材替换方案和营养优化建议。

社区功能:用户上传自己的菜谱,分享烹饪心得。引入评分和评论机制,形成菜谱社区。

语音交互:集成鸿蒙的语音识别能力,用户通过语音输入食材和偏好,语音播报烹饪步骤。

购物清单:根据推荐菜谱自动生成购物清单,按食材分类整理,方便用户采购。

7.3 长期规划(6-12个月)

多设备协同:利用鸿蒙的分布式能力,实现手机推荐菜谱、平板查看步骤、智慧屏播放烹饪视频的多设备协同体验。

健康管理集成:与鸿蒙健康平台打通,根据用户的健康数据(体重、运动量、饮食记录)提供个性化的营养建议。

智能厨房生态:与智能厨电联动,自动设置烤箱温度、电磁炉火力等参数,实现一键烹饪。

多语言支持:扩展菜谱的多语言版本,覆盖更多国家和地区的饮食文化。


八、开发要点总结

8.1 ArkTS开发注意事项

通过本次开发实践,我们总结了以下ArkTS开发的要点:

类型安全:始终使用显式类型注解,避免使用any。利用接口定义复杂数据结构,让编译器帮助发现类型错误。

避免解构:ArkTS不支持解构赋值语法,需要使用传统的对象属性访问方式。例如使用recipe.name而非const { name } = recipe

状态管理:使用@State装饰器管理组件状态,避免在build方法中直接修改状态变量。状态更新会自动触发UI重新渲染。

组件化:使用@Builder装饰器封装可复用的UI片段,提高代码复用率和可维护性。

声明式UI:采用声明式编程范式,通过链式调用属性方法描述UI样式,而非命令式地操作DOM。

8.2 性能优化建议

列表渲染:使用ForEach组件渲染列表,并为其提供唯一的键值生成函数,帮助框架高效地进行差异更新。

条件渲染:使用if语句进行条件渲染,避免渲染不可见的UI元素,减少不必要的布局计算。

避免深层嵌套:过多的UI嵌套层级会增加布局计算开销,尽量保持UI结构扁平化。

合理使用Scroll:当内容超出屏幕时使用Scroll组件,但不要将所有内容都放在Scroll中,固定区域(如标题栏)应该放在Scroll外部。


九、结语

智能菜谱推荐应用展示了HarmonyOS NEXT平台下ArkTS开发的完整流程。从接口定义到数据建模,从推荐算法到声明式UI,从状态管理到AI集成预留,我们覆盖了鸿蒙原生开发的多个核心知识点。

这个应用虽然功能相对简单,但架构设计上预留了充足的扩展空间。离线推荐引擎保证了基础体验的流畅性,AI集成接口为未来的智能化升级做好了准备。单文件架构在保持代码简洁的同时,也展示了良好的代码组织方式。

随着鸿蒙生态的不断壮大,掌握ArkTS和ArkUI开发技能将成为越来越多开发者的迫切需求。希望本文能够为正在学习鸿蒙原生开发的读者提供有价值的参考,帮助大家更快地适应这个充满活力的新平台。

鸿蒙的征途才刚刚开始,让我们共同期待这个生态的蓬勃发展。


附录:项目文件结构

智能菜谱推荐/
├── Index.ets          # 主应用文件(257行)
│   ├── 接口定义        # NutritionInfo, RecipeStep, Recipe 等
│   ├── 模拟菜谱数据     # 10道菜谱,覆盖10个菜系
│   ├── 推荐引擎        # 多维加权评分算法
│   ├── LLM API 预留   # 注释状态,待激活
│   └── ArkUI 界面     # 声明式UI,组件化构建
└── blog.md            # 本文档

环境要求:HarmonyOS NEXT, API Version 24, ArkTS, ArkUI

权限配置:在src/main/module.json5中添加"requestPermissions": [{"name": "ohos.permission.INTERNET"}]


作者注:本文代码基于HarmonyOS NEXT平台开发,部分API可能随平台版本更新而变化。建议开发者参考最新的官方文档进行开发。

十、鸿蒙生态与开发者机遇

在深入探讨了开发技术细节之后,有必要从更宏观的视角审视鸿蒙生态的发展现状和开发者面临的机遇。HarmonyOS NEXT的发布,标志着华为在操作系统领域迈出了决定性的一步。与之前的版本不同,NEXT版本彻底移除了Android兼容层,采用了完全自研的鸿蒙内核,实现了从底层内核到上层应用框架的全面自主可控。

对于开发者而言,这意味着几个重要的变化。首先,开发工具链全面升级。DevEco Studio作为鸿蒙官方IDE,提供了从代码编写、调试、性能分析到应用发布的完整工具链。ArkTS语言在TypeScript的基础上进行了裁剪和增强,移除了动态类型相关的特性,强化了静态类型检查,使得代码更加安全可靠。ArkUI框架采用了声明式编程范式,开发者通过描述UI的"应该是什么样"而非"如何构建UI"来编写界面代码,极大地降低了UI开发的复杂度。

其次,鸿蒙的分布式能力为开发者打开了全新的想象空间。传统的移动应用开发中,每个设备上的应用是独立运行的,设备之间的数据同步和协同需要开发者手动实现。而鸿蒙通过分布式软总线、分布式数据管理和分布式任务调度等底层能力,让跨设备协同变得像在同一设备上操作一样自然。开发者只需要关注业务逻辑,底层的设备发现、连接管理和数据同步由系统自动完成。

第三,鸿蒙的原子化服务架构为应用分发提供了新的渠道。传统的应用分发依赖应用商店,用户需要下载安装完整的应用包。而原子化服务,也称元服务,允许用户无需安装即可使用应用的核心功能,通过服务卡片、负一屏、智慧搜索等触点触达用户。这种轻量化的分发方式降低了用户的使用门槛,提高了应用的转化率。对于菜谱推荐这类工具型应用来说,原子化服务是一个极具吸引力的分发形态。用户可以在负一屏的服务卡片上看到今日推荐菜谱,点击即可进入完整功能,无需下载安装。

最后,从市场规模来看,鸿蒙已经成为全球第三大移动操作系统。10亿级的设备连接数、数千万的开发者注册量、以及头部应用的集体入驻,都表明鸿蒙生态正在从"可用"走向"好用"。对于正在考虑学习鸿蒙开发的开发者来说,现在是一个非常好的时机。早期入场的开发者能够享受生态红利,在竞争相对较小的蓝海市场中建立自己的优势。


十一、测试策略与质量保障

虽然本应用规模不大,但测试和质量保障仍然是不可忽视的环节。在鸿蒙开发中,测试分为三个层次:单元测试、UI测试和集成测试。

单元测试主要针对推荐引擎的算法逻辑。推荐引擎的输入输出非常明确,输入是用户选择的筛选条件,输出是匹配度最高的菜谱。这使得单元测试的编写变得非常简单。我们可以设计多组测试用例:正常情况下的食材匹配、边界情况下的空输入处理、极端情况下的所有条件都不匹配时的兜底行为。例如,当用户输入空字符串时,推荐引擎应该能正常运行并返回一个结果,而不是崩溃或返回空值。当用户选择了不存在的菜系时,菜系匹配应该得零分,但不影响其他维度的计算。

UI测试主要验证界面元素的正确渲染和交互响应。在ArkUI中,UI测试可以通过自动化测试框架实现。测试用例应该覆盖芯片的选中与取消选中切换、输入框的文本输入和清除、推荐按钮的点击触发、以及结果卡片的正确显示。特别需要注意的是,当推荐结果产生后,再次修改筛选条件并再次推荐时,UI应该正确更新为新的结果,而不是残留旧的结果。

集成测试验证整个推荐流程的端到端正确性。从用户输入食材、选择菜系、设置难度和口味,到点击推荐按钮、查看结果卡片,整个过程应该流畅无阻。结果卡片中显示的所有信息,包括菜名、标签、食材列表、烹饪步骤、技巧和营养信息,都应该与模拟数据中的记录严格一致。

对于AI集成的测试,需要特别注意网络异常情况的处理。当LLM API不可用或返回错误时,应用应该优雅降级,回退到离线推荐结果,而不是崩溃或显示空白页面。这种容错设计是生产级应用的基本要求。

此外,性能测试也应该纳入考量。虽然当前10道菜谱的规模下性能完全不是问题,但开发者应该养成测量性能的习惯。可以使用DevEco Studio自带的性能分析工具,监控
ecommendRecipe方法的执行时间。如果未来菜谱库扩展到数百道,可能需要考虑引入索引结构来优化食材匹配的查询效率,例如将食材到菜谱的映射关系预计算为倒排索引。


十二、从菜谱推荐看鸿蒙应用的设计哲学

回顾整个开发过程,可以发现鸿蒙应用的设计哲学与传统的Android应用有着显著的不同。这些差异不仅体现在技术层面,更体现在设计理念上。

首先是"意图驱动"的设计理念。在鸿蒙的设计体系中,用户的操作被抽象为"意图",系统根据意图智能地调度资源和服务。以菜谱推荐为例,用户的意图是"根据现有食材找到合适的菜谱",这个意图可以通过多个入口触发:在主应用中输入食材、通过语音助手说出食材、通过服务卡片看到的快捷入口、甚至是通过拍照识别食材后自动触发。无论从哪个入口进入,用户最终都能获得一致的推荐体验。这种设计理念要求开发者将核心业务逻辑与UI展示解耦,使业务逻辑可以服务于多个入口。

其次是"一次开发,多端部署"的核心理念。虽然本应用目前只实现了手机端,但得益于ArkUI的响应式布局能力,代码可以比较轻松地适配到平板、智慧屏等不同尺寸的设备上。在适配时,主要需要调整的是布局参数:在手机上使用单列布局,在平板上可以使用双列布局,在智慧屏上则需要增大字体和间距。业务逻辑和推荐引擎完全不需要修改。

第三是"服务化"的架构倾向。在鸿蒙生态中,应用不再是孤立的个体,而是可以被其他应用发现和调用的服务。菜谱推荐的能力可以被封装为原子化服务,供其他应用集成。例如,一个生鲜电商应用可以调用菜谱推荐服务,当用户购买食材时自动推荐相关菜谱。一个健康管理应用可以调用菜谱推荐服务,根据用户的健康数据推荐营养均衡的菜谱。这种服务化的架构大大提升了应用的价值和复用性。

最后是"安全与隐私"的底线思维。鸿蒙在权限管理上非常严格,网络权限、存储权限等敏感权限必须显式声明,并在运行时获得用户授权。本应用仅需要网络权限用于AI API调用,在离线模式下甚至不需要任何权限。这种最小权限原则保护了用户的隐私,也降低了应用的安全风险。开发者在设计应用时,应该始终遵循"最小权限原则",只申请必要的权限,并在不需要时主动释放。



十三、写在最后:技术选择背后的价值观

在完成这个智能菜谱推荐应用的开发后,回过头来看,我们做出的每一个技术选择背后都蕴含着特定的价值观。选择ArkTS而非跨平台框架,是因为我们相信原生体验的价值;选择离线推荐而非在线服务,是因为我们尊重用户的时间和数据隐私;选择简单算法而非复杂模型,是因为我们推崇"够用就好"的工程哲学;选择预留AI接口而非立即集成,是因为我们理解技术演进需要循序渐进。

这些价值观不仅适用于菜谱推荐这一个应用,也适用于更广泛的软件开发实践。在技术飞速发展的今天,开发者很容易被新技术的光环所吸引,追逐最新的框架、最热门的模型、最复杂的架构。但真正优秀的软件产品,往往是那些在技术选择上保持克制、在用户体验上追求极致、在工程实践上稳扎稳打的产品。

鸿蒙生态的发展为开发者提供了前所未有的机遇,而能否抓住这个机遇,关键在于能否用恰当的技术解决真实的问题,用优雅的代码创造美好的体验,用务实的工程态度构建可靠的软件。希望每一位读者都能在鸿蒙的世界里找到属于自己的位置,创造出属于自己的精彩。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐