鸿蒙原生应用实战(五):路由导航与工程优化 — 从开发到上线的完整流程
鸿蒙原生应用实战五路由导航与工程优化 — 从开发到上线的完整流程一、前言经过前四篇的开发我们的游戏收藏夹 App 已经拥有 5 个页面、1800 行 ArkTS 代码。本篇将从架构高度重新审视整个项目涵盖路由系统深度解析与导航架构设计module.json5 配置详解构建配置与性能优化单元测试与 UI 测试实践ArkTS 严格模式最佳实践DevEco Studio 调试技巧二、路由系统深度解析2.1 路由架构概览Index (首页) / | \ ▼ ▼ ▼ GameListPage WishPage StatsPage | ▼ GameDetailPage整个 App 的路由关系是星型拓扑首页作为 Hub可以跳转到任意子页面详情页作为最深层级页面。2.2 路由配置在main_pages.json中注册所有页面路由{src:[pages/Index,pages/GameListPage,pages/GameDetailPage,pages/WishPage,pages/StatsPage]}在module.json5中引用{module:{pages:$profile:main_pages,abilities:[{name:EntryAbility,srcEntry:./ets/entryability/EntryAbility.ets,launchType:standard}]}}2.3 路由 API 全面解析2.3.1 路由导入// API 23 下的正确导入方式importrouterfromohos.router;注意API 23 版本下router从ohos.router导入而不是kit.AbilityKit。这个版本kit.AbilityKit不导出 router API如果用错会导致编译错误。2.3.2 页面跳转// 不带参数的跳转router.pushUrl({url:pages/GameListPage});// 带参数的跳转router.pushUrl({url:pages/GameDetailPage,params:{gameId:1}});2.3.3 接收参数// 参数接收的标准写法constparamsrouter.getParams()asRecordstring,Object;if(paramsparams[filter]!undefined){this.filterparams[filter]asstring;}2.3.4 返回上一页router.back();2.4 项目中的路由调用汇总源页面目标页面携带参数触发方式IndexGameListPage{ filter: string }快速筛选标签点击IndexGameListPage无底部导航游戏库IndexWishPage无愿望单统计卡片 / 底部导航IndexStatsPage无底部导航统计GameListPageGameDetailPage{ gameId: number }游戏卡片点击WishPageGameDetailPage{ gameId: number }愿望单卡片点击任意详情页——返回按钮 →router.back()2.5 导航架构设计模式2.5.1 显式导航 vs 隐式导航鸿蒙的router.pushUrl属于显式导航直接指定目标页面 URL 和参数。优点是类型安全编译时校验页面路径参数明确通过params对象传递调用链路清晰2.5.2 导航栈管理router.pushUrl默认使用标准模式每次跳转都入栈初始: [Index] 跳转: [Index, GameListPage] 再跳转: [Index, GameListPage, GameDetailPage] 返回: [Index, GameListPage]这种栈式管理保证了router.back()总能正确返回上一页支持系统返回按键避免页面层级过深最多 3 层三、module.json5 深度配置3.1 完整配置解读{ module: { name: entry, type: entry, // module 类型entry/feature/har description: $string:module_desc, mainElement: EntryAbility, // 主 Ability 入口 deviceTypes: [phone], deliveryWithInstall: true, // 随安装包交付 installationFree: false, // 是否免安装 pages: $profile:main_pages, // 引用页面路由配置 abilities: [ { name: EntryAbility, srcEntry: ./ets/entryability/EntryAbility.ets, description: $string:EntryAbility_desc, icon: $media:layered_image, label: $string:EntryAbility_label, startWindowIcon: $media:startIcon, startWindowBackground: $color:start_window_background, exported: true, // 允许外部启动 skills: [ // 隐式意图过滤 { entities: [entity.system.home], actions: [ohos.want.action.home] } ] } ], extensionAbilities: [ { name: EntryBackupAbility, srcEntry: ./ets/entrybackupability/EntryBackupAbility.ets, type: backup, exported: false, metadata: [ { name: ohos.extension.backup, resource: $profile:backup_config } ] } ] } }3.2 关键字段解析字段值作用typeentry应用主入口模块mainElementEntryAbility指定入口 AbilitydeliveryWithInstalltrue随安装包一体交付deviceTypes[“phone”]仅支持手机skillshome intent让 App 出现在桌面3.3 $ 资源引用鸿蒙使用$前缀引用资源文件$string:module_desc → string.json 中的 module_desc $media:layered_image → media 目录下的图片资源 $color:start_window_background → color.json 中的色值 $profile:main_pages → profile 目录下的 main_pages.json资源文件目录结构resources/ ├── base/ │ ├── element/ │ │ ├── string.json // 字符串 │ │ ├── color.json // 颜色 │ │ └── float.json // 字号/尺寸 │ ├── media/ // 图片资源 │ └── profile/ // 配置文件 └── dark/ └── element/ └── color.json // 暗色模式颜色覆盖四、构建配置优化4.1 项目级 build-profile.json5{ app: { products: [ { name: default, signingConfig: default, targetSdkVersion: 6.1.1(24), compatibleSdkVersion: 6.1.0(23), runtimeOS: HarmonyOS, buildOption: { strictMode: { caseSensitiveCheck: true, // 大小写敏感检查 useNormalizedOHMUrl: true // 使用规范 OHM 包 URL } } } ], buildModeSet: [ { name: debug }, { name: release } ] } }strictMode 详解caseSensitiveCheck: true— 对 HarmonyOS 文件系统区分大小写的设备如某些模拟器确保 import 路径大小写一致。如果导入from ./pages/Index但实际文件是index.ets会报错。4.2 模块级 build-profile.json5{ apiType: stageMode, buildOption: { resOptions: { copyCodeResource: { enable: false } } }, buildOptionSet: [ { name: release, arkOptions: { obfuscation: { // 代码混淆 ruleOptions: { enable: false, files: [./obfuscation-rules.txt] } } } } ], targets: [ { name: default }, { name: ohosTest } ] }4.3 构建命令hvigorw--modemodule\-pmoduleentrydefault\-pproductdefault\-prequiredDeviceTypephone\assembleHap\--analyzenormal\--parallel\--incremental\--daemon参数含义参数说明--mode module模块级构建-p moduleentrydefault构建 entry 模块的 default 目标assembleHap生成 HAP 安装包--parallel启用并行构建--incremental增量编译仅编译变更文件--daemon保持守护进程加速后续构建五、测试实践5.1 测试目录结构entry/src/ ├── main/ # 源代码 └── test/ # 本地单元测试 ├── List.test.ets └── LocalUnit.test.ets entry/src/ohosTest/ # 设备/UI 测试 └── ets/ └── test/ ├── Ability.test.ets └── List.test.ets5.2 本地单元测试// LocalUnit.test.etsimport{describe,it,expect}fromohos/hypium;import{UIAbility}fromkit.AbilityKit;describe(GameDataTest,(){it(test_filter_status,0,(){// 测试筛选逻辑的正确性constgames[{id:1,title:Game A,status:通关},{id:2,title:Game B,status:在玩}];constfilteredgames.filter(gg.status通关);expect(filtered.length).assertEqual(1);expect(filtered[0].title).assertEqual(Game A);});it(test_calc_stats,0,(){// 测试统计数据计算constgames[{id:1,hours:100,status:通关},{id:2,hours:50,status:在玩}];consttotalHoursgames.reduce((sum,g)sumg.hours,0);expect(totalHours).assertEqual(150);});});5.3 UI 测试// Ability.test.etsimport{describe,it,expect}fromohos/hypium;import{Driver,ON}fromohos.UiTest;describe(GameAppUITest,(){it(test_navigate_to_detail,0,async(){// 点击游戏卡片跳转到详情页constdriverawaitDriver.create();awaitdriver.delay(1000);// 点击最近游玩区域的第一个游戏卡片constgameCardawaitdriver.findComponent(ON.text(艾尔登法环));awaitgameCard.click();awaitdriver.delay(500);// 验证是否跳转检测详情页标题是否存在constdetailTitleawaitdriver.findComponent(ON.text(我的状态));expect(detailTitle!null).assertTrue();});});5.4 测试框架Hypium Hamock项目使用ohos/hypium单元测试框架和ohos/hamockMock 框架oh_modules/ohos/ ├── hypium/ # Hypium 测试框架 │ ├── index.ets │ └── src/main/ └── hamock/ # Hamock Mock 框架 └── index.etsoh-package.json5中的依赖声明{ dependencies: { ohos/hypium: 1.0.25, ohos/hamock: 1.0.0 } }六、ArkTS 严格模式最佳实践6.1 常见规则与解法规则错误示例正确写法arkts-no-untyped-obj-literals{ label: PC, count: 7 }先定义接口再赋值类型变量arkts-no-noninferrable-arr-literalsconst arr [1, 2, 3]const arr: number[] [1, 2, 3]arkts-no-for-offor (const g of games)for (let i: number 0; ...)arkts-strict-param-types.filter(g g.status).filter((g: Game) g.status)6.2 对象字面量模式// ❌ 错误直接使用对象字面量Column(){Text(通关).backgroundColor(this.filter通关?#FF6B35:#F0F0F0)}// ✅ 正确将数组对象提取为独立类型变量interfaceFilterItem{label:string;key:string;}constfilterItems:FilterItem[][{label:全部,key:all},{label:在玩,key:playing}];ForEach(filterItems,(item:FilterItem){Text(item.label)},(item:FilterItem)item.key)6.3 数组字面量模式// ❌ 错误conststatuses[通关,在玩,想玩];// ✅ 正确conststatuses:string[][通关,在玩,想玩];// ✅ 或者用类数组接口conststatuses:Arraystring[通关,在玩,想玩];6.4 ForEach key 生成规则// ✅ 筛选场景使用复合 key确保重建ForEach(this.getFilteredGames(),(game:GameItem){this.buildGameCard(game)},(game:GameItem)game.id.toString()this.filter)// ✅ 静态列表使用唯一 idForEach(this.filters,(f:string){Text(f)},(f:string)f)七、DevEco Studio 调试技巧7.1 hilog 日志输出import{hilog}fromkit.PerformanceAnalysisKit;constDOMAIN0x0000;// 调试日志hilog.debug(DOMAIN,GameApp,Loading game id: %{public}d,gameId);// 信息日志hilog.info(DOMAIN,GameApp,Page loaded successfully);// 错误日志hilog.error(DOMAIN,GameApp,Failed to load game: %{public}s,errMsg);7.2 性能优化建议惰性加载避免在aboutToAppear中执行繁重计算ForEach key 优化静态列表用稳定 key动态列表用复合 keyBuilder 粒度控制每个Builder控制在 30-50 行内减少嵌套层级避免Stack Column Row ...过深嵌套7.3 常见错误处理// 路由参数缺失的兜底aboutToAppear():void{constparamsrouter.getParams()asRecordstring,Object;if(paramsparams[gameId]!undefined){this.gameIdparams[gameId]asnumber;}this.loadGame();}// 数据加载失败的回退if(!this.game){this.gameallGames[0];// 默认显示第一个}八、项目总结8.1 项目规模维度数据页面数5 个总代码行~1800 行 ArkTS数据模型Game, GameItem, GameDetail, WishItem, GameStat, GenrePie组件复用15 个 Builder 组件路由跳转7 条路由路径8.2 技术亮点纯 ArkTS 图表不使用第三方库用 Stack Column 实现条形图、柱状图色彩识别系统每个游戏分配主题色替代封面图减少资源占用条件渲染善用if判断和三元运算符实现动态 UI响应式状态State 结合 ForEach数据变化自动驱动 UI 更新8.3 可扩展性方向当前实现 → 未来扩展 ─────────────────────────────────────────── 静态 mock 数据 → 接入网络 API 本地 state → AppStorage/LocalStorage router 导航 → Navigation 组件 纯色封面 → 网络图片加载 无状态持久化 → Preferences/RelationalStore 单 entry 模块 → multi-har/library 模块九、结语五篇博文从项目搭建、列表开发、详情交互、数据统计到工程优化我们完整走完了一个鸿蒙原生应用的开发全流程。核心收获️ Stage 模型 ArkTS 的项目结构 声明式 UI 的BuilderState组合 路由传参与页面间通信 纯 UI 组件实现数据可视化⚡ 严格模式下的类型安全编程鸿蒙生态正在快速发展掌握 ArkTS 和 Stage 模型是当前鸿蒙开发的关键技能。希望这五篇实战文章能够帮助更多开发者顺利上手鸿蒙原生应用开发系列目录全五篇第一篇项目搭建与首页开发第二篇游戏库列表与筛选排序第三篇游戏详情页与交互功能第四篇愿望单与个人统计第五篇路由导航与工程优化本文项目信息基于 HarmonyOS API 23 (compatibleSdkVersion 23, targetSdkVersion 24) Stage 模型 ArkTS使用 DevEco Studio 开发。所有代码均已通过 ArkTS 严格模式编译。