ReerRouter 1.0.2

ReerRouter 1.0.2

phoenix 维护。



  • phoenix

中文文档

ReerRouter

仅限 iOS 的应用程序 URL 路由器。受 URLNavigator 启发。

示例应用程序

要运行示例项目,请克隆仓库,然后首先从 Example 目录运行 pod install

需求

至少需要 iOS 10.0 Xcode 13.2

安装

CocoaPods

ReerRouter可通过CocoaPods获取。要安装它,只需将以下行添加到您的Podfile中

pod 'ReerRouter'

Swift Package Manager

import PackageDescription

let package = Package(
    name: "YOUR_PROJECT_NAME",
    targets: [],
    dependencies: [
        .package(url: "https://github.com/reers/ReerRouter.git", from: "1.0.0")
    ]
)

接下来,将ReerRouter添加到您的目标依赖项中,如下所示

.target(
    name: "YOUR_TARGET_NAME",
    dependencies: ["ReerRouter",]
),

入门

1. 了解Route.Key

Route.Key有两种模式。

模式1:Route.Key表示URL的hostpath

/// myapp://example.com/over/there?name=phoenix#nose
/// \______/\_________/\_________/ \__________/ \__/
///    |         |          |           |        |
///  scheme     host       path      queries   fragment
///              \_________/
///                   |
///               route key

模式1:为路由实例设置host,使用path作为Route.Key

/// myapp://example.com/over/there?name=phoenix#nose
/// \______/\_________/\_________/ \__________/ \__/
///    |         |          |           |        |
///  scheme     host       path      queries   fragment
///                         |
///                         |
///                    route key

2. 注册路由

模式 1

现在 Route.Key 代表的是 URL 的 hostpath 的组合。

  • 注册一个动作。
Router.shared.registerAction(with: "abc_action") { _ in
    print("action executed.")
}
  • 通过类型和路由键注册视图控制器。
extension Route.Key {
    static let userPage: Self = "user"
}
Router.shared.register(UserViewController.self, forKey: .userPage)
Router.shared.register(UserViewController.self, forKey: "user")
  • 通过类型和路由键注册视图控制器。
Router.shared.registerPageClasses(with: ["preference": PreferenceViewController.self])
  • 通过类型名和路由键注册视图控制器。
Router.shared.registerPageClasses(with: ["preference": "ReerRouter_Example.PreferenceViewController"])

模式 2

首先,你应该为路由实例设置 host

Router.shared.host = "phoenix.com"

现在 Route.Key 代表的是 URL 路径,然后所有注册方法都与 模式 1 相同。("path", "/path" 都支持。)

  • 为视图控制器实现 Routable
class UserViewController: UIViewController, Routable {
    var params: [String: Any]
    
    required init?(param: Route.Param) {
        self.params = param.allParams
        super.init(nibName: nil, bundle: nil)
    }
}   

3. 执行路径动作。

Router.shared.executeAction(byKey: "abc_action")

// Mode 1.
Router.shared.open("myapp://abc_action")

// Mode 2.
Router.shared.open("myapp://phoenix.com/abc_action")

4. 打开视图控制器。

Router.shared.present(byKey: .userPage, embedIn: UINavigationController.self, userInfo: [
    "name": "apple",
    "id": "123123"
])

// Mode 1.
Router.shared.open("myapp://user?name=phoenix")
Router.shared.push("myapp://user?name=phoenix")
Router.shared.present("myapp://user?name=phoenix")

// Mode 2.
Router.shared.open("myapp://phoenix.com/user?name=phoenix")
Router.shared.push("myapp://phoenix.com/user?name=phoenix")
Router.shared.present("myapp://phoenix.com/user?name=phoenix")

5. 关于路由的应用代理。

extension RouteManager: RouterDelegate {
    func router(_ router: Router, willOpenURL url: URL, userInfo: [String : Any]) -> URL? {
        print("will open \(url)")
        if let _ = url.absoluteString.range(of: "google") {
            return URL(string: url.absoluteString + "&extra1=234244&extra2=afsfafasd")
        } else if let _ = url.absoluteString.range(of: "bytedance"), !isUserLoggedIn() {
            print("intercepted by delegate")
            return nil
        }
        return url
    }

