URLNavigator 2.5.1

URLNavigator 2.5.1

测试已测试
语言语言 SwiftSwift
许可 MIT
发布上次发布2023年7月
SPM支持 SPM

Suyeol JeonKanghoon Oh 维护。



  • 作者:
  • Suyeol Jeon 和 Kanghoon Oh

URLNavigator

Swift CocoaPods Build Status CodeCov

⛵️URLNavigator 提供了一种优雅的方式来通过 URL 进行视图控制器导航。可以使用 URLNavigator.register(_:_:) 函数来映射 URL 模式。

URLNavigator 可以用于使用两种类型映射 URL 模式: URLNavigableURLOpenHandlerURLNavigable 是一个定义自定义初始化器的类型,而 URLOpenHandler 是一个可以执行的闭包。初始化器和闭包都接收一个 URL 和占位符值。

开始使用

1. 理解 URL 模式

URL 模式可以包含占位符。占位符将用从 URL 中匹配的值替换。使用 <> 来创建占位符。占位符可以有类型: string(默认),intfloatpath

例如,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模式与视图控制器和闭包进行映射的示例。每个闭包有三个参数:urlvaluescontext

  • 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)。

  1. 构建并安装示例应用程序。
  2. 打开Safari应用。
  3. 在URL栏中输入 navigator://user/devxoul
  4. 示例应用程序将被启动。

技巧与窍门

在哪里初始化Navigator实例

  1. 定义为全局常量

    let navigator = Navigator()
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
      // ...
    }
  2. 注册到一个IoC容器中

    container.register(NavigatorProtocol.self) { _ in Navigator() } // Swinject
    let navigator = container.resolve(NavigatorProtocol.self)!
  3. 从组合根中注入依赖。

在哪里映射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许可证。有关更多信息,请参阅许可证文件