码道托管 + 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.1 | 0.00 |
| DevEco Studio | 6.0.0 Release | 免费 |
| 模拟器(Emulator) | HarmonyOS 6.0.0 | 免费 |
二、基础环境与资源准备
2.1 下载安装DevEco Studio
2.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:应用的全局配置信息。
- entry:HarmonyOS工程模块,编译构建生成一个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: () => {
this.getUIContext().showTextPickerDialog({
range: this.sexArray,
selected: this.select,
canLoop: false,
onAccept: (value: TextPickerResult) => {
this.select = value.index as number;
this.sex = value.value as string;
},
onChange: (value: TextPickerResult) => {
this.select = value.index as number;
}
})
}
})
}
Column() {
TextCommonComponent({
textImage: $r('app.media.icon_height'),
title: $r('app.string.current_height'),
content: this.currentHeight,
onItemClick: () => {
let heightArray: Array = [];
for (let i = 150; i {
this.select = value.index as number;
this.currentHeight = value.value as string;
},
onChange: (value: TextPickerResult) => {
this.select = value.index as number;
}
})
}
})
}
Column() {
TextCommonComponent({
textImage: $r('app.media.icon_age'),
title: $r('app.string.current_age'),
content: this.currentAge,
onItemClick: () => {
let ageArray: Array = [];
for (let i = 18; i {
this.select = value.index as number;
this.currentAge = value.value as string;
},
onChange: (value: TextPickerResult) => {
this.select = value.index as number;
}
})
}
})
}
Column() {
TextCommonComponent({
textImage: $r('app.media.icon_current'),
title: $r('app.string.current_weight'),
content: this.currentWeight,
onItemClick: () => {
let weightArray: Array = [];
for (let i = 40; i {
this.select = value.index as number;
this.currentWeight = value.value as string;
},
onChange: (value: TextPickerResult) => {
this.select = value.index as number;
}
})
}
})
}
Column() {
TextCommonComponent({
textImage: $r('app.media.icon_target'),
title: $r('app.string.target_weight'),
content: this.targetWeight,
onItemClick: () => {
let weightArray: Array = [];
for (let i = 40; i {
this.select = value.index as number;
this.targetWeight = value.value as string;
},
onChange: (value: TextPickerResult) => {
this.select = value.index as number;
}
})
}
})
}
Button('获取私教建议')
.width('95%')
.height('45vp')
.fontSize('18fp')
.fontWeight(FontWeight.Medium)
.backgroundColor('#007DFF')
.margin({ top: '40vp', bottom: '12vp' })
.onClick(() => {
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) => {
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(() => {
this.getParamsPrint();
})
.title("健身建议")
.layoutWeight(HorizontalAlign.Center)
.width("100%")
.padding({ top: 40 })
.hideTitleBar(false)
.onReady((context: NavDestinationContext) => {
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) => {
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赋能:鸿蒙原生健身应用实践的案例已全部完成。
四、反馈改进建议
如您在案例实操过程中遇到问题或有改进建议,可以到论坛帖评论区反馈即可,我们会及时响应处理,谢谢!
更多推荐




所有评论(0)