背景&痛点

随着CSDN App技术栈的扩展,从原本最最简单的原生页面到原生页面的跳转,扩展到目前同一个App中包含原生页面、H5页面、小程序页面、Flutter页面之间的跳转。

这样带来的问题是:随着App的版本迭代,很多原本原生实现的页面,需要通过新的H5页面进行升级/降级,或者原本PC或者H5页面,需要重定向到已有的原生页面。而这些基本都是硬编码的跳转逻辑,需要随着版本不停改动。总结下来,现有的,各个技术栈隔离的页面跳转逻辑面临的直接问题有:

  • 跳转的逻辑需要根据版本迭代走,无法统一远程进行改动(例如:每次新增一个需要拦截跳转原生的页面,都需要通过发版来解决)
  • 跨技术栈跳转的实现成本比较高,必须在桥接模块中进行特殊适配
  • H5页面中,某些跳转需要跳转原生或者其他页面,必须要通过WebView跳转的拦截做特殊判断处理

为了解决以上硬编码及灵活性差的问题,我们通过梳理现有的各技术栈跳转逻辑,将这些跳转整合,能够满足动态性、可配置的需求。

路由的意义

首先要明确的是,路由并非只是指的界面跳转,还包括数据获取,业务处理。

前端的路由

网络中路由概念是指路由器从一个接口上接收到数据包,根据数据包的目的地址进行定向转发到另一个接口的过程。直白一点就是,路由是一种数据的收集和分发过程。在前端开发中,路由的作用主要是保证视图和 URL 的信息同步,用户可以通过手动输入或者与页面进行交互来改变 URL,然后程序向服务端发送请求获取资源,接着重新绘制 UI。iOS 移动端可以借用前端的思路,遵循约定的路由协议,通过某种手段映射到具体的视图组件/控制器/功能等资源。

移动端(iOS)的路由

URI

统一资源标识符(Uniform Resource Identifier)是一种用于标识互联网资源的字符串,此种标识允许用于对网络中的资源通过特定的协议进行交互操作。URI 最常见的形式就是统一资源定位符 URL。


这是一段URL,每一段都代表类对应的含义,我们可以理解 URL 为一段携带了获取到某资源的所有必须的信息的特定组合字符串。

URL Scheme

iOS 系统里面支持的 URL Scheme 方式打开应用。我们可以通过 TARGETS -> Info -> URL Types 添加应用的 Scheme,该 Scheme 可以理解为 App 的一个身份标识,用它可以打开我们的应用(在三方分享时经常需要我们去平台生成自己的 Scheme,三方平台用此字段跳转我们App)。

这样,我们运行App之后,通过 Safari 就可以跳转到我们的App。输入 csdnapp:// 跳转。

你也可以通过 info.plist 文件中的 URL types 字段管理你的 URL Scheme 信息。即使你没有用过 URL Scheme,那么你一定使用过一些系统的服务,例如拨打电话,使用系统邮箱等功能。他们的协议头就像下面这样:

mailto://
tel://110

如果你未使用过,那么最直观的,你在手机的系统浏览器 Safari 中输入上面的命令,系统就会提示你是否拨打电话或者编写邮件。tel://mailto:// 就是系统电话和邮件应用的路由协议头。

一些热门的应用同样定义了自己的路由协议头,例如QQ、微信、微博等:

mqq://
weixin://
sinaweibo://
接收处理

通过 -openURL: 过来的的消息,我们可以通过 AppDelegate 中的回调代理进行接收处理:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options

Universal Links

使用 URL Scheme 有两个弊端,第一个就是混乱,由于 URL Scheme 是自定义字段,任何App都可以使用 weixin:// 这就可能导致系统跳转错误,这种情况在公司开发一系列的应用时经常发生。第二个就是如果用户未安装与URL Scheme对应的应用时,系统则无法正常跳转,这时通常需要我们程序员手动判断是否可以打开此 URL : -canOpenURL:,然后引导用户去安装对应的应用。

