背景
隨著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.routersfor (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 booleanif (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 objectlet routMapArray = jsonObj['routerMap'] as Array<object>if (!strUtils.isBlank(urlStr)) {try {let tempURL = Url.URL.parseURL(urlStr)let tempUrlStr = tempURL.protocol + '//' + tempURL.host + tempURL.pathnamelet found = falsefor (let value of routMapArray){let name = value['name'] as stringif (name === tempUrlStr) {found = truebreak}}return found}catch (err){}}return false}
至此,基本路由跳轉方案均已經實現,另外可以通過判斷路由是否注冊,來提示用戶。