鸿蒙动态路由实现方案
背景
随着CSDN 鸿蒙APP 业务功能的增加,以及为了与iOS、Android 端统一页面跳转路由,以及动态下发路由链接,路由重定向等功能。鸿蒙动态路由方案的实现迫在眉睫。
实现方案
鸿蒙版本动态路由的实现原理,类似于 iOS与Android的实现原理,具体理论可以查看 iOS 动态路由实现 这篇博文,这边不在赘述,这边只阐述实现逻辑。
1、路由地址与页面绑定
为了让鸿蒙中的每个页面都有一个固定的URL地址,我们这边借助了三方框架 HMRouter,具体HMRouter的实现方案,可以查看文档
@HMRouter({ pageUrl: 'app://app.com/blog/detail' })
@Component
export struct BlogDetailPage {
}
2、动态路由注册与跳转
我们实现了一个Router类,该类来实现我们动态路由表存储以及跳转的所有逻辑。routers
中存放了所有已经注册的URL。
class Router {
/**
* 保存了所有已注册的 URL
* 结构类似 {"blog": {":blogId": {"_":callback}}}
*/
private routers:Map<string,CommonAllType>
}
通过下面方法实现注册动态路由表routers
/*
* 添加路由到路由表
* */
private addURL(urlStr:string):Map<string,CommonAllType>{
let pathComponents = this.pathComponentsFromURL(urlStr)
let subRoutes = this.routers
for (let pathComponent of pathComponents){
if (!subRoutes.get(pathComponent)) {
subRoutes.set(pathComponent,new Map())
}
subRoutes = subRoutes.get(pathComponent) as Map<string,CommonAllType>
}
return subRoutes
}
例如注册如下路由:
Router.registerURLPattern('https://blog.csdn.net/:us' ,(params)=> {
})
注册到本地路由表routers
中应该是如下所示
{
"https": {
"blog.csdn.net": {
":us": {
"_": function ( {...} )
}
}
}
}
所有注册的路由,都是以这种方式存储在routers
中,跳转时就会从路由表中查询匹配到的路由,来跳转。
当有路由跳转时,调用以下方法:
Router.openUrl('https://blog.csdn.net/weixin_36162680/article/details/124127748', {'isLogin':true})
跳转时,匹配到路由有,那么也会生成相应的路由参数,如下:
{
"un": "weixin_36162680",
"id": "124127748"
}
3、动态路由重定向实现及远端路由表格式
路由重定向
对于移动端的路由重定向,实际上就是将一个路由转换为另一个路由,例如:
https://blog.csdn.net/:us
转换为:
app://app.com/blog/detail?us=xxx
远端路由表格式
一条路由规则,分为一个 Key 和对应的 Value,Key 为需要注册的路由(匹配规则),Value 中包含重定向的路由地址,或者需要拦截的参数等。
这里面的Key 必须是与鸿蒙中页面所绑定的路由地址。
{
"app://app.csdn.net/blog/detail": {
"needLogin": true
},
"https://blog.csdn.net/:un": {
"redirectUrl": "csdnapp://app.csdn.net/blog/detail"
}
}
跳转时重定向逻辑
Router.registerURLPattern('https://blog.csdn.net/:us' ,(params)=> {
//判断是否需要登录
if (!UserTool.isLogin() && params.has(Router.routerNeedLogin)) {
let needLogin = params.get(Router.routerNeedLogin) as boolean
if (needLogin) {
Router.login()
return
}
}
//判断是否需要重定向
.....
})
HMRouter 路由是否注册
在使用的时候,还有情况需要判断页面是否绑定了HMRouter
/*
* hm_router是否注册
* */
static isRegisterHMRouter(urlStr: string) : boolean {
let mapJsonValue = getContext().resourceManager.getRawFileContentSync('hm_router_map.json')
let jsonStr: string = strUtils.uint8ArrayToStr(mapJsonValue)
let jsonObj = JSON.parse(jsonStr) as object
let routMapArray = jsonObj['routerMap'] as Array<object>
if (!strUtils.isBlank(urlStr)) {
try {
let tempURL = Url.URL.parseURL(urlStr)
let tempUrlStr = tempURL.protocol + '//' + tempURL.host + tempURL.pathname
let found = false
for (let value of routMapArray){
let name = value['name'] as string
if (name === tempUrlStr) {
found = true
break
}
}
return found
}
catch (err){
}
}
return false
}
至此,基本路由跳转方案均已经实现,另外可以通过判断路由是否注册,来提示用户。