在 iOS 9.0 之后,苹果新增了一项功能 Universal Links,直译就是通用链接,这个功能让我们可以通过普通的 HTTP 链接就能启动我们的 App。

使用 Universal Links 跳转应用的好处就是:

如果安装了App,无论是在系统浏览器 Safari 里,还是在其他使用了webView控件的页面中,都可以打开App。

如果没有安装App,就会打开对应的网页,这个网页可以是宣传官网,又或者是下载安装地址。

从iOS 系统里面支持的URL Scheme方式,我们可以看出,对于一个资源的访问,苹果也是用URI的方式来访问的。

解决了什么问题


借用iOS 组件化 —— 路由设计思路分析一文中的图,很形象的展示了项目中各个控制器模块之间错综复杂的关系。
我们项目中使用的路由组件是基于MGJRouter进行二次开发实现的路由组件CNRouter,各种页面之间的跳转都可以通过 URL 的方式进行路由,
使用Router之后大概是这样:

步骤
  • APP内每个页面控制器都需要对应一个路由地址URL
  • 路由页面跳转前,需要将对应的路由地址URL注册到CNRouter
  • 不同页面跳转时,将消息发送到CNRouter中统一处理
  • CNRouter根据其注册的URL来找到对应信息,然后负责实例化,解析参数,跳转页面等业务处理

通过上述步骤,我们可以看到,每个控制器之间并不需要相互依赖对方,可以完美的解决不同模块之间的耦合。

动态路由的价值

基于CNRouter URL跳转,我们又实现了动态路由功能,它的职责主要有:

  • 承担 App 内所有页面跳转逻辑
  • 通过Apollo配置,支持获取/配置路由替换规则
  • 匹配所有的路由跳转规则,命中路由规则的直接进行跳转
  • 将实际跳转目标地址传递给路由组件执行实际的跳转行为(路由重定向)

实现方案

1、 路由注册与跳转

整个CNRouter就是由一个NSMutableDictonary *routes 控制的,routes中存放了所有已经注册的URL。

@interface CNRouter ()
/***  保存了所有已注册的 URL*  结构类似 @{@"blog": @{@":blogId": {@"_", [block copy]}}}*/
@property (nonatomic) NSMutableDictionary *routes;
@end


通过以下方法构造路由匹配规则的字典。

- (NSMutableDictionary *)addURLPattern:(NSString *)URLPattern
{NSArray *pathComponents = [self pathComponentsFromURL:URLPattern];NSMutableDictionary* subRoutes = self.routes;for (NSString* pathComponent in pathComponents) {if (![subRoutes objectForKey:pathComponent]) {subRoutes[pathComponent] = [[NSMutableDictionary alloc] init];}subRoutes = subRoutes[pathComponent];}return subRoutes;
}

例如注册以下两条路由:

[CNRouter registerURLPattern:@"https://blog.csdn.net/:userName/article/details/:articleId"  toHandler:^(NSDictionary *routerParameters) {}];
[CNRouter registerURLPattern:@"csdnapp://app.csdn.net/blog/detail"  toHandler:^(NSDictionary *routerParameters) {}];

按照上面构造路由匹配规则的字典的方法,该路由规则字典就会变成这个样子:

{https = {blog.csdn.net = {:userName = {article = {details = {:articleId = {_ = < __NSMallocBlock__: 0x282240ac0 > ;};};};};};};csdnapp = {app.csdn.net = {blog = {detail = {_ = < __NSMallocBlock__: 0x282241bc0 > ;};};};};
}

路由规则字典生成之后,等到路由匹配的时候就会遍历这个字典。所有注册的路由,都是以这种方式存放在routes中。
当有路由跳转时,调用以下方法:

[CNRouter openURL:@"https://blog.csdn.net/weixin_36162680/article/details/123161859" withUserInfo:@{@"isLogin": @YES} completion:^(id result) {NSLog(@"result = %@",result);
}];

上面的URL会匹配成功,那么生成的参数字典结构如下:

