URLNavigator
URLNavigator.register(_:_:)
函数来映射 URL 模式。
URLNavigator 可以用于使用两种类型映射 URL 模式: URLNavigable
和 URLOpenHandler
。 URLNavigable
是一个定义自定义初始化器的类型,而 URLOpenHandler
是一个可以执行的闭包。初始化器和闭包都接收一个 URL 和占位符值。
开始使用
1. 理解 URL 模式
URL 模式可以包含占位符。占位符将用从 URL 中匹配的值替换。使用 <
和 >
来创建占位符。占位符可以有类型: string
(默认),int
,float
和 path
。
例如,myapp://user/<int:id>
与以下匹配:
myapp://user/123
myapp://user/87
但它不匹配以下内容:
myapp://user/devxoul
(预期为整数)myapp://user/123/posts
(URL结构不同)/user/devxoul
(缺少协议)
2. 将视图控制器和URL打开处理程序映射
URLNavigator允许使用URL模式映射视图控制器和URL打开处理程序。以下是一个将URL模式与视图控制器和闭包进行映射的示例。每个闭包有三个参数:url
、values
和 context
。
url
是从push()
和present()
传递的URL。values
是一个包含URL占位符键的字典。context
是一个包含由push()
、present()
或open()
传递的额外值的字典。
let navigator = Navigator()
// register view controllers
navigator.register("myapp://user/<int:id>") { url, values, context in
guard let userID = values["id"] as? Int else { return nil }
return UserViewController(userID: userID)
}
navigator.register("myapp://post/<title>") { url, values, context in
return storyboard.instantiateViewController(withIdentifier: "PostViewController")
}
// register url open handlers
navigator.handle("myapp://alert") { url, values, context in
let title = url.queryParameters["title"]
let message = url.queryParameters["message"]
presentAlertController(title: title, message: message)
return true
}
3. 推送、显示和打开URL
URLNavigator可以推送和显示视图控制器,并使用URL执行闭包。
将from
参数提供到push()
以指定新视图控制器将要推送的导航控制器。类似地,将from
参数提供到present()
以指定新视图控制器将要显示的视图控制器。如果传递的是null
(默认值),则将使用当前应用的最顶层视图控制器来推送或显示视图控制器。
present()
还有一个额外参数:wrap
。如果指定了UINavigationController
类,则新视图控制器将被这个类包裹。默认值是null
。
Navigator.push("myapp://user/123")
Navigator.present("myapp://post/54321", wrap: UINavigationController.self)
Navigator.open("myapp://alert?title=Hello&message=World")
安装
URLNavigator仅正式支持CocoaPods。
Podfile
pod 'URLNavigator'
示例
您可以在以下链接找到示例应用程序:[这里](https://github.com/devxoul/URLNavigator/tree/master/Example)。
- 构建并安装示例应用程序。
- 打开Safari应用。
- 在URL栏中输入
navigator://user/devxoul
。 - 示例应用程序将被启动。
技巧与窍门
在哪里初始化Navigator实例
-
定义为全局常量
let navigator = Navigator() class AppDelegate: UIResponder, UIApplicationDelegate { // ... }
-
注册到一个IoC容器中
container.register(NavigatorProtocol.self) { _ in Navigator() } // Swinject let navigator = container.resolve(NavigatorProtocol.self)!
-
从组合根中注入依赖。
在哪里映射URL
我更愿意使用独立的URL映射文件。
struct URLNavigationMap {
static func initialize(navigator: NavigatorProtocol) {
navigator.register("myapp://user/<int:id>") { ... }
navigator.register("myapp://post/<title>") { ... }
navigator.handle("myapp://alert") { ... }
}
}
然后在AppDelegate的application:didFinishLaunchingWithOptions:
中调用initialize()
。
@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
// Navigator
URLNavigationMap.initialize(navigator: navigator)
// Do something else...
}
}
实现 AppDelegate 启动选项 URL
如果注册了自定义方案,则可以通过 URL 打开您的应用程序。为了使用 URL 导航到视图控制器,您必须实现 application:didFinishLaunchingWithOptions:
方法。
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
// ...
if let url = launchOptions?[.url] as? URL {
if let opened = navigator.open(url)
if !opened {
navigator.present(url)
}
}
return true
}
实现 AppDelegate 打开 URL 方法
您可能想要实现自定义 URL 打开处理器。以下是一个使用 URLNavigator 和其他 URL 打开处理器的示例。
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// If you're using Facebook SDK
let fb = FBSDKApplicationDelegate.sharedInstance()
if fb.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation) {
return true
}
// URLNavigator Handler
if navigator.open(url) {
return true
}
// URLNavigator View Controller
if navigator.present(url, wrap: UINavigationController.self) != nil {
return true
}
return false
}
在 Push、Present 和打开时传递额外值
let context: [AnyHashable: Any] = [
"fromViewController": self
]
Navigator.push("myapp://user/10", context: context)
Navigator.present("myapp://user/10", context: context)
Navigator.open("myapp://alert?title=Hi", context: context)
定义自定义 URL 值转换器
您可以定义用于 URL 占位符的自定义 URL 值转换器。
例如,占位符 <region>
仅允许字符串 ["us-west-1", "ap-northeast-2", "eu-west-3"]
。如果它不包含这些字符串中的任何一个,则 URL 模式不应匹配。
将自定义值转换器添加到 [String: URLValueConverter]
字典中的您的 Navigator 实例。
navigator.matcher.valueConverters["region"] = { pathComponents, index in
let allowedRegions = ["us-west-1", "ap-northeast-2", "eu-west-3"]
if allowedRegions.contains(pathComponents[index]) {
return pathComponents[index]
} else {
return nil
}
}
例如,根据以上代码,myapp://region/<region:_>
与以下匹配:
myapp://region/us-west-1
myapp://region/ap-northeast-2
myapp://region/eu-west-3
但它不匹配以下内容:
myapp://region/ca-central-1
有关更多信息,请参阅默认 URL 值转换器的实现。
许可证
URLNavigator 采用MIT许可证。有关更多信息,请参阅许可证文件。