更新时间: 2018-6-6

在程序开发过程之中, 我们总是希望模块化处理某一类相似的事情。 在 ezbuy 开发中, 我接触到了对于 URL 处理的优秀的代码, 学习、改进、记录下来。希望对你有所帮助。

对于 URL 处理, 我将分为两个部分来说明:

  • URL Handle in Swift (一) - URL 分解;
  • URL Handle in Swift (二) - 响应链处理 URL 。

一、 URL 格式分析

URL(Uniform Resource Locator) 全称为“统一资源定位符”, 有时也被俗称为网页地址网址)

URL标准格式如下:

截取《网络是怎样连接的》的图片来解释一下(图侵删)

实际上, URL的标准格式中, 我们可以通过参数来传递相关的信息, 如 https://www.google.com.hk/search?q=rsenjoyer

二、 iOS 客户端处理 URL

iOS客户端的URL大体可以分为两类:

  • 自定义协议的URL, 如: igame://myNote
  • 标准的HTTP(S) URL;

理论上你可以自定义任意的协议来构建URL, 响应协议URL。 在 iOS 开发中,你可以来自定义 URL Scheme 来实现应用程序间的通信。 URL Scheme 相关的信息你可以参考URL Schemes 使用详解 以及 Inter-App Communication

对于标准的 HTTP(S) URL,不同的URL有着不一样的处理的方式。如:大多情况下, 应用程序受到一个URL就直接用 WKWebView 或者 UIWebView 直接打开; 但处理 Universal Link是需要打开应用程序内对应的页面等。

根据需求, 可以设计出如下的结构图:

不同的URL通过Bridge最终都转换为 “统一”的 Instruction, Instruction保存着 URL所有的信息, “Handler”通过 Instruction的信息执行不一样的处理。

Talk is Cheap, Show me the code!!

2.1 Bridge代码的实现

Bridge 根据URL的不同而转换成 Instruction。

//
// IGBridge.swift
// eziNode
//
// Created by enjoy on 2018/4/9.
// Copyright © 2018年 enjoy. All rights reserved.
// import Foundation protocol IGBridge { func bridgeToIG(from url: URL?) -> IGInstruction? func bridgeToURL(from instruction: IGInstruction?) -> URL?
} class IGameAppURLBridge: IGBridge { private static let iGameAppScheme = "igame" static let `default` = IGameAppURLBridge() func bridgeToIG(from url: URL?) -> IGInstruction? { guard let url = url else { return nil } guard let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true), urlComponents.scheme?.lowercased() == IGameAppURLBridge.iGameAppScheme else { return nil } guard let host = urlComponents.host else { return nil } let queries = makeDictionary(fromQueryItems: urlComponents.queryItems) let components = urlComponents.path.components(separatedBy: "/").filter { !$0.isEmpty } let instruction = IGInstruction(type: IGInstructionType(identifier: host), components: components, queryItems: queries, bridge: self) return instruction
} func bridgeToURL(from instruction: IGInstruction?) -> URL? {
// 转换为 URL
}
} class HttpWebURLBridge: IGBridge {
// HttpWebURLBridge 的实现
} class UniversalLinURLBridge: IGBridge {
// UniversalLinURLBridge 的实现
}

2.2 Instruction代码实现

“Instruction”需要包含着 URL 完整的以及需要怎样被处理. 客户端所支持的 URL 类型实际上可以用一个枚举来列出。