{userName = "weixin_36162680";CNRouterParameterUserInfo = {isLogin = 1;};CNRouterParameterURL = "https://blog.csdn.net/weixin_36162680/article/details/123161859";articleId = "123161859";
}

由上可见,路由组件CNRouter,它主要负责:

  • 启动时注册路由和页面
  • 查询正确的页面进行跳转或者执行其他业务逻辑

2、 动态路由与规则配置

概念

动态路由:粗略的讲就是指你的URL地址与页面或者组件之间的映射关系。 本项目会根据Apollo配置,通过远端下发的方式,去动态构建这个路由映射表。实现动态显示可跳转的页面或组件。

路由重定向

对于移动端的路由重定向,实际上就是将一个路由转换为另一个路由,例如:
https://live.csdn.net/room/:id
转换为:
csdnapp://app.csdn.net/live/room?id=xxxx

规则配置

路由重定向中的一个关键节点就是“配置”,我们需要一个路由规则列表来记录和下发匹配规则。为了方便下发路由规则表,我们将这份配置表存放在Apollo,动态地下发到客户端。

一条路由规则,分为一个 Key 和对应的 Value,Key 为需要注册的路由(匹配规则),Value 为需要实例化的控制器名称或者需要重定向的URL,使用 JSON 格式定义。
例如:

{"https://blog.csdn.net/:userName/article/details/:articleId": {"class": "CNNewBlogDetailViewController"},"https://live.csdn.net/room/:id": {"redirectUrl": "csdnapp://app.csdn.net/live/room"}
}

流程

在APP启动阶段拉取正确的路由表(映射规则),进行注册并且保存下来。

实际代码实现中,我们在页面执行跳转前,判断是否有重定向路由,如果有重定向路由,则执行重定向跳转,否则直接初始化目标控制器。


代码实现如下:

[CNRouter cn_addRoute:router handler:^(NSDictionary *routerParameters) {//判断是否有重定向if ([routerParameters[kCNRouteClassRedirectUrl] isValid]) {//跳转重定向地址[CNRouter cn_openURL: routerParameters[kCNRouteClassRedirectUrl] withUserInfo: routerParameters];}else{//初始化控制器[self executeRouterClassName:className parameters: routerParameters];}
}];

实际应用

先来说下使用动态路由的背景,CSDN APP中技能树模块是用小程序来开发的,现在需要将PC URL在APP中不用H5打开,需要用小程序来展示页面。而APP小程序的URL与PC的URL是不一致的,如果直接用PC URL的话,会存在无法跳转小程序问题。以私信中技能树跳转为例:

  • iOS中技能树小程序的路由URL:csdnapp://app.csdn.net/mpTinyApp?id=__UNI__C92EAF9?language=cloud_native
  • PC端私信中发送的URL: https://edu.csdn.net/skill/cloud_native

那么解决这一问题,只需要在 iOS 的动态路由添加一个规则,将 https://edu.csdn.net/skill/cloud_native 动态替换成 csdnapp://app.csdn.net/mpTinyApp?id=__UNI__C92EAF9&language=cloud_native 就可以了。
配置如下:

{"https://edu.csdn.net/skill/:language": {"redirectUrl": "csdnapp://app.csdn.net/mpTinyApp?id=__UNI__C92EAF9"}
}

iOS 动态路由实现方案相关推荐

  1. 动态添加的路由 直接访问_VUE 动态路由(二)

    上一篇介绍了一种动态路由的方案,由前端写好路由表,然后通过登陆用户的角色来匹配出需要的路由.今天来研究下另外一种方案,后端返回路由表,然后生成导航菜单. 先讲下场景,同样是做权限控制,要根据登陆者的角 ...

  2. seo vue 动态路由_基于Vue SEO的四种方案

    前言:众所周知,Vue SPA单页面应用对SEO不友好,当然也有相应的解决方案,下面列出几种最近研究和使用过的SEO方案,SSR和静态化基于Nuxt.js来说. 关于服务器渲染:,对Vue版本有要求, ...

  3. Unity(iOS)AssetBundle资源内存动态分块加密方案

    一.背景 AssetBunlde资源包是unity引擎游戏对资源(声音.图片.脚本等)的压缩包,那我们为啥要保护AssetBunlde(以下简称AB包)?对于一般技术人员都清楚, 游戏逆向者(游戏外挂 ...

  4. 《IP路由协议疑难解析》一1.3 动态路由

    本节书摘来自异步社区<IP路由协议疑难解析>一书中的第1章,第1.3节,作者 [美]Zaheer Aziz, CCIE #4127 , Johnson Liu, CCIE #2637 , ...

  5. Quagga:开源的基于Zebra实现了RIP, OSPF, BGP的动态路由软件

    目录 quagga简介 特性 安装 quagga简介 https://www.jianshu.com/p/300acac7801f Quagga是一个开源的基于Zebra实现了RIP, OSPF, B ...

  6. 路由ssr服务器信息不完整,基于Nuxt构建动态路由SSR服务

    大约两年前曾经分享过基于Vue的SSR框架Nuxt的简单使用<基于Vue.js的SSR方案之Nuxt.js>,今天因为有SSR需求又重新做了一些尝试. 由于目前在做的是一个能够动态构建页面 ...

  7. python组件的react实现_React-Router动态路由设计最佳实践

    写在前面 随着单页应用(SPA)概念的日趋火热,React框架在设计和实践中同样也围绕着SPA的概念来打造自己的技术栈体系,其中路由模块便是非常重要的一个组成部分.它承载着应用功能分区,复杂模块组织, ...

  8. Junos路由器静态路由及动态路由rip和ospf配置测试

    一.测试拓扑: 二.基本配置: A.R1: interface Ethernet0/0 ip address 202.100.100.1 255.255.255.0     no shut inter ...

  9. 演示:混合配置基于Linux winows cisco环境动态路由

    演示:混合配置基于Linux winows cisco环境动态路由 (使用GNS3+VM完全可以一台物理计算机上完成所有实验) 配套演示录像:http://edu.51cto.com/course/c ...

最新文章

  1. python 全栈开发,Day132(玩具管理页面,控制玩具通讯录,基于请求的好友关系建立)...
  2. ijkplayer-android框架详解
  3. jQuery面向对象写法规定写法样式规定
  4. bootstrap --- 面板
  5. 前端学习(3186):ant-design的button介绍按钮属性
  6. Silverlight+WCF 新手实例 象棋 介绍(一)
  7. python bokeh 示例_Python bokeh.plotting.figure.arc()用法及代码示例
  8. Ansible初级应用
  9. nginx 优化配置
  10. 汉服php素材,【福利】汉服裁剪制作图——收录大全
  11. android xp,安卓手机刷xp系统装机版xp
  12. 网吧电影视频服务器架设完全入门教程(转)
  13. 聚合物-化学键-聚合物PEG-Hyd-PDLLA /PLA-PHis-hyd-PEG/PEG-PUSeSe-PEG
  14. 【微信小程序】获取Bmob后端云数据库某一数据表的所有记录
  15. [bzoj1233]干草堆tower
  16. springboot 发送邮件 QQ邮箱 535error
  17. 递归、迭代和分治(1):递归
  18. 信息学奥赛一本通C++语言——1139:整理药名
  19. 如何做好百度竞价?需清楚竞价账户的结构和核心思维
  20. ADF——增广迪基—福勒检验 和 自相关

热门文章

  1. 什么是Openlaszlo
  2. 还在为信号不稳定、流量限速烦恼?来试试4G路由器
  3. 外企英文面试的决胜宝典
  4. seq2seq结构的问题以及PGN网络模型
  5. Cortex-M0(+)内核的处理器架构简介
  6. poj 1080 Human Gene Functions (最长公共子序列变形)
  7. Python_Crawl_spider对招聘网进行爬取
  8. SQL Sever 2019 安装教程
  9. 女王祖白绿和糖饭桌子的故事(二)
  10. HeyUI组件库发布vscode插件,PS教程: 如何开发vscode插件?