背景と問題点
CSDNアプリテクノロジースタックの拡張により、最も単純なネイティブページからネイティブページへのジャンプが、同じアプリ内のネイティブページ、H5ページ、アプレットページ、およびFlutterページ間のジャンプに拡張されました。これによって引き起こされる問題は次のとおりです。アプリバージョンの反復では、元々ネイティブに実装されていた多くのページを新しいH5ページでアップグレード/ダウングレードするか、元のPCまたはH5ページを既存のネイティブページにリダイレクトする必要があります。 。そして、これらは基本的にハードコードされたジャンプロジックであり、バージョンによって常に変更する必要があります。要約すると、各テクノロジスタックによって分離されたページジャンプロジックが直面する既存の直接的な問題は次のとおりです。
- ジャンプのロジックはバージョンに基づいて反復的に行う必要があり、統一された方法でリモートで変更することはできません(たとえば、インターセプトして元のページにジャンプする必要があるページが追加されるたびに、次の方法で解決する必要があります。バージョンの発行)
- テクノロジースタックを飛び越えるための実装コストは比較的高く、ブリッジモジュールで特別な適応を行う必要があります
- H5ページでは、一部のジャンプはネイティブページまたは他のページにジャンプする必要があり、WebViewジャンプのインターセプトを通じて特別な判断処理を行う必要があります。
ハードコーディングと柔軟性の低さという上記の問題を解決するために、動的で構成可能なニーズを満たすことができる既存のテクノロジースタックジャンプロジックを組み合わせることにより、これらのジャンプを統合します。
ルーティングの意味
最初に明確にする必要があるのは、ルーティングはインターフェイスジャンプだけでなく、データ取得とビジネス処理も指すということです。
フロントエンドルーティング
ネットワークでのルーティングの概念は、ルーターが1つのインターフェイスからデータパケットを受信し、データパケットの宛先アドレスに従って別のインターフェイスに転送するプロセスを指します。率直に言って、ルーティングはデータを収集して配布するプロセスです。フロントエンド開発では、ルーティングの役割は主にビューとURL情報の同期を確保することです。ユーザーはページを手動で入力または操作することでURLを変更でき、プログラムはサーバーにリクエストを送信してリソースを取得します。次に、UIを再描画します。iOSモバイル端末は、フロントエンドのアイデアを借用し、合意されたルーティングプロトコルに従い、特定のビューコンポーネント/コントローラー/機能およびその他のリソースに何らかの方法でマッピングできます。
モバイル(iOS)ルーティング
URI
ユニフォームリソース識別子(Uniform Resource Identifier)は、インターネットリソースを識別するために使用される文字列であり、特定のプロトコルを介してネットワーク内のリソースの相互運用性を可能にします。URIの最も一般的な形式は、Uniform ResourceLocatorURLです。
这是一段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,动态地下发到客户端。
ルーティングルールは、キーと対応する値に分けられます。キーは登録されるルート(一致ルール)であり、値はインスタンス化されるコントローラーの名前またはリダイレクトされる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];
}
}];
复制代码
実用化
まず、動的ルーティングの使用の背景について説明します。CSDNAPPのスキルツリーモジュールは小さなプログラムで開発されています。次に、H5なしでAPPのPC URLを開く必要があり、小さなプログラムを使用してページを表示します。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"
}
}
复制代码