码道托管 + MaaS赋能:鸿蒙原生健身应用实践 案例介绍本案例使用 DevEco Studio 与鸿蒙本地模拟器开展开发调试依托华为云码道实现代码自动生成并集成华为云 MaaS 大模型服务完成鸿蒙原生健身助手应用的全流程开发实现编码提效与 AI 智能的融合落地。案例内容一、概述1.1 案例介绍本案例使用 DevEco Studio 与鸿蒙本地模拟器开展开发调试依托华为云码道实现代码自动生成并集成华为云 MaaS 大模型服务完成鸿蒙原生健身助手应用的全流程开发实现编码提效与 AI 智能的融合落地。案例技术选型华为云码道CodeArts代码智能体一个理解项目需求懂得编码之道善用百器的实干派AI研发专家开启你的编码自动驾驶模式。本案例中作为核心开发工具通过智能体模式快速构建鸿蒙原生应用代码。DevEco Studio是 HarmonyOS 应用及服务的集成开发环境IDE提供了一站式的开发平台包括代码编辑、编译构建、代码调试、性能调优、模拟器、应用测试等能力。DevEco Studio提供了模拟器Emulator为开发者提供了运行和调试HarmonyOS应用/元服务的便捷方式。模拟器还原了真实设备的基本功能如屏幕旋转、音量调节、模拟的硬件传感器和指定设备的位置等。这使得您无需拥有不同类型的物理设备就可以在各种虚拟环境中轻松测试您的应用程序。在某些情况下在模拟器上进行应用测试相比于在实际物理设备上的测试有着更快速、更高效的体验。例如模拟器提供了摇一摇的操作模拟让您能够轻松触发摇一摇功能。通过DevEco Studio提供的模拟器您可以更灵活、更高效地进行应用开发和调试提升您的开发体验与效率。MaaS(MaaS模型即服务)是华为云面向AI开发者推出的一站式大模型开发平台支持开发者一键体验大模型能力快速构建大模型应用。Mass平台提供大模型训练、推理、部署、管理、监控等全生命周期管理能力帮助开发者快速构建大模型应用加速AI开发。1.2 适用对象企业个人开发者高校学生1.3 案例时间本案例总时长预计90分钟。1.4 案例流程说明开发者下载安装DevEco Studio并在DevEco Studio中安装配置华为云码道基于华为云码道接入MaaS大模型自动生成健身助手应用代码用户创建并连接本地模拟器使用模拟器调试运行健身助手应用代码。1.5 资源总览本案例预计花费0元。资源名称规格单价元华为云码道CodeArts代码智能体体验版免费ModelArts Studio大模型DS/K2/Q3等GLM-5.10.00DevEco Studio6.0.0 Release免费模拟器EmulatorHarmonyOS 6.0.0免费二、基础环境与资源准备2.1 下载安装DevEco Studio2.2 创建HarmonyOS工程2.3 创建本地模拟器2.4 DevEco Studio中安装华为云码道CodeArts代码智能体2.1 ~ 2.4节请参考案例《简记APP鸿蒙原生记账应用全流程开发实战》中的“二、基础环境与资源准备 2.1 ~ 2.4”章节完成DevEco Studio的下载安装、HarmonyOS工程创建、本地模拟器的创建及安装华为云码道CodeArts代码智能体。2.5 领取华为云MaaS平台大模型Tokens福利参考案例《华为开发者空间 - ModelArts Studio大模型通用代金券领取使用指导》中的“二、 开通MaaS平台大模型”章节内容领取代金券获取到模型的API地址、模型名称和API Key。注意记录API Key、API地址以及模型名称留作后面步骤使用。三、鸿蒙原生健身应用代码实践3.1 华为云码道赋能代码开发打开华为云码道CodeArts代码智能体对话框中输入以下提示词复制代码在当前项目目录下根据以下需求文档完成鸿蒙原生健身应用代码开发 1、整体需求概述 用户在前端页面录入个人健身相关信息性别、身高、年龄、当前体重、目标体重等确认信息无误后点击「获取私教建议」按钮前端收集完整用户参数并传递至后端服务后端调用华为云MaaS API接口将用户信息封装为智能分析请求接收AI返回的专业化私教建议内容最终将结果返回前端展示给用户完成智能化私教指导服务。 MaaS API参数如下 API_URL: string YOUR_API_URL; MODEL_NAME: string YOUR_MODEL_NAME; API_KEY: string Bearer YOUR_API_KEY; 2、功能需求 2.1 用户信息录入功能 该功能为系统基础前置功能支持用户完整录入个人身体及健身目标信息所有输入项做合法性校验确保传递给AI接口的数据准确有效。具体输入字段及规则如下 性别单选输入选项为男/女为必输项不可为空用于AI适配差异化健身方案男女身体机能、训练强度、减脂逻辑不同。 身高数值输入单位默认厘米cm支持正整数/一位小数设置合理数值区间130cm-230cm禁止空值、负数、非法字符用于计算用户BMI、适配训练负荷。 年龄数值输入支持正整数区间限制为18-80岁必输项禁止非法输入用于AI结合年龄段适配运动强度、规避运动风险。 当前体重数值输入单位默认千克kg支持正整数/一位小数设置合理数值区间40kg-140kg必输项用于分析用户当前体态、肥胖程度。 目标体重数值输入单位默认千克kg支持正整数/一位小数必输项需大于0用于AI制定减脂、塑形、增重等针对性目标方案。 额外功能支持用户一键清空输入内容方便用户重新录入信息输入框实时校验非法输入实时提示用户修改。 2.2 私教建议生成功能 该功能为系统核心核心业务功能基于用户录入的有效信息触发AI接口调用并生成专属私教建议完整流程如下 触发条件用户完整填写所有必填信息且全部字段校验通过后点击「获取私教建议」按钮触发后续业务逻辑若存在空值、非法数值按钮点击无效页面提示对应输入错误。 参数封装后端接收前端传递的用户性别、身高、年龄、当前体重、目标体重数据统一数据格式封装为符合华为云MaaS API要求的请求参数。 AI接口调用后端调用华为云MaaS大模型API将用户身体数据、健身目标作为提示词核心内容请求AI进行智能分析。 结果接收与解析后端接收华为云MaaS API返回的结构化文本数据完成数据解析、去冗余、格式优化剔除无效内容。 结果前端展示将处理后的AI私教建议返回前端以清晰的文本格式展示内容需涵盖训练计划、饮食建议、作息指导、注意事项、周期目标等详细内容。 2.3 加载与异常提示功能 加载状态用户点击获取建议按钮后页面展示加载状态提示「AI正在生成专属私教建议请稍候」避免用户重复点击操作。 3、接口需求 3.1 第三方接口华为云MaaS API 本系统核心依赖华为云MaaS大模型API实现智能建议生成接口需求如下 接口用途基于用户个人身体数据和体重目标智能分析并生成个性化健身私教全套建议。 请求方式遵循华为云MaaS API官方请求协议HTTPS。 请求参数包含用户性别、年龄、身高、当前体重、目标体重以及固定业务提示词引导大模型输出专业、详细、可落地的健身私教方案涵盖训练、饮食、禁忌等维度。 响应数据返回纯文本结构化内容内容需分层清晰包含适配用户情况的个性化建议无无关冗余信息。 超时要求接口请求超时时间不超过15秒超时则触发异常提示。 3.2 前后端交互接口 提供前端信息提交、AI建议获取接口支持POST请求接收用户录入的完整信息返回最终AI生成的私教建议内容及状态码。注意替换常量MODEL_NAME、API_URL、API_KEY。YOUR_API_URL替换成步骤“2.5 领取华为云MaaS平台大模型Tokens福利”中获取的API地址。YOUR_MODEL_NAME替换成步骤“2.5 领取华为云MaaS平台大模型Tokens福利”中获取的模型名称。YOUR_API_KEY替换成步骤“2.5 领取华为云MaaS平台大模型Tokens福利”中获取的API Key。经过几分钟后华为云码道帮助我们生成了基础版原始代码。由于模型本身的局限性生成的代码存在语法错误和逻辑错误代码优化时间过长为了减少无效的等待并增加案例的连贯性和趣味性因此本案例提供鸿蒙原生健身应用源码。下载解压完成后使用DevEco Studio打开项目源码3.2 项目介绍与项目结构项目介绍本项目集成AI能力用户输入个人信息(性别、身高、年龄、当前体重和目标体重等)点击获取私教建议按钮调用华为云MaaS API获取详细的私教建议。项目结构FitnessAssistant项目名称AppScope app.json5应用的全局配置信息。entryHarmonyOS工程模块编译构建生成一个HAP包。src main ets用于存放ArkTS源码。bean:大模型返回数据的封装类entryability应用/服务的入口。entrybackupability应用提供扩展的备份恢复能力。model模型返回数据解析并获取。pages:应用/服务包含的页面。utils工具类包含日志打印、网络请求、常量配置等工具类。view自定义组件。src main resources用于存放应用/服务所用到的资源文件如图形、多媒体、字符串、布局文件等。src main module.json5模块配置文件。build-profile.json5当前的模块信息 、编译信息配置项包括buildOption、targets配置等。hvigorfile.ts模块级编译构建任务脚本。obfuscation-rules.txt混淆规则文件。混淆开启后在使用Release模式进行编译时会对代码进行编译、混淆及压缩处理保护代码资产。oh-package.json5用来描述包名、版本、入口文件类型声明文件和依赖项等信息。oh_modules用于存放三方库依赖信息。build-profile.json5工程级配置信息包括签名signingConfigs、产品配置products等。其中products中可配置当前运行环境默认为HarmonyOS。hvigorfile.ts工程级编译构建任务脚本。oh-package.json5主要用来描述全局配置。3.3 核心代码解析应用主界面pages/MainPage.ets智能健身助手的主界面用户在此界面选择性别、身高、年龄、当前体重、目标体重等信息。点击“获取私教建议”按钮调用华为云MaaS API获取详细的私教建议。MainPage.ets完整代码如下复制代码import TextCommonComponent from ../view/TextCommonComponent; import { PersonInfo } from ../bean/PersonInfo; Entry Component struct Index { pageInfos: NavPathStack new NavPathStack(); State sex: string 男; State currentHeight: string 175cm; State currentAge: string 28岁; State targetWeight: string 75kg State currentWeight: string 65kg; State select: number 0; State customPopup: boolean false private sexArray: Resource $r(app.strarray.sex_array); build() { Column() { Navigation((this.pageInfos)) { Stack({ alignContent: Alignment.Top }) { Image($r(app.media.picture_bg)) .width(100%) .height(200) .objectFit(ImageFit.Fill) Text(智能健身助手) .fontSize(28) .fontWeight(FontWeight.Bold) .fontColor(Color.White) .margin({ top: 45 }) } .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP]) .width(100%) .height(200) Column() { TextCommonComponent({ textImage: $r(app.media.icon_sex), title: $r(app.string.sex), content: this.sex, onItemClick: () gt; { this.getUIContext().showTextPickerDialog({ range: this.sexArray, selected: this.select, canLoop: false, onAccept: (value: TextPickerResult) gt; { this.select value.index as number; this.sex value.value as string; }, onChange: (value: TextPickerResult) gt; { this.select value.index as number; } }) } }) } Column() { TextCommonComponent({ textImage: $r(app.media.icon_height), title: $r(app.string.current_height), content: this.currentHeight, onItemClick: () gt; { let heightArray: Array []; for (let i 150; i { this.select value.index as number; this.currentHeight value.value as string; }, onChange: (value: TextPickerResult) gt; { this.select value.index as number; } }) } }) } Column() { TextCommonComponent({ textImage: $r(app.media.icon_age), title: $r(app.string.current_age), content: this.currentAge, onItemClick: () gt; { let ageArray: Array []; for (let i 18; i { this.select value.index as number; this.currentAge value.value as string; }, onChange: (value: TextPickerResult) gt; { this.select value.index as number; } }) } }) } Column() { TextCommonComponent({ textImage: $r(app.media.icon_current), title: $r(app.string.current_weight), content: this.currentWeight, onItemClick: () gt; { let weightArray: Array []; for (let i 40; i { this.select value.index as number; this.currentWeight value.value as string; }, onChange: (value: TextPickerResult) gt; { this.select value.index as number; } }) } }) } Column() { TextCommonComponent({ textImage: $r(app.media.icon_target), title: $r(app.string.target_weight), content: this.targetWeight, onItemClick: () gt; { let weightArray: Array []; for (let i 40; i { this.select value.index as number; this.targetWeight value.value as string; }, onChange: (value: TextPickerResult) gt; { this.select value.index as number; } }) } }) } Button(获取私教建议) .width(95%) .height(45vp) .fontSize(18fp) .fontWeight(FontWeight.Medium) .backgroundColor(#007DFF) .margin({ top: 40vp, bottom: 12vp }) .onClick(() gt; { let personInfo: PersonInfo new PersonInfo(this.sex,this.currentHeight,this.currentAge,this.currentWeight, this.targetWeight); this.pageInfos.pushPathByName(detailPage, personInfo); }) } }.width(100%).height(100%) .backgroundColor(#F1F3F5) } }应用详情页pages/DetailPage.ets调用华为云MaaS API获取数据、解析数据并展示在该界面上。DetailPage.ets完整代码如下复制代码import Logger from ../utils/Logger; import { PersonInfo } from ../bean/PersonInfo; import { List } from kit.ArkTS; import UploadingLayout from ../view/UploadingLayout; import DetailViewModel from ../model/DetailViewModel; Builder export function DetailPageBuilder(name: string, param: Object) { DetailPage() } Component export struct DetailPage { pageInfos: NavPathStack new NavPathStack(); State content: string State prompt: string State isUploading: boolean false; formatString(str: string): string { // 使用正则表达式找到数字之间的横线并用特殊标记替换 let result: string str.replace(/(\d(\.\d)?)-(\d(\.\d)?)/g, $1__TEMP_DASH__$3); // 删除所有的 -、#、* let cleaned: string result.replace(/[-#*]/g, ); // 恢复数字范围中的横线 return cleaned.replace(/__TEMP_DASH__/g, -); } getParamsPrint() { this.isUploading true let jsonString JSON.stringify(this.pageInfos.getParamByName(detailPage)) let personInfoList: List JSON.parse(jsonString) as List; let personInfo: PersonInfo personInfoList[0] as PersonInfo; let age: string personInfo.currentAge; let sex: string personInfo.sex; let height: string personInfo.currentHeight; let currentWeight: string personInfo.currentWeight; let targetWeight: string personInfo.targetWeight; this.prompt 您好我是一名健身爱好者年龄:${age}、性别:${sex}、身高:${height}、当前体重:${currentWeight}、目标体重:${targetWeight}请给出健身建议; Logger.info(prompt: ${this.prompt}); DetailViewModel.requestModelData(this.prompt).then((content) gt; { Logger.info(content: ${content}); this.isUploading false this.content content }) } build() { Column() { NavDestination() { Stack() { Scroll() { Text(this.formatString(this.content)) .fontSize(18) .fontWeight(FontWeight.Medium) .width(100%) .padding({ top: 20, left: 10, right: 10, bottom: 20 }) .textAlign(TextAlign.Start) } .height(100%) if (this.isUploading) { UploadingLayout() } } } .onShown(() gt; { this.getParamsPrint(); }) .title(健身建议) .layoutWeight(HorizontalAlign.Center) .width(100%) .padding({ top: 40 }) .hideTitleBar(false) .onReady((context: NavDestinationContext) gt; { this.pageInfos context.pathStack; }) } } }模型数据获取HttpHelper.ets封装网络请求工具类HttpHelper用于获取模型返回的数据。HttpHelper.ets完整代码如下复制代码import { http } from kit.NetworkKit; import { ModelResultBean } from ../bean/ModelResultBean; import Logger from ./Logger; import { ModelConstants } from ./ModelConstants; class HttpHelper { async requestData(prompt: string): Promise { // 每一个httpRequest对应一个HTTP请求任务不可复用 let httpRequest http.createHttp(); // 用于订阅HTTP响应头此接口会比request请求先返回。可以根据业务需要订阅此消息 httpRequest.on(headersReceive, (header) gt; { console.info(header: JSON.stringify(header)); }); let options: http.HttpRequestOptions { method: http.RequestMethod.POST, // 开发者根据自身业务需要添加header字段 header: { Content-Type: application/json, // 把yourApiKey替换成真实的API Key Authorization: ${ModelConstants.API_KEY} }, // 当使用POST请求时此字段用于传递请求体内容具体格式与服务端协商确定 extraData: { model: ${ModelConstants.MODEL_NAME}, messages: [ { role: system, content: You are a helpful assistant. }, { role: user, content: prompt } ], stream: false, temperature: 0.6 }, // 可选指定返回数据的类型 expectDataType: http.HttpDataType.STRING, // 可选默认为true usingCache: true, // 可选默认为1 priority: 1, // 可选默认为60000ms connectTimeout: 180000, // 可选默认为60000ms readTimeout: 180000, // 可选协议类型默认值由系统自动指定 usingProtocol: http.HttpProtocol.HTTP1_1, } let messageResult: string try { let httpResponse await httpRequest.request(ModelConstants.API_URL, options) let responseCode httpResponse.responseCode let responseResult httpResponse.result as string Logger.info(responseResult: ${responseResult}); Logger.info(responseCode: ${responseCode}); if (responseCode 200) { let modelResultBean JSON.parse(responseResult) as ModelResultBean messageResult JSON.stringify(modelResultBean.choices) Logger.info(messageResult: ${messageResult}); } else { messageResult } } catch (err) { Logger.info(messageResult: ${JSON.stringify(err)}); messageResult } httpRequest.off(headersReceive); // 当该请求使用完毕时调用destroy方法主动销毁 httpRequest.destroy(); return messageResult } } export default new HttpHelper();注意调用MaaS API需要使用网络权限。entry src main module.json5文件中添加网络请求权限。复制代码requestPermissions: [ { name: ohos.permission.INTERNET } ],MaaS API常量ModelConstants.ets包含模型的API地址、模型名称和API Key。复制代码export class ModelConstants { static readonly API_URL: string YOUR_API_URL; static readonly MODEL_NAME: string YOUR_MODEL_NAME; static readonly API_KEY: string Bearer YOUR_API_KEY; }注意替换常量MODEL_NAME、API_URL、API_KEY。YOUR_API_URL替换成步骤“2.5 领取华为云MaaS平台大模型Tokens福利”中获取的API地址。YOUR_MODEL_NAME替换成步骤“2.5 领取华为云MaaS平台大模型Tokens福利”中获取的模型名称。YOUR_API_KEY替换成步骤“2.5 领取华为云MaaS平台大模型Tokens福利”中获取的API Key。3.4 运行体验鸿蒙原生健身应用打开DevEco Studio项目工程点击右上角运行按钮部署鸿蒙应用。选择性别选择身高选择年龄选择当前体重选择目标体重点击获取私教建议按钮调用MaaS API:获取了详细的健身建议至此码道托管 MaaS赋能鸿蒙原生健身应用实践的案例已全部完成。