当前位置: 首页 > news >正文

关于鸿蒙配置HMRouter的问题,比如白屏等

参考1:https://gitee.com/hadss/hmrouter/blob/master/HMRouterLibrary/README.md

参考2:https://ohpm.openharmony.cn/#/cn/detail/@hadss%2Fhmrouter

配置流程:

一、下载安装

使用ohpm安装依赖

ohpm install @hadss/hmrouter

注意:这里你安装的版本号,和后面在hvigor/hvigor-config.json中配置的版本号一定要一致,否则盲目的根据官方会出现白屏,因为版本不一致

二、使用配置

编译插件配置

1.修改工程的hvigor/hvigor-config.json文件,加入路由编译插件

{"dependencies": {"@hadss/hmrouter-plugin": "^1.2.0-rc.0"// 使用npm仓版本号},// ...其他配置
}

2.在使用到HMRouter的模块中引入路由编译插件,修改hvigorfile.ts

示例:

// ./hvigorfile.ts  工程根目录的hvigorfile.ts
import { appTasks } from '@ohos/hvigor-ohos-plugin';export default {system: appTasks,plugins:[]
}// entry/hvigorfile.ts  entry模块的hvigorfile.ts
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { hapPlugin } from '@hadss/hmrouter-plugin';export default {system: hapTasks,plugins: [hapPlugin()] // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
}// libHar/hvigorfile.ts  libHar模块的hvigorfile.ts
import { harTasks } from '@ohos/hvigor-ohos-plugin';
import { harPlugin } from '@hadss/hmrouter-plugin';export default {system: harTasks,plugins:[harPlugin()]  // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
}// libHsp/hvigorfile.ts  libHsp模块的hvigorfile.ts
import { hspTasks } from '@ohos/hvigor-ohos-plugin';
import { hspPlugin } from '@hadss/hmrouter-plugin';export default {system: hspTasks,plugins: [hspPlugin()]  // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
}

如果模块是Har则使用harPlugin(), 模块是Hsp则使用hspPlugin(), 模块是Hap则使用hapPlugin()

3.在项目根目录创建路由编译插件配置文件hmrouter_config.json(可选)

{// 如果不配置则扫描src/main/ets目录,对代码进行全量扫描,如果配置则数组不能为空,建议配置指定目录可缩短编译耗时"scanDir": ["src/main/ets/components","src/main/ets/interceptors"],// 默认为false,调试排除错误时可以改成true,不删除编译产物"saveGeneratedFile": false,// 默认为false,不自动配置混淆规则,只会生成hmrouter_obfuscation_rules.txt文件帮助开发者配置混淆文件;如果设置为true,会自动配置混淆规则,并删除hmrouter_obfuscation_rules.txt文件"autoObfuscation": false,// 默认模板文件,不配置时使用插件内置模板"defaultPageTemplate": "./templates/defaultTemplate.ejs",// 特殊页面模版文件,匹配原则支持文件通配符"customPageTemplate": [{"srcPath": ["**/component/Home/**/*.ets"],"templatePath": "templates/home_shopping_template.ejs"},{"srcPath": ["**/live/**/*.ets"],"templatePath": "templates/live_template.ejs"}]
}

配置文件读取规则为 模块 > 工程 > 默认

优先使用本模块内的配置,如果没有配置,则使用工程目录中的配置,若找不到则使用默认配置

工程配置

由于拦截器、生命周期和自定义转场动画会在运行时动态创建实例,因此需要进行如下配置,使得HMRouter路由框架可以动态导入项目中的模块

1.在工程目录下的build-profile.json5中,配置useNormalizedOHMUrl属性为true

{"app": {"products": [{"name": "default","signingConfig": "default","compatibleSdkVersion": "5.0.0(12)","runtimeOS": "HarmonyOS","buildOption": {"strictMode": {"useNormalizedOHMUrl": true}}}],// ...其他配置}
}

2.在oh-package.json5中配置对Har和Hsp的依赖,这里需要注意依赖的模块名称需要与module.json5中moduleName、oh-package.json5中name保持一致

详见官网文档:动态import实现方案介绍 中的备注部分

{"dependencies": {"AppHar": "file:../AppHar",// AppHar库可以正确动态创建拦截器、生命周期和自定义转场动画对象"@app/har": "file:../AppHar"// 错误使用方式,无法动态创建对象}
}

快速开始

在UIAbility或者启动框架AppStartup中初始化路由框架

export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {HMRouterMgr.init({context: this.context})}
}

使用启动框架请查看:如何在启动框架中初始化HMRouter

定义路由入口

HMRouter依赖系统Navigation能力,所以必须在页面中定义一个HMNavigation容器,并设置相关参数,具体代码如下:

@Entry
@Component
export struct Index {modifier: NavModifier = new MyNavModifier();build() {// @Entry中需要再套一层容器组件,Column或者StackColumn(){// 使用HMNavigation容器HMNavigation({navigationId: 'mainNavigation', homePageUrl: 'MainPage',options: {standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,modifier: this.modifier}})}.height('100%').width('100%')}
}class MyNavModifier extends AttributeUpdater<NavigationAttribute> {initializeModifier(instance: NavigationAttribute): void {instance.hideNavBar(true);}
}

Navigation的系统属性通过modifier传递,部分modifier不支持的属性使用options设置

定义拦截器

使用@HMInterceptor标签定义拦截器,并实现IHMInterceptor接口

@HMInterceptor({ interceptorName: 'JumpInfoInterceptor', global: true })
export class JumpInfoInterceptor implements IHMInterceptor {handle(info: HMInterceptorInfo): HMInterceptorAction {let connectionInfo: string = info.type === 'push' ? 'jump to' : 'back to';Logger.info(`${info.srcName} ${connectionInfo} ${info.targetName}`)return HMInterceptorAction.DO_NEXT;}
}

定义生命周期

使用@HMLifecycle标签定义生命周期处理器,并实现IHMLifecycle接口

@HMLifecycle({ lifecycleName: 'PageDurationLifecycle' })
export class PageDurationLifecycle implements IHMLifecycle {private time: number = 0;onShown(ctx: HMLifecycleContext): void {this.time = new Date().getTime();}onHidden(ctx: HMLifecycleContext): void {const duration = new Date().getTime() - this.time;Logger.info(`Page ${ctx.navContext?.pathInfo.name} stay ${duration}`);}
}

自定义转场动画

通过@HMAnimator标签定义转场动画,并实现IHMAnimator接口

@HMAnimator({ animatorName: 'liveCommentsAnimator' })
export class liveCommentsAnimator implements IHMAnimator {effect(enterHandle: HMAnimatorHandle, exitHandle: HMAnimatorHandle): void {// 入场动画enterHandle.start((translateOption: TranslateOption, scaleOption: ScaleOption,opacityOption: OpacityOption) => {translateOption.y = '100%'})enterHandle.finish((translateOption: TranslateOption, scaleOption: ScaleOption,opacityOption: OpacityOption) => {translateOption.y = '0'})enterHandle.duration = 500// 出场动画exitHandle.start((translateOption: TranslateOption, scaleOption: ScaleOption,opacityOption: OpacityOption) => {translateOption.y = '0'})exitHandle.finish((translateOption: TranslateOption, scaleOption: ScaleOption,opacityOption: OpacityOption) => {translateOption.y = '100%'})exitHandle.duration = 500}
}

自定义转场动画的详细使用:查看详情

路由跳转使用

使用@HMRouter标签定义页面,绑定拦截器、生命周期及自定义转场动画

@HMRouter({ pageUrl: '/pageB', lifecycle: 'pageLifecycle', animator: 'pageAnimator' })
@Component
export struct PageB {// 获取生命周期中定义的状态变量@State model: ObservedModel | null = (HMRouterMgr.getCurrentLifecycleOwner().getLifecycle() as PageLifecycle).model@State param: HMPageParam = HMRouterMgr.getCurrentParam(HMParamType.all)build() {Column() {Text(`${this.model?.property}`)Text(`${this.param.paramsMap?.get('msg')}`)}}
}

定义页面PageA,使用HMRouterMgr.push执行路由跳转至PageB

const PAGE_URL: string = '/pageA'@HMRouter({ pageUrl: PAGE_URL })
@Component
export struct PageA {build() {Column() {Button('Push').onClick(() => {HMRouterMgr.push({ pageUrl: 'pageB?msg=abcdef' })})}
}
}

路由跳转支持URL带参数的方式,例如定义的页面pageUrl: /pages1/users,跳转时可以指定pageUrl为: /pages1/users?msg=1234

通过HMRouterMgr.getCurrentParam传入HMParamType.all获取URL的参数内容

服务路由使用

服务路由用于类似服务提供发现机制(Service Provider Interface),通过不依赖实现模块的方式获取接口实例并调用方法,当前仅提供方法级的调用

export class CustomService {@HMService({ serviceName: 'testConsole' })testConsole(): void {Logger.info('调用服务 testConsole')}@HMService({ serviceName: 'testFunWithReturn' })testFunWithReturn(param1: string, param2: string): string {return `调用服务 testFunWithReturn:${param1} ${param2}`}@HMService({ serviceName: 'testAsyncFun', singleton: true })async asyncFunction(): Promise<string> {return new Promise((resolve) => {resolve('调用异步服务 testAsyncFun')})}
}@HMRouter({ pageUrl: 'test://MainPage' })
@Component
export struct Index {build() {Row() {Column({ space: 8 }) {Button('service').onClick(() => {HMRouterMgr.request('testConsole')Logger.info(HMRouterMgr.request('testFunWithReturn', 'home', 'service').data)HMRouterMgr.request('testAsyncFun').data.then((res: string) => Logger.info(res))})}.width('100%')}.height('100%')
}
}

当前不支持同时和其他注解混用,也不支持静态方法

// 不支持类与类方法同时添加 @HM* 装饰器
@HMLifecycle({ serviceName: 'lifecycleName' })
export class CustomServiceErr1 {@HMService({ serviceName: 'testConsole' }) // 类已经添加 @HMLifecycle 装饰器,@HMService 无法识别testConsole(): void {Logger.info('调用服务 testConsole')}
}// 不支持在静态方法上添加 @HMService 装饰器
export class CustomServiceErr2 {@HMService({ serviceName: 'testConsole' }) // 静态方法添加 @HMService 装饰器,调用时会报错static testConsole(): void {Logger.info('调用服务 testConsole')}
}

混淆配置说明

@hadss/hmrouter-plugin(1.0.0-rc.6)版本之后HMRouter支持混淆自动配置白名单

开发者在build-profile.json5中配置混淆选项enable为true(开启混淆),如下所示,并且在当前模块hmrouter_config.json 中配置autoObfuscation为true(默认为false)。

HMRouter会自动生成HMRouter必须的白名单配置。将其保存在当前模块hmrouter_obfuscation_rules.txt 文件中,并在编译阶段将该文件自动加入到混淆配置文件files列表中,实现混淆自动配置效果。

// build-profile.json5
{"buildOptionSet": [{"name": "release","arkOptions": {"obfuscation": {"ruleOptions": {"enable": true,"files": ["./obfuscation-rules.txt"]}}}},],
}
// hmrouter_config.json
{"saveGeneratedFile": true,"autoObfuscation": true
}

如果将autoObfuscation改为false,则只会生成混淆规则文件,但不会自动修改模块的混淆配置。

开发者需要自行将生成的混淆文件hmrouter_obfuscation_rules.txt文件加入到混淆配置文件files列表中。

HMRouter手动配置混淆请参考HMRouter混淆配置

HMRouter标签的使用规则

标签中的字符串属性支持使用常量,详见FAQ

路由标签@HMRouter

@HMRouter(pageUrl, isRegex, regexPriority, dialog, singleton, interceptors, lifecycle, animator) 标签使用在自定义组件struct上,且该自定义组件需要添加export关键字

  • pageUrl: string, 用来表示NavDestination,必填

    1.支持使用本文件或者本模块定义的常量,或者Class中定义的静态变量

    2.pageUrl配置支持的格式说明:

    • 支持普通字符串定义,路由跳转采用全路径方式匹配,例如定义demo://xxxx,路由跳转时pageUrl=demo://xxx可以使用全路径匹配

    3.pageUrl路由匹配优先级说明:优先全路径匹配,然后匹配正则格式路由,正则内的路由匹配优先级通过regexPriority属性设置;例如定义了两个路由:pageUrl/detail, pageUrl/.* ;当路由跳转时传入pageUrl=/pages/detail,将匹配第一个/pages/detail,当路由跳转时传入pageUrl=/pages/abcdef时,将匹配/pages/.*定义的路由页面

  • isRegex:boolean, 标识配置的pageUrl是否是正则表达式,如果配置为正则,会影响页面跳转效率,配置为true时,需要确保pageUrl为正确的正则表达式格式,非必填
  • regexPriority: number, pageUrl正则匹配优先级,数字越大越先匹配,默认值为0,优先级相同时,不保证先后顺序,非必填,默认为0
  • dialog: boolean, 是否是Dialog类型页面,非必填,默认为false
  • singleton: boolean, 是否是单例页面,单例页面即表示在一个HMNavigation容器中,只有一个此页面,非必填,默认为false
  • interceptors: string[], @HMInterceptor标记的拦截器名称列表,非必填
  • lifecycle: string, @HMLifecycle标记的生命周期处理实例,非必填
  • animator: string, @HMAnimator标记的自定义转场实例,非必填

示例:

@HMRouter({pageUrl: 'pageOne',interceptors: ['LoginInterceptor'],lifecycle: 'pageLifecycle',animator: 'pageAnimator'
})
@Component
export struct PageOne {build() {}
}// constants.ets
export class Constants {static readonly PAGE: string = 'pageTwo'
}@HMRouter({ pageUrl: Constants.PAGE })
@Component
export struct PageOne {build() {}
}

拦截器标签 @HMInterceptor

标记在实现了IHMInterceptor的对象上,声明此对象为一个拦截器

  • interceptorName: string, 拦截器名称,必填
  • priority: number, 拦截器优先级,数字越大优先级越高,非必填,默认为9;
  • global: boolean, 是否为全局拦截器,当配置为true时,所有跳转均过此拦截器;默认为false,当为false时需要配置在@HMRouter的interceptors中才生效。

执行时机:

在路由栈发生变化前,转场动画发生前进行回调。 1.当发生push/replace路由时,pageUrl为空时,拦截器不会执行,需传入pageUrl路径;

2.当跳转pageUrl目标页面不存在时,执行全局以及发起页面拦截器,当拦截器未执行DO_REJECT时,然后执行路由的onLost回调

3.当跳转pageUrl目标页面存在时,执行全局,发起页面和目标页面的拦截器;

拦截器执行顺序:

  1. 按照优先级顺序执行,不区分自定义或者全局拦截器,优先级相同时先执行@HMRouter中定义的自定义拦截器
  2. 当优先级一致时,先执行srcPage>targetPage>global

srcPage表示跳转发起页面。

targetPage表示跳转结束时展示的页面。

示例:

@HMInterceptor({priority: 9,interceptorName: 'LoginInterceptor'
})
export class LoginInterceptor implements IHMInterceptor {handle(info: HMInterceptorInfo): HMInterceptorAction {if (isLogin) {// 跳转下一个拦截器处理return HMInterceptorAction.DO_NEXT;} else {HMRouterMgr.push({pageUrl: 'loginPage',param: { targetUrl: info.targetName },skipAllInterceptor: true})// 拦截结束,不再执行下一个拦截器,不再执行相关转场和路由栈操作return HMInterceptorAction.DO_REJECT;}}
}

生命周期标签 @HMLifecycle

@HMLifecycle(lifecycleName, priority, global)

标记在实现了IHMLifecycle的对象上,声明此对象为一个自定义生命周期处理器

  • lifecycleName: string, 自定义生命周期处理器名称,必填
  • priority: number, 生命周期优先级,数字越大优先级越高,非必填,默认为9;
  • global: boolean, 是否为全局生命周期,当配置为true时,所有页面生命周期事件会转发到此对象;默认为false

生命周期触发顺序:

按照优先级顺序触发,不区分自定义或者全局生命周期,优先级相同时先执行@HMRouter中定义的自定义生命周期

示例:

@HMLifecycle({ lifecycleName: 'exampleLifecycle' })
export class ExampleLifecycle implements IHMLifecycle {
}

转场动画标签 @HMAnimator

标记在实现了IHMAnimator的对象上,声明此对象为一个自定义转场动画对象

  • animatorName: string, 自定义动画名称,必填。

示例:

@HMAnimator({ animatorName: 'exampleAnimator' })
export class ExampleAnimator implements IHMAnimator {effect(enterHandle: HMAnimatorHandle, exitHandle: HMAnimatorHandle): void {}
}

服务标签 @HMServiceProvider

标记在类上,声明此类为一个服务

  • serviceName: string,服务名称,必填。
  • singleton: boolean,是否是单例,非必填,默认为false

示例:

@HMServiceProvider({ serviceName: ServiceConstants.CLASS_SERVICE, singleton: true })
export class CustomService implements IService {testConsole(): void {Logger.info('Calling service testConsole');}
}

使用HMRouterMgr.getService()进行调用

const res = HMRouterMgr.getService<IService>(ServiceConstants.CLASS_SERVICE).testFunWithReturn()

服务标签 @HMService

标记在类的方法上,声明此方法为一个服务

  • serviceName: string,服务名称,必填。
  • singleton: boolean,是否是单例,非必填,默认为false

示例:

export class ExampleClass {@HMService({ serviceName: 'ExampleService', singleton: true })exampleFun(params: string): void {}
}

文章转载自:

http://r74jPpyC.ngmjn.cn
http://0OLG7k3y.ngmjn.cn
http://qYjT2G3s.ngmjn.cn
http://u6ES2J1G.ngmjn.cn
http://EIcwkQ5t.ngmjn.cn
http://HM7Ekxpg.ngmjn.cn
http://rk9nWhoe.ngmjn.cn
http://DfqBI7AQ.ngmjn.cn
http://9igxzZPk.ngmjn.cn
http://uAsdYcFt.ngmjn.cn
http://ksazH4Yn.ngmjn.cn
http://xWXAaR0h.ngmjn.cn
http://ALpH0Tv0.ngmjn.cn
http://S9m5IcbS.ngmjn.cn
http://xbptETVd.ngmjn.cn
http://7XyPMX3h.ngmjn.cn
http://pyehuFu8.ngmjn.cn
http://USXTeKNa.ngmjn.cn
http://YEqODBS2.ngmjn.cn
http://H5moDzze.ngmjn.cn
http://nKNAYAQT.ngmjn.cn
http://pUkJw0Hi.ngmjn.cn
http://5Ya2EbQG.ngmjn.cn
http://rt8udubw.ngmjn.cn
http://qHsJteLN.ngmjn.cn
http://ONRSqCGL.ngmjn.cn
http://BS2CcxqM.ngmjn.cn
http://Qt7JA8po.ngmjn.cn
http://sIc4qWjb.ngmjn.cn
http://DVJ5GkWD.ngmjn.cn
http://www.dtcms.com/a/387277.html

相关文章:

  • 为什么 socket.io 客户端在浏览器能连接服务器但在 Node.js 中报错 transport close?
  • Express框架介绍(基于Node.js的轻量级、灵活的Web应用框架)
  • Lustre Ceph GlusterFS NAS 需要挂载在k8s容器上,数据量少,选择哪一个存储较好
  • Axios与Java Spring构建RESTful API服务集成指南
  • 贪心算法应用:集合覆盖问题详解
  • 分布式拜占庭容错算法——权益证明(PoS)算法详解
  • Maven 深入profiles和mirrors标签
  • SQL Server 运维实战指南:从问题排查到性能优化
  • FFmpeg的安装及简单使用
  • F019 vue+flask海外购商品推荐可视化分析系统一带一路【三种推荐算法】
  • R语言数据统计分析与ggplot2高级绘图实践应用
  • Java 设计模式——观察者模式进阶:分布式场景扩展与实战配置
  • ​​[硬件电路-238]:电阻、电容、电感对数字电路中的作用
  • IPD驱动下的电源技术革命:华为数字能源模块化复用与降本增效实践
  • 线性回归与 Softmax 回归:深度学习基础模型解析
  • 安全迎国庆|假日期间,企业如何做好网络安全防护?
  • Product Hunt 每日热榜 | 2025-09-16
  • 告别静态图谱!TextSSL如何用「稀疏学习」实现更智能的文档分类?
  • centos Apache服务器安装与配置全攻略
  • centos配置hadoop环境变量并可启动hadoop集群
  • 告别“扁平化”UI:我用Substance Painter+glTF,构建空间感交互界面工作流
  • 【2026计算机毕业设计】基于Django的选课系统的设计与实现
  • 大文件传输软件选型指南:如何选择高效安全的企业级解决方案
  • 元宇宙与教育产业:沉浸式交互重构教育全流程生态
  • linux时间同步
  • Linux嵌入式自学笔记(基于野火EBF6ULL):3.连网、Linux文件目录
  • 【高并发内存池——项目】thread cache 讲解
  • InnoDB ACID实现:数据库可靠性的核心秘密
  • python ui框架
  • 【Linux手册】解决多线程共享资源访问冲突:互斥锁与条件变量的使用及底层机制