import Foundation // 客户端支持的URL 类型
public enum IGInstructionType: String { case specialExercise
case examinationPaper
case redoWrong
case collection
case myNote
case refreshQuestionSet
case unKnown init(identifier: String?) {
guard let identifier = identifier else { self = .unKnown; return } switch identifier {
case IGInstructionType.specialExercise.rawValue:
self = .specialExercise
case IGInstructionType.examinationPaper.rawValue:
self = .examinationPaper
case IGInstructionType.redoWrong.rawValue:
self = .redoWrong
case IGInstructionType.collection.rawValue:
self = .collection
case IGInstructionType.myNote.rawValue:
self = .myNote
case IGInstructionType.refreshQuestionSet.rawValue:
self = .refreshQuestionSet
default:
self = .unKnown
}
} } struct IGInstruction { let type: IGInstructionType let components: [String] var path: String {
return self.components.isEmpty ? "" : ([""] + self.components).joined(separator: "/")
} let queryItems: [String: String] var bridge: IGBridge? init(type: IGInstructionType, components: [String] = [], queryItems: [String: String] = [:], bridge: IGBridge? = nil ) {
self.type = type
self.components = components
self.queryItems = queryItems
self.bridge = bridge
}
} extension IGInstruction { // Options 下面会提到
init?(url: URL?, options: IGURLBridgeOptionsInfo = [.iGameApp]) { if let bridge = options.iGameAppUrlBridge, let ins = bridge.bridgeToIG(from: url) {
self = ins
return
} if let bridge = options.httpWebUrlBridge, let ins = bridge.bridgeToIG(from: url) {
self = ins
return
} if let bridge = options.universalUrlBridge, let ins = bridge.bridgeToIG(from: url) {
self = ins
return
} return nil
}
} extension IGInstruction { var url: URL? {
return self.bridge?.bridgeToURL(from: self)
}
}

2.3 Options 可选值

import Foundation

typealias IGURLBridgeOptionsInfo = [IGURLBridgeInfoItem]

enum IGURLBridgeInfoItem {

    case iGameApp

    case httpWeb

    case universalLink
} precedencegroup ItemComparisonPrecedence {
associativity: none
higherThan: LogicalConjunctionPrecedence
} infix operator <== : ItemComparisonPrecedence func <== (lhs: IGURLBridgeInfoItem, rhs: IGURLBridgeInfoItem) -> Bool { switch (lhs, rhs) {
case (.iGameApp, .iGameApp): return true
case (.httpWeb, .httpWeb): return true
case (.universalLink, .universalLink): return true
default: return false
}
} extension Collection where Iterator.Element == IGURLBridgeInfoItem { func lastMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
return reversed().first { $0 <== target }
} func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
return filter { !($0 <== target) }
}
} extension Collection where Iterator.Element == IGURLBridgeInfoItem { var iGameAppUrlBridge: IGameAppURLBridge? {
if let item = lastMatchIgnoringAssociatedValue(.iGameApp),
case .iGameApp = item
{
return IGameAppURLBridge.default
}
return nil
} var httpWebUrlBridge: HttpWebURLBridge? {
if let item = lastMatchIgnoringAssociatedValue(.httpWeb),
case .httpWeb = item
{
return HttpWebURLBridge.default
}
return nil
} var universalUrlBridge: UniversalLinURLBridge? {
if let item = lastMatchIgnoringAssociatedValue(.universalLink),
case .universalLink = item
{
return UniversalLinURLBridge.default
}
return nil
}
}

AppDelegate实现

iOS AppDelegate 默认是一个全局的单例,因此可以将其设置为处理的入口;


@objc static let current: AppDelegate = UIApplication.shared.delegate as! AppDelegate @discardableResult
func handleIGURL(_ url: URL, httpConvertible: Bool = true) -> Bool { guard let instruction = IGInstruction(url: url, options: httpConvertible ? [.iGameApp, .httpWeb] : [.iGameApp]) else { return false } return handleIGInstruction(instruction)
} func handleIGInstruction(_ ins: IGInstruction) -> Bool { switch ins.type {
case .specialExercise, .examinationPaper, .redoWrong, .collection, .myNote, .refreshQuestionSet:
print("handler --- \(ins.type.rawValue) 类型数据")
default:
break
}
return true }
}

