【OpenHarmony】鸿蒙应用开发实战指南:构建网络数据列表应用
鸿蒙应用开发实战指南:构建网络数据列表应用
前言:本文从零开始,详细介绍如何使用HarmonyOS ArkTS语言开发一个具备网络请求和数据列表展示功能的应用。涵盖工程搭建、网络封装、UI开发、错误处理等核心知识点,适合鸿蒙开发入门者学习参考。
一、开发环境准备
1.1 必备软件清单
| 软件 | 版本要求 | 用途 | 下载地址 |
|---|---|---|---|
| Node.js | 16.x+ | JavaScript运行环境 | nodejs.org |
| DevEco Studio | 4.0+ | 鸿蒙官方IDE | developer.huawei.com |
| Git | 最新版 | 版本控制工具 | git-scm.com |
1.2 Git全局配置
# 配置用户信息git config --global user.name "YourName"git config --global user.email "[email protected]"# 配置默认分支名git config --global init.defaultBranch main # 配置凭证缓存(避免频繁输入密码)git config --global credential.helper store 1.3 代码仓库创建
在Gitee/AtomGit等平台创建新仓库:
仓库配置建议:
- 仓库名:
harmonyos-network-demo - 可见性:公开
- 许可证:MIT
- 初始化选项:添加README、.gitignore(选择OpenHarmony模板)
1.4 本地仓库初始化
# 克隆仓库git clone https://gitee.com/your-username/harmonyos-network-demo.git cd harmonyos-network-demo # 或本地初始化后关联远程git init gitadd.git commit -m"chore: 初始化鸿蒙网络请求示例项目"git branch -M main git remote add origin https://gitee.com/your-username/harmonyos-network-demo.git git push -u origin main 二、工程创建与目录结构
2.1 创建鸿蒙工程
- 打开DevEco Studio,点击「Create Project」
- 选择「Empty Ability」模板
- 配置工程信息:
- 工程名:
HarmonyoNetworkList - 包名:
com.example.networklist - 保存位置:选择刚才克隆的仓库目录
- SDK版本:API 10+
- 设备类型:Phone
- 工程名:
2.2 推荐目录结构
HarmonyoNetworkList/ ├── entry/ │ └── src/ │ └── main/ │ ├── ets/ # ArkTS源码目录 │ │ ├── entryability/ # Ability入口 │ │ ├── pages/ # 页面目录 │ │ ├── model/ # 数据模型 │ │ ├── utils/ # 工具类 │ │ └── common/ # 公共资源 │ │ ├── constants/ # 常量定义 │ │ └── styles/ # 样式配置 │ ├── resources/ # 资源文件 │ │ ├── base/ # 基础资源 │ │ │ ├── element/ # 元素资源 │ │ │ ├── media/ # 媒体资源 │ │ │ └── profile/ # 配置文件 │ │ └── rawfile/ # 原始文件 │ └── module.json5 # 模块配置 ├── oh-package.json5 # 依赖管理 ├── build-profile.json5 # 构建配置 └── app.json5 # 应用配置 三、核心配置文件详解
3.1 依赖管理(oh-package.json5)
{ "name": "entry", "version": "1.0.1", "description": "HarmonyOS网络请求与列表展示示例", "main": "", "author": "", "license": "MIT", "dependencies": {}, "devDependencies": { "@ohos/hypium": "1.0.16" } } 3.2 模块配置(module.json5)
{ "module": { "name": "entry", "type": "entry", "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": [ "default", "tablet" ], "deliveryWithInstall": true, "installationFree": false, "pages": "$profile:main_pages", "abilities": [ { "name": "EntryAbility", "srcEntry": "./ets/entryability/EntryAbility.ets", "description": "$string:EntryAbility_desc", "icon": "$media:app_icon", "label": "$string:EntryAbility_label", "startWindowIcon": "$media:icon", "startWindowBackground": "$color:start_window_background", "exported": true, "skills": [ { "entities": [ "entity.system.home" ], "actions": [ "action.system.home" ] } ] } ], "requestPermissions": [ { "name": "ohos.permission.INTERNET", "reason": "$string:internet_permission_reason", "usedScene": { "abilities": [ "EntryAbility" ], "when": "inuse" } } ] } } 3.3 页面路由配置(main_pages.json)
{ "src": [ "pages/TaskListPage" ] } 3.4 应用级配置(app.json5)
{ "app": { "bundleName": "com.example.networklist", "vendor": "example", "versionCode": 1000000, "versionName": "1.0.0", "icon": "$media:app_icon", "label": "$string:app_name", "description": "$string:app_description", "targetSDKVersion": 10, "apiReleaseType": "Release" } } 3.5 字符串资源配置
// resources/base/element/string.json { "string": [ { "name": "app_name", "value": "任务清单" }, { "name": "app_description", "value": "基于HarmonyOS的网络请求与列表展示示例" }, { "name": "module_desc", "value": "网络请求与数据列表示例模块" }, { "name": "EntryAbility_desc", "value": "任务清单应用入口" }, { "name": "EntryAbility_label", "value": "任务清单" }, { "name": "internet_permission_reason", "value": "需要网络权限以获取任务数据" }, { "name": "loading_text", "value": "加载中..." }, { "name": "error_text", "value": "加载失败,请重试" }, { "name": "retry_text", "value": "重试" }, { "name": "empty_text", "value": "暂无数据" } ] } 3.6 颜色资源配置
// resources/base/element/color.json { "color": [ { "name": "start_window_background", "value": "#FFFFFF" }, { "name": "primary_color", "value": "#0A59F7" }, { "name": "background_color", "value": "#F5F5F5" }, { "name": "card_background", "value": "#FFFFFF" }, { "name": "text_primary", "value": "#182431" }, { "name": "text_secondary", "value": "#99182431" }, { "name": "divider_color", "value": "#E5E5E5" }, { "name": "success_color", "value": "#00C853" }, { "name": "error_color", "value": "#FF5252" } ] } 四、数据模型定义
4.1 任务数据模型
// entry/src/main/ets/model/TaskModel.ets/** * 任务数据项模型 */exportinterfaceTaskItem{ id:number;// 任务ID title:string;// 任务标题 completed:boolean;// 完成状态 userId:number;// 用户ID}/** * 网络响应基类 */exportinterfaceApiResponse<T>{ data:T;// 响应数据 code:number;// 响应码 message:string;// 响应消息}/** * 列表响应数据 */exportinterfaceListResponse<T>{ items:T[];// 数据列表 total:number;// 总数量 page:number;// 当前页码 pageSize:number;// 每页大小}4.2 常量定义
// entry/src/main/ets/common/constants/ApiConstants.ets/** * API常量定义 */exportclassApiConstants{// 基础URLprivatestaticreadonlyBASE_URL='https://jsonplaceholder.typicode.com';// API端点staticreadonlyTASKS_ENDPOINT='/todos';staticreadonlyTASK_DETAIL_ENDPOINT=(id:number)=>`/todos/${id}`;staticreadonlyUSER_TASKS_ENDPOINT=(userId:number)=>`/todos?userId=${userId}`;// 完整URL构建staticgetFullUrl(endpoint:string):string{return`${this.BASE_URL}${endpoint}`;}// 超时时间(毫秒)staticreadonlyCONNECT_TIMEOUT=10000;staticreadonlyREAD_TIMEOUT=15000;}/** * 业务常量 */exportclassBusinessConstants{// 每页加载数量staticreadonlyPAGE_SIZE=20;// 状态码staticreadonlySUCCESS_CODE=200;staticreadonlyERROR_CODE=-1;// 缓存时间(秒)staticreadonlyCACHE_DURATION=300;}五、网络请求封装
5.1 HTTP请求工具类
// entry/src/main/ets/utils/HttpUtil.etsimport http from'@ohos.net.http';import{ BusinessConstants }from'../common/constants/ApiConstants';/** * HTTP请求配置 */interfaceRequestConfig{ method?: http.RequestMethod; header?: Record<string,string>; readTimeout?:number; connectTimeout?:number; extraData?:string| Object | ArrayBuffer;}/** * HTTP响应数据 */interfaceHttpResponse<T>{ data:T; statusCode:number; headers: Record<string,string>;}/** * HTTP请求工具类 */exportclassHttpUtil{/** * GET请求 * @param url 请求地址 * @param params 请求参数 * @param config 请求配置 */staticasyncget<T>( url:string, params?: Record<string,string>, config?: RequestConfig ):Promise<HttpResponse<T>>{// 构建带参数的URLlet fullUrl = url;if(params && Object.keys(params).length >0){const queryString = Object.keys(params).map(key =>`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&'); fullUrl =`${url}?${queryString}`;}returnthis.request<T>(fullUrl,{ method: http.RequestMethod.GET, readTimeout: BusinessConstants.CONNECT_TIMEOUT, connectTimeout: BusinessConstants.READ_TIMEOUT,...config });}/** * POST请求 * @param url 请求地址 * @param data 请求数据 * @param config 请求配置 */staticasyncpost<T>( url:string, data?: Object |string, config?: RequestConfig ):Promise<HttpResponse<T>>{returnthis.request<T>(url,{ method: http.RequestMethod.POST, extraData: data, readTimeout: BusinessConstants.READ_TIMEOUT, connectTimeout: BusinessConstants.CONNECT_TIMEOUT,...config });}/** * 通用请求方法 * @param url 请求地址 * @param config 请求配置 */privatestaticasyncrequest<T>( url:string, config: RequestConfig ={}):Promise<HttpResponse<T>>{// 创建HTTP请求对象const httpRequest = http.createHttp();try{// 设置默认请求头const defaultHeaders: Record<string,string>={'Content-Type':'application/json','Accept':'application/json'};// 合并请求头const headers ={...defaultHeaders,...config.header };// 发起请求const response =await httpRequest.request(url,{ method: config.method || http.RequestMethod.GET, header: headers, readTimeout: config.readTimeout ||15000, connectTimeout: config.connectTimeout ||10000, extraData: config.extraData });// 解析响应数据let responseData:T;const contentType = response.headers?.['Content-Type']||'';const responseType = response.responseType;switch(responseType){case http.HttpResponseType.STRING:if(contentType.includes('application/json')){ responseData =JSON.parse(response.result asstring)asT;}else{ responseData = response.result asT;}break;case http.HttpResponseType.ARRAY_BUFFER: responseData = response.result asT;break;default: responseData = response.result asT;}return{ data: responseData, statusCode: response.responseCode, headers: response.headers };}catch(error){thrownewError(`请求失败: ${error.message || error}`);}finally{// 销毁请求对象 httpRequest.destroy();}}}5.2 任务数据服务
// entry/src/main/ets/utils/TaskService.etsimport{ HttpUtil }from'./HttpUtil';import{ TaskItem }from'../model/TaskModel';import{ ApiConstants }from'../common/constants/ApiConstants';/** * 任务数据服务类 */exportclassTaskService{/** * 获取所有任务列表 */staticasyncgetAllTasks():Promise<TaskItem[]>{const url = ApiConstants.getFullUrl(ApiConstants.TASKS_ENDPOINT);const response =await HttpUtil.get<TaskItem[]>(url);return response.data;}/** * 获取单个任务详情 * @param taskId 任务ID */staticasyncgetTaskDetail(taskId:number):Promise<TaskItem>{const url = ApiConstants.getFullUrl(ApiConstants.TASK_DETAIL_ENDPOINT(taskId));const response =await HttpUtil.get<TaskItem>(url);return response.data;}/** * 获取指定用户的任务 * @param userId 用户ID */staticasyncgetUserTasks(userId:number):Promise<TaskItem[]>{const url = ApiConstants.getFullUrl(ApiConstants.USER_TASKS_ENDPOINT(userId));const response =await HttpUtil.get<TaskItem[]>(url);return response.data;}/** * 按完成状态筛选任务 * @param completed 是否完成 */staticasyncgetTasksByStatus(completed:boolean):Promise<TaskItem[]>{const url = ApiConstants.getFullUrl(ApiConstants.TASKS_ENDPOINT);const response =await HttpUtil.get<TaskItem[]>(url,{ completed:String(completed)});return response.data;}}六、UI组件开发
6.1 任务列表页面
// entry/src/main/ets/pages/TaskListPage.etsimport{ TaskItem }from'../model/TaskModel';import{ TaskService }from'../utils/TaskService';import promptAction from'@ohos.promptAction';/** * 任务状态枚举 */enum LoadState {IDLE='idle',LOADING='loading',SUCCESS='success',ERROR='error'}/** * 任务列表页面 */@Entry@Component struct TaskListPage {// 任务列表数据@Stateprivate taskList: TaskItem[]=[];// 加载状态@Stateprivate loadState: LoadState = LoadState.IDLE;// 错误信息@Stateprivate errorMessage:string='';// 是否正在下拉刷新@Stateprivate isRefreshing:boolean=false;/** * 页面即将出现时加载数据 */aboutToAppear():void{this.loadTaskData();}/** * 加载任务数据 */privateasyncloadTaskData():Promise<void>{this.loadState = LoadState.LOADING;this.errorMessage ='';try{const tasks =await TaskService.getAllTasks();this.taskList = tasks;this.loadState = LoadState.SUCCESS;}catch(error){this.errorMessage = error.message ||'加载失败,请重试';this.loadState = LoadState.ERROR;console.error(`[TaskListPage] 加载失败: ${this.errorMessage}`);}}/** * 下拉刷新 */privateasynconRefresh():Promise<void>{this.isRefreshing =true;awaitthis.loadTaskData();this.isRefreshing =false;}/** * 重试加载 */privateonRetry():void{this.loadTaskData();}/** * 任务项点击事件 */privateonTaskClick(task: TaskItem):void{ promptAction.showToast({ message:`任务: ${task.title}\n状态: ${task.completed ?'已完成':'进行中'}`, duration:2000});}/** * 切换任务完成状态 */privatetoggleTaskStatus(task: TaskItem):void{ task.completed =!task.completed;// 更新UIconst index =this.taskList.findIndex(item => item.id === task.id);if(index !==-1){this.taskList.splice(index,1,{...task });}}/** * 构建加载中UI */@BuilderprivateLoadingBuilder(){Column(){LoadingProgress().width(48).height(48).color($r('app.color.primary_color'))Text($r('app.string.loading_text')).fontSize(16).fontColor($r('app.color.text_secondary')).margin({ top:16})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}/** * 构建错误UI */@BuilderprivateErrorBuilder(){Column({ space:16}){Image($r('app.media.ic_error')).width(80).height(80).fillColor($r('app.color.error_color'))Text(this.errorMessage ||$r('app.string.error_text')).fontSize(16).fontColor($r('app.color.text_secondary')).textAlign(TextAlign.Center)Button($r('app.string.retry_text')).onClick(()=>this.onRetry()).type(ButtonType.Capsule).backgroundColor($r('app.color.primary_color'))}.width('100%').height('100%').justifyContent(FlexAlign.Center).padding(24)}/** * 构建空数据UI */@BuilderprivateEmptyBuilder(){Column({ space:16}){Image($r('app.media.ic_empty')).width(120).height(120).fillColor($r('app.color.text_secondary'))Text($r('app.string.empty_text')).fontSize(16).fontColor($r('app.color.text_secondary'))}.width('100%').height('100%').justifyContent(FlexAlign.Center)}/** * 构建任务项UI */@BuilderprivateTaskItemBuilder(task: TaskItem, index:number){Row(){// 状态图标Image(task.completed ?$r('app.media.ic_check_circle'):$r('app.media.ic_radio_unchecked')).width(24).height(24).fillColor(task.completed ?$r('app.color.success_color'):$r('app.color.text_secondary')).margin({ right:12})// 任务信息Column({ space:4}){Text(task.title).fontSize(16).fontColor($r('app.color.text_primary')).maxLines(2).textOverflow({ overflow: TextOverflow.Ellipsis }).decoration({ type: task.completed ? TextDecorationType.LineThrough : TextDecorationType.None })Text(`ID: ${task.id} | 用户: ${task.userId}`).fontSize(12).fontColor($r('app.color.text_secondary'))}.alignItems(HorizontalAlign.Start).layoutWeight(1)// 箭头图标Image($r('app.media.ic_arrow_right')).width(16).height(16).fillColor($r('app.color.text_secondary'))}.width('100%').padding(16).backgroundColor($r('app.color.card_background')).borderRadius(8).margin({ bottom:8}).onClick(()=>this.onTaskClick(task)).gesture(LongPressGesture({ repeat:false}).onAction(()=>{this.toggleTaskStatus(task);}))}/** * 构建页面UI */build(){Column(){// 标题栏Row(){Text('任务清单').fontSize(20).fontWeight(FontWeight.Bold).fontColor($r('app.color.text_primary'))}.width('100%').height(56).padding({ left:16, right:16}).backgroundColor($r('app.color.card_background'))// 内容区域if(this.loadState === LoadState.LOADING){this.LoadingBuilder()}elseif(this.loadState === LoadState.ERROR){this.ErrorBuilder()}elseif(this.taskList.length ===0){this.EmptyBuilder()}else{// 任务列表List({ space:0}){ForEach(this.taskList,(task: TaskItem, index:number)=>{ListItem(){this.TaskItemBuilder(task, index)}},(task: TaskItem)=> task.id.toString())}.width('100%').layoutWeight(1).padding({ left:16, right:16, top:8}).scrollBar(BarState.Auto).edgeEffect(EdgeEffect.Spring)}// 统计信息if(this.loadState === LoadState.SUCCESS&&this.taskList.length >0){Row(){Text(`共 ${this.taskList.length} 条任务`).fontSize(14).fontColor($r('app.color.text_secondary'))Blank()Text(`已完成: ${this.taskList.filter(t => t.completed).length}`).fontSize(14).fontColor($r('app.color.success_color'))}.width('100%').height(48).padding({ left:16, right:16}).backgroundColor($r('app.color.card_background'))}}.width('100%').height('100%').backgroundColor($r('app.color.background_color'))}}6.2 样式配置类
// entry/src/main/ets/common/styles/AppStyles.ets/** * 应用样式配置 */exportclassAppStyles{// 间距staticreadonlySPACING={XS:4,SM:8,MD:12,LG:16,XL:20,XXL:24};// 字体大小staticreadonlyFONT_SIZE={XS:12,SM:14,MD:16,LG:18,XL:20,XXL:24};// 圆角staticreadonlyRADIUS={SM:4,MD:8,LG:12,XL:16,CIRCLE:999};// 阴影staticreadonlySHADOW={SM:{ radius:4, color:'#1A000000', offsetX:0, offsetY:2},MD:{ radius:8, color:'#1A000000', offsetX:0, offsetY:4},LG:{ radius:16, color:'#1A000000', offsetX:0, offsetY:8}};}七、常见问题与解决方案
7.1 网络请求相关
问题1:网络请求失败提示权限不足
错误信息: Permission denial 解决方案:检查module.json5中是否正确配置网络权限
"requestPermissions": [ { "name": "ohos.permission.INTERNET", "reason": "$string:internet_permission_reason", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } } ] 问题2:HTTPS证书校验失败
解决方案:在开发阶段可临时忽略证书校验(生产环境不推荐)
httpRequest.request(url,{// 使用http协议仅用于开发测试// 生产环境必须使用https并正确配置证书})7.2 UI渲染相关
问题3:列表数据更新后UI不刷新
解决方案:确保使用@State装饰状态变量,更新时触发刷新
// 错误做法this.taskList[index].completed =true;// 正确做法this.taskList.splice(index,1,{...task, completed:true});问题4:ForEach渲染警告:需要唯一的key标识
解决方案:确保ForEach的第三个参数返回唯一标识
ForEach(this.taskList,(task: TaskItem)=>{ListItem(){...}},(task: TaskItem)=> task.id.toString())// 使用唯一ID作为key7.3 资源引用相关
问题5:资源引用报错"Resource is not defined"
解决方案:使用$r()语法引用资源
// 错误写法Text('加载中')// 正确写法Text($r('app.string.loading_text'))7.4 Git操作相关
问题6:推送时提示"remote rejected"
解决方案:
# 拉取远程最新代码git pull origin main --rebase# 解决冲突后推送git push origin main 问题7:提交时报错"nothing to commit"
解决方案:检查文件状态
# 查看文件状态git status # 添加文件gitadd.# 提交git commit -m"feat: 添加任务列表功能"八、测试与验证
8.1 模拟器运行
- 打开Device Manager
- 创建Phone模拟器(API 10+)
- 选择模拟器,点击运行按钮
8.2 功能验证清单
- 应用启动正常,显示任务列表页面
- 首次加载显示加载状态
- 网络请求成功,显示任务列表
- 点击任务项显示详情提示
- 长按任务项切换完成状态
- 下拉刷新功能正常
- 错误状态显示正确,重试功能可用
- 空数据状态显示正确
- 统计信息正确显示
8.3 日志记录
// 添加日志标签constTAG='[TaskListPage]';// 使用console记录日志console.log(`${TAG} 加载数据`);console.error(`${TAG} 加载失败: ${error.message}`);console.warn(`${TAG} 数据为空`);九、代码提交规范
9.1 提交信息格式
遵循 Conventional Commits 规范:
<type>(<scope>): <subject> <body> <footer> 9.2 常用提交类型
| 类型 | 说明 | 示例 |
|---|---|---|
| feat | 新功能 | feat(task): 添加任务列表功能 |
| fix | 问题修复 | fix(network): 修复网络请求超时问题 |
| docs | 文档更新 | docs(readme): 更新项目说明文档 |
| style | 代码格式 | style(ui): 统一代码缩进格式 |
| refactor | 重构 | refactor(service): 重构网络请求层 |
| test | 测试 | test(api): 添加单元测试用例 |
| chore | 构建/工具 | chore(deps): 更新依赖版本 |
9.3 提交示例
# 功能开发提交gitadd.git commit -m"feat(task): 实现任务列表数据加载与展示 - 添加网络请求封装类HttpUtil - 添加任务数据服务TaskService - 实现任务列表页面UI - 支持下拉刷新和状态切换"# 问题修复提交gitadd.git commit -m"fix(ui): 修复列表项点击事件无响应问题"# 文档更新提交gitadd README.md git commit -m"docs(readme): 更新项目运行环境说明"十、进阶优化方向
10.1 数据持久化
// 使用Preferences存储本地数据import dataPreferences from'@ohos.data.preferences';exportclassLocalStorage{privatestatic preferences: dataPreferences.Preferences |null=null;staticasyncinit(context: Context):Promise<void>{this.preferences =await dataPreferences.getPreferences(context,'task_store');}staticasyncsaveTasks(tasks: TaskItem[]):Promise<void>{awaitthis.preferences?.put('tasks',JSON.stringify(tasks));awaitthis.preferences?.flush();}staticasyncgetTasks():Promise<TaskItem[]>{const data =awaitthis.preferences?.get('tasks','[]');returnJSON.parse(data asstring);}}10.2 状态管理
// 使用简单的状态管理exportclassStore<T>{private state:T;private listeners:Array<(state:T)=>void>=[];constructor(initialState:T){this.state = initialState;}getState():T{returnthis.state;}setState(newState: Partial<T>):void{this.state ={...this.state,...newState };this.notify();}subscribe(listener:(state:T)=>void):()=>void{this.listeners.push(listener);return()=>{const index =this.listeners.indexOf(listener);this.listeners.splice(index,1);};}privatenotify():void{this.listeners.forEach(listener =>listener(this.state));}}10.3 图片缓存
// 简单的图片缓存管理exportclassImageCache{privatestatic cache: Map<string, PixelMap>=newMap();staticasyncget(url:string):Promise<PixelMap |null>{if(this.cache.has(url)){returnthis.cache.get(url)!;}const imageSource = image.createImageSource(url);const pixelMap =await imageSource.createPixelMap();this.cache.set(url, pixelMap);return pixelMap;}staticclear():void{this.cache.clear();}}十一、总结
本文通过一个完整的网络请求与数据列表示例,介绍了HarmonyOS应用开发的核心流程:
11.1 核心知识点回顾
- 工程结构:合理的目录结构提升代码可维护性
- 配置文件:module.json5、oh-package.json5等核心配置
- 网络请求:基于@ohos.net.http的封装与使用
- UI组件:List、ForEach等组件实现列表展示
- 状态管理:@State装饰器的响应式更新机制
- 资源管理:字符串、颜色等资源的统一管理
11.2 关键收获
- 掌握鸿蒙应用的基本开发流程
- 了解网络请求的标准封装方式
- 熟悉列表组件的最佳实践
- 学会常见问题的排查与解决
11.3 下一步学习建议
- 深入学习ArkTS语法和特性
- 掌握更多UI组件的使用方法
- 学习应用数据持久化方案
- 了解分布式开发相关特性
- 探索性能优化技巧
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.ZEEKLOG.net
参考资源:HarmonyOS官方文档OpenHarmony文档JSONPlaceholder测试接口