DeeplinkNavigator 0.3.7

DeeplinkNavigator 0.3.7

测试已测试
Lang语言 SwiftSwift
许可证 MIT
Released上次发布2017年8月
SwiftSwift版本3.1
SPM支持SPM

LawrenceHan维护。



  • LawrenceHan

感谢devxoul,该项目基于他的努力并受到启发。

DeeplinkNavigator 可以通过 2 种类型的类型使用 URL 模式进行映射:DeeplinkNavigableDeeplinkOpenHandlerDeeplinkNavigable 是一个协议,具有 2 个子协议:StoryboardNavigableInitNavigable(viewController 的默认初始化方法)。DeeplinkOpenHandler 是一个可以执行的闭包。初始化器和闭包都接收一个 URL 和占位符值。

入门指南

1. 映射 URL 模式

URL 模式可以包含占位符。占位符将被替换为从 URL 中匹配的值。使用 <> 创建占位符。占位符可以具有类型:`string`(默认)、`int`、`float` 和 `path`。

以下是将 URL 模式映射到 view controller 和闭包的示例。要使用 URL 模式进行映射,viewController 应符合 DeeplinkNavigable 协议。

Navigator.map("myapp://user/<int:id>", UserViewController.self)
Navigator.map("myapp://post/<title>", PostViewController.self)

Navigator.map("myapp://alert") { url, values in
  print(url.queryParameters["title"])
  print(url.queryParameters["message"])
  return true
}

注意:全局常量 Navigator 是 `DeeplinkNavigator.default 的快捷方式。

2. 推送、呈现和打开 URL

DeeplinkNavigator 可以使用 URL 推送并呈现 view controller,并且可以执行闭包。

push() 中提供 from 参数,以指定将推送的新 view controller 的 DeeplinkPushable。类似地,向 present() 提供 from 参数,以指定将被呈现的新 view controller 的 DeeplinkPresentable。如果传入 nil,这是默认值,则使用当前应用程序的最高级 view controller 以推送或呈现 view controller。

present() 需要一个额外的参数:`wrap`。如果指定为 `true`,则新 view controller 将被包装在 `UINavigationController` 中。默认值为 `false`。

Navigator.push("myapp://user/123")
Navigator.present("myapp://post/54321", wrap: true)

Navigator.open("myapp://alert?title=Hello&message=World")

3. 实现 DeeplinkNavigable

视图控制器应遵守协议DeeplinkNavigable以与URL进行映射。协议DeeplinkNavigable定义了2个初始化协议:StoryboardNavigableInitNavigable,其中navigation参数包含作为属性的urlvaluesmappingContextnavigationContext

属性url是从DeeplinkNavigator.push()DeeplinkNavigator.present()传递的URL。values是一个字典,包含URL占位符键和值。mappingContextmap()函数传递的上下文。navigationContext是一个包含从push()present()传递的额外值的字典。

final class StoryboardViewController: UIViewController {
}

extension StoryboardViewController: StoryboardNavigable {
    static func viewControllerFromStoryBoard(navigation: DeeplinkNavigation) -> UIViewController? {
        let sb = UIStoryboard(name: "Main", bundle: nil)
        let vc = sb.instantiateViewController(withIdentifier: String(describing: self))
        return vc
    }
}

final class XibViewController: UIViewController {
}

extension XibViewController: InitNavigable {
    convenience init?(navigation: DeeplinkNavigation) {
        self.init()
    }
}

final class InitViewController: UIViewController {
}

extension InitViewController: InitNavigable {
    convenience init?(navigation: DeeplinkNavigation) {
        self.init()
    }
}

安装

  • CocoaPods

    pod 'DeeplinkNavigator'
  • Carthage

    github "LawrenceHan/DeeplinkNavigator"
    

技巧和窍门

在哪里映射URL

我更愿意使用独立的URL映射文件。

struct NavigationMap {

  static func initialize() {
    Navigator.map("myapp://user/<int:id>", UserViewController.self)
    Navigator.map("myapp://post/<title>", PostViewController.self)

    Navigator.map("myapp://alert") { url, values in
      print(url.queryParameters["title"])
      print(url.queryParameters["message"])
      self.someUtilityMethod()
      return true
    }
  }

  private static func someUtilityMethod() {
    print("This method is really useful")
  }

}

然后在AppDelegate的application:didFinishLaunchingWithOptions:中调用initialize()

@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
  ) -> Bool {
    // Navigator
    URLNavigationMap.initialize()
    
    // Do something else...
  }
}

将UIView传递给push()present()

有时你可能有一个多窗口层次结构的情况,你可以传递一个UIView对象,并由DeeplinkNavigator为你寻找正确的UINavigationControllerUIViewController

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath)
        Navigator.push("myapp://test", from: cell, animated: true)
    }

使用pushOrPopTo扩展

你可能想要推一个viewController,但你也想如果它已经存在,就弹出该viewController。

Navigator.popTo("myapp://user")
Navigator.pushOrPopTo("myapp://user/10")

实现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.push(url)
    }
  }
  return true
}

实现AppDelegate打开URL方法

你可能想实现自定义URL打开处理器。这里是一个使用DeeplinkNavigator和其他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
  }

  // DeeplinkNavigator Handler
  if Navigator.open(url) {
    return true
  }

  // DeeplinkNavigator View Controller
  if Navigator.present(url, wrap: true) != nil {
    return true
  }

  return false
}

设置默认方案

在DeeplinkNavigator实例上设置scheme属性以从每个URL中删除方案。

Navigator.scheme = "myapp"
Navigator.map("/user/<int:id>", UserViewController.self)
Navigator.push("/user/10")

这完全等同于

Navigator.map("myapp://user/<int:id>", UserViewController.self)
Navigator.push("myapp://user/10")

设置scheme属性不会影响已经包含方案的现有其他URL。

Navigator.scheme = "myapp"
Navigator.map("/user/<int:id>", UserViewController.self) // `myapp://user/<int:id>`
Navigator.map("http://<path>", MyWebViewController.self) // `http://<path>`

在映射时传递上下文

let context = Foo()
Navigator.map("myapp://user/10", UserViewController.self, context: context)

在推送或呈现时传递额外值

let context: [AnyHashable: Any] = [
  "fromViewController": self
]
Navigator.push("myapp://user/10", context: context)
Navigator.present("myapp://user/10", context: context)

许可证

DeeplinkNavigator是在MIT许可证下。请参阅LICENSE文件以获取更多信息。