URL Handle in Swift (一) -- URL 分解
更新时间: 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 分解的更多相关文章
- URL Handle in Swift (二) — 响应链处理 URL
最后更新: Swift4时候的博客,以前在 CMD markdown 上编辑的,现在搬到这里 在上篇文章-URL Handle in Swift (一) -- URL 分解中,我们已经将URL进行了分 ...
- SharePoint 2010 Url Shortener --SharePoint 2010 短URL生成器
SharePoint 2010 Url Shortener --SharePoint 2010 短URL生成器 项目描写叙述 本项目加入了这种功能.在SP站点中能够生成短URLs. 这些URLs指向列 ...
- js 获取url中的参数 修改url 参数 移除url参数
js 获取url中的参数 修改url 参数 移除url参数 var jsUrlHelper = { getUrlParam : function(url, ref) { var str = " ...
- 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 ...
- 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 ...
- 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 ...
- UrlUtils工具类,Java URL工具类,Java URL链接工具类
UrlUtils工具类,Java URL工具类,Java URL链接工具类 >>>>>>>>>>>>>>>&g ...
- 获取URL的name值 getUrl(url,name) 传入url和key 得到key对应的value
<body> <script type="text/javascript"> var url = "http://192.168.1.82:802 ...
- 加密解密Url字符串,C#对Url进行处理,传递Url
string _QueryStringKey = "abcdefgh"; //URL传输参数加密Key /// 加密URL传输的字符串 public string E ...
随机推荐
- Bzoj 3145 - [Feyat cup 1.5]Str
bzoj 3145 - [Feyat cup 1.5]Str Description 给你两个长度\(10^5\)级别的串\(S, T\) 求\(S,T\)的最长模糊匹配公共子串 模糊匹配 : 至多一 ...
- [AGC003F] Fraction of Fractal(矩阵乘法)
Description Snuke从他的母亲那里得到了生日礼物--一个网格.网格有H行W列.每个单元格都是黑色或白色.所有黑色单元格都是四联通的,也就是说,只做水平或垂直移动且只经过黑色单元格即可从任 ...
- 【CF1073C】Vasya and Robot(二分,构造)
题意:给定长为n的机器人行走路线,每个字符代表上下左右走,可以更改将一些字符改成另外三个字符,定义花费为更改的下标max-min+1, 问从(0,0)走到(X,Y)的最小花费,无解输出-1 n< ...
- Xcode打包和生成ipa文件
1.生成Archive文档 a) 需将左上角红色方框里的设备类型选为ios device,不能选择具体的设备类型,否则不能生成Archive文档: b) 中部选择Team的方框,可此时选,也在后续ex ...
- 【Visual Studio】设置使用多字符集
- 802.11 MAC层
1. 介绍 本文主要介绍了802.11 MAC层 2. 访问机制 CSMA/CA: Carrier Sense Multiple Access with Collision Avoidance Wi ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---23
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:
- python+requests接口自动化测试框架
1.首先,我们先来理一下思路. 正常的接口测试流程是什么? 脑海里的反应是不是这样的: 确定测试接口的工具 —> 配置需要的接口参数 —> 进行测试 —> 检查测试结果(有的需要数据 ...
- python print的参数介绍
参考print的官方文档 print(...) print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints th ...
- LeetCode OJ-- Populating Next Right Pointers in Each Node II **@
https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ 接上一题目,输入的树不是perfect ...