URL Handle in Swift (一) -- URL 分解的更多相关文章

  1. URL Handle in Swift (二) — 响应链处理 URL

    最后更新: Swift4时候的博客,以前在 CMD markdown 上编辑的,现在搬到这里 在上篇文章-URL Handle in Swift (一) -- URL 分解中,我们已经将URL进行了分 ...

  2. SharePoint 2010 Url Shortener --SharePoint 2010 短URL生成器

    SharePoint 2010 Url Shortener --SharePoint 2010 短URL生成器 项目描写叙述 本项目加入了这种功能.在SP站点中能够生成短URLs. 这些URLs指向列 ...

  3. js 获取url中的参数 修改url 参数 移除url参数

    js 获取url中的参数 修改url 参数 移除url参数 var jsUrlHelper = { getUrlParam : function(url, ref) { var str = " ...

  4. Django报错:提交表单报错---RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and you have APPEND_SLASH set.

    Django报错:提交表单报错---RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and ...

  5. IDEA报错: Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.datasource.url' in value "${spring.datasource.url}"

    运行审核流模块: 在ActivitiServiceApplication模块日志报错: Error starting ApplicationContext. To display the auto-c ...

  6. django ajax报错解决:You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set.

    Django版本号:1.11.15 django中ajax请求报错:You called this URL via POST, but the URL doesn't end in a slash a ...

  7. UrlUtils工具类,Java URL工具类,Java URL链接工具类

    UrlUtils工具类,Java URL工具类,Java URL链接工具类 >>>>>>>>>>>>>>>&g ...

  8. 获取URL的name值 getUrl(url,name) 传入url和key 得到key对应的value

    <body> <script type="text/javascript"> var url = "http://192.168.1.82:802 ...

  9. 加密解密Url字符串,C#对Url进行处理,传递Url

    string _QueryStringKey = "abcdefgh"; //URL传输参数加密Key /// 加密URL传输的字符串        public string E ...

随机推荐

  1. 【13】react 之 redux(2)

    转载:http://www.cnblogs.com/MuYunyun/p/6530715.html 什么情况需要用redux? 用户的使用方式复杂 不同身份的用户有不同的使用方式(比如普通用户和管理员 ...

  2. 子Repeater获取父级Repeater绑定项的值

    原文发布时间为:2010-12-27 -- 来源于本人的百度文章 [由搬家工具导入] 1.子级Repeater中绑定父级的某个字段: <%# DataBinder.Eval((Container ...

  3. Accelerating Enum-Based Dictionaries with Generic EnumComparer

    原文发布时间为:2011-03-03 -- 来源于本人的百度文章 [由搬家工具导入] 文章:http://www.codeproject.com/KB/cs/EnumComparer.aspx 源码: ...

  4. 怎样让enum枚举支持string

    原文发布时间为:2011-03-02 -- 来源于本人的百度文章 [由搬家工具导入] 大家都知道enum是以下两种情况,不能支持string 1,enum类型是静态 2,enum类型仅限于long、i ...

  5. C 语言 和 python 调用 .so 文件

    什么是静态库和动态库, 看一篇博客 http://www.cnblogs.com/skynet/p/3372855.html 现在,我们首先生成.so文件 首先, 我们写一个a.c文件 1 2 3 4 ...

  6. C语言中的内存相关问题

    内存是用来存储数据与程序的,对我们写程序来说非常重要.所以内存对程序来说几乎是本质需求.越简单的程序需要越少的内存,而越庞大越复杂的程序需要更多的内存. 注意:在嵌入式系统中有ROM和RAM两类内存, ...

  7. AC日记——幸运号码 51nod 1043

    幸运号码 思路: 传说中的数位dp: 不难发现,n(n<1000) ,那么,n个数的最大和为9*1000=9000: 对于9000*1000的时间范围,我们可以用dp来解决: dp[i][j], ...

  8. 解决dvajs使用BrowserHistory路由模式后仍然会出现hash(哈希)

    在dvajs中,如果你在初始化dva对象的时候不作任何处理,那么你就会发现即使你是用了BrowserRouter来作为Router url中也是会出现#/.解决方法也很简单: 使用前先手动安装下 hi ...

  9. Codeforces Gym10081 A.Arcade Game-康托展开、全排列、组合数变成递推的思想

    最近做到好多概率,组合数,全排列的题目,本咸鱼不会啊,我概率论都挂科了... 这个题学到了一个康托展开,有点用,瞎写一下... 康托展开: 适用对象:没有重复元素的全排列. 把一个整数X展开成如下形式 ...

  10. hibernate中SQL包含冒号

    当前负责的项目使用的是hibernate,而“:”是hibernate的一个占位符,作为预编译使用的, select tmp.pid from (select pid, loginTime, @i : ...