    func router(_ router: Router, didOpenURL url: URL, userInfo: [String : Any]) {
        print("did open \(url) success")
    }
    
    func router(_ router: Router, didFailToOpenURL url: URL, userInfo: [String : Any]) {
        print("did fail to open \(url)")
    }
    
    func router(_ router: Router, didFallbackToURL url: URL, userInfo: [String: Any]) {
        print("did fallback to \(url)")
    }
}

6. 降级方案

  • 使用route_fallback_url键作为出错时的回退链接。
Router.shared.open("myapp://unregisteredKey?route_fallback_url=myapp%3A%2F%2Fuser%3Fname%3Di_am_fallback")

7. 重定向

  • 实现redirectURLWithRouteParam(_:)方法,以将视图控制器重定向到新URL。
class PreferenceViewController: UIViewController, Routable {
    
    required init?(param: Route.Param) {
        super.init(nibName: nil, bundle: nil)
    }
    
    class func redirectURLWithRouteParam(_ param: Route.Param) -> URL? {
        if let value = param.allParams["some_key"] as? String, value == "redirect" {
            return URL(string: "myapp://new_preference")
        }
        return nil
    }
}

8. 路由的全局实例(单例)。

public let AppRouter = Router.shared
AppRouter.open("myapp://user")

9. 当将要打开和已打开时的通知。

NotificationCenter.default.addObserver(
    forName: Notification.Name.routeWillOpenURL,
    object: nil,
    queue: .main
) { notification in
    if let param = notification.userInfo?[Route.notificationUserInfoKey] as? Route.Param {
        print("notification: route will open \(param.sourceURL)")
    }
}

NotificationCenter.default.addObserver(
    forName: Notification.Name.routeDidOpenURL,
    object: nil,
    queue: .main
) { notification in
    if let param = notification.userInfo?[Route.notificationUserInfoKey] as? Route.Param {
        print("notification: route did open \(param.sourceURL)")
    }
}

10. 自定义控制过渡段。

public typealias UserTransition = (
    _ fromNavigationController: UINavigationController?,
    _ fromViewController: UIViewController?,
    _ toViewController: UIViewController
) -> Bool

public enum TransitionExecutor {
    /// Transition will be handled by router automatically.
    case router
    /// Transition will be handled by user who invoke the router `push` or `present` method.
    case user(UserTransition)
    /// Transition will be handled by user who invoke the router `push` or `present` method.
    case delegate
}

let transition: Route.UserTransition = { fromNavigationController, fromViewController, toViewController in
    toViewController.transitioningDelegate = self.animator
    toViewController.modalPresentationStyle = .currentContext
    // Use the router found view controller directly, or just handle transition by yourself.
    // fromViewController?.present(toViewController, animated: true)
    self.present(toViewController, animated: true)
    return true
}
AppRouter.present(user.urlString, transitionExecutor: .user(transition))

11. UIViewController的打开样式。

路由器打开控制器的方式所依赖的优先级如下。

`Router` instance property `preferredOpenStyle` <
  `Routable` property `preferredOpenStyle` that UIViewController implemented <
    The method you called. If you called `Router.push(...)`, the view controller will be pushed.

12. 禁止过渡动画。

  • 使用 route_no_animation 键来禁止动画。
Router.shared.open("myapp://user?name=google&route_no_animation=1")

13. 外部拦截。

在某些特殊情况下拦截一个路由,返回 false 表示拦截 URL。

Router.shared.addInterceptor(forKey: .userPage) { (_) -> Bool in
    print("intercepted user page")
    return true
}

Router.shared.addInterceptor(forKey: .userPage) { (params) -> Bool in
    print("intercepted user page")
    if let name = params.allParams["name"] as? String, name == "google" {
        print("intercepted user page success")
        return false
    }
    return true
}

作者

phoenix, [邮箱保护]

许可证

ReerRouter 受 MIT 许可证许可。有关更多信息,请参阅 LICENSE 文件。