iOS页面路由思路

iOS页面路由,具体可能需要处理的场景、问题有:

  1. 最普通 原生页面跳转到原生页面
  2. 有多种技术栈的app,可能包含原生、h5/rn/flutter等页面。就扩展出:
    • 原生页面和h5页面互相跳转
    • 原生和rn页面互相跳转
    • 原生和flutter互相跳转等
  3. 在上述的基础上,很多原本原生实现的页面,需要通过新的H5页面进行升级/降级,或者原本PC或者H5页面,需要重定向到已有的原生页面。而这些基本都是硬编码的跳转逻辑,需要随着版本不停改动。跳转的逻辑需要根据版本迭代走,无法统一远程进行改动(例如:每次新增一个需要拦截跳转原生的页面,都需要通过发版来解决)
    • 跨技术栈跳转的实现成本比较高,必须在桥接模块中进行特殊适配。H5页面中,某些跳转需要跳转原生或者其他页面,必须要通过WebView跳转的拦截做特殊判断处理
    • 需要梳理的各技术栈跳转逻辑,将这些跳转整合,能够满足动态性、可配置的需求。
  4. 一些应用有社交分享功能,需要分享出去一个链接以打开自身app内特定页面。或者有应用内分享链接 也可以打开自身app内特定页面。
    • 一般来说 应用外打开app需要使用iOS的URL Scheme功能或者Universal links功能

iOS页面路由

URI简介

统一资源标识符(Uniform Resource Identifier)是一种用于标识互联网资源的字符串,此种标识允许用于对网络中的资源通过特定的协议进行交互操作。URI 最常见的形式就是统一资源定位符 URL。
URL WIKI
这是一段URL,每一段都代表类对应的含义,我们可以理解 URL 为一段携带了获取到某资源的所有必须的信息的特定组合字符串。

URL Scheme

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

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

1
2
mailto://
tel://110

我们可以通过 AppDelegate 中的回调代理进行接收处理:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options

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

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

如果安装了App,无论是在系统浏览器 Safari 里,还是在其他使用了webView控件的页面中,都可以打开App。
如果没有安装App,就会打开对应的网页,这个网页可以是宣传官网,又或者是下载安装地址。

设计iOS路由需要考虑的

  1. APP内外跳转统一:APP外跳转是用的URL方式,起码应用内跳转需要做到支持URL解析映射到页面的逻辑
    1. 通过URLScheme过来的的消息 需要在- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options中处理参数
    2. 通过Universal Link/Spotlight打开的 ,并且userActivity:activityType为NSUserActivityTypeBrowsingWeb需要在- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler; 之中处理参数
  2. 老生常谈的的页面互相引用耦合问题
    1. 原始页面跳转一般是直接引用目标页面,然后初始化获取目标页面实例,然后手动跳转到该页面。这样就会造成页面之间的相互引用耦合
    2. 目前常见的路由做法为 所有页面引用路由中心,通过传入参数从路由中心获取目标页面实例进行跳转。其注册的URL来找到对应信息,然后负责实例化,解析参数,跳转页面等业务处理。在这个实现里完成引用的转移。
  3. 页面配置相关
    1. 页面配置对应URI是否配置成 scheme://router/demo 一个完整的URI 或者URI的部分,path 参数相组合。配置成部分信息的场景在于对于一个页面有时候不仅仅只需要一个路由动作,可能是仅仅是拿取这个vc实例,可能是拿取vc嵌套进其他页面,可能是与这个vc通信。即不只有router一个动作,配置成URI部分,URI的前面信息可以改成 scheme://action等便于复用。
    2. 配置信息的分布,配置信息是统一注册,还是可以每个页面离散式注册。不同的方式可以带来不同优势和缺点。
    3. 是否有动态路由 动态配置下发。粗略的讲就是指你的URL地址与页面或者组件之间的映射关系。 会根据最新配置,通过远端下发的方式,去动态构建这个路由映射表。实现动态显示可跳转的页面或组件。一般来说经常的用法是某个URL配置不同的活动页面,或者某个iOS原生页面降级为h5页面,或者h5页面替换为RN页面等等
  4. 页面跳转相关
    1. 在iOS里一般有两种跳转push 和 present方式,或者是自定义一个UIView盖在上面自己控制相关的转场动画。
    2. 比较简单的做法有直接在当前页面进行push跳转到下一个页面,或者遇到当前页无法push的先present一个UINavigationController然后在这个UINavigationController中进行push
    3. 另外一种当然是直接present目标页面,一直present操作…
    4. 在有tabcontroller时,还需要处理跨tab跳转
  5. 页面间传值
    1. 页面间传值有许多方式,比如属性传值,delegate传值,通过中间持久层(单例、数据库、NSUserDefalt)等传递
    2. 既然页面路由统一了跳转方式,页面间传值也需要统一一下。比较简单的方法有将要传递的信息通过字典传递给下一个页面,路由实例化下一个页面后统一调用解析参数方法。解析参数方法具体实现由各个页面自定义实现。