├── Demo
├── Demo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Utils
│ │ ├── Notification.swift
│ │ └── Notificationable.swift
│ ├── Account.swift
│ ├── NoneViewController.swift
│ ├── NeedLoginViewController.swift
│ ├── Router
│ │ ├── RouterType.swift
│ │ ├── Plugins
│ │ │ ├── RouterAccountPlugin.swift
│ │ │ ├── RouterLaunchPlugin.swift
│ │ │ └── RouterSinglePlugin.swift
│ │ ├── Router.swift
│ │ └── RouterOpener.swift
│ ├── FastViewController.swift
│ ├── LiveViewController.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── LoginViewController.swift
│ ├── AppDelegate.swift
│ └── ViewController.swift
├── Podfile
├── Demo.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── Demo.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Podfile.lock
├── Podfile
├── Router.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── Router.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Podfile.lock
├── Sources
├── PrivacyInfo.xcprivacy
├── Router.h
├── Context.swift
├── Info.plist
├── Plugin.swift
├── Provider.swift
└── Protocol.swift
├── Router.podspec
├── LICENSE
├── .gitignore
├── README_CN.md
└── README.md
/Demo/Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 |
2 | platform :ios, '11.0'
3 | inhibit_all_warnings!
4 |
5 | target 'Router' do
6 | use_frameworks!
7 |
8 | pod 'URLNavigator' , '2.5.1'
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/Demo/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '12.2'
2 | inhibit_all_warnings!
3 |
4 | target 'Demo' do
5 | use_frameworks!
6 |
7 | pod 'Router', :path => "../"
8 | pod 'SnapKit' , '~>5.0.0'
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Demo/Utils/Notification.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension NotificationCenter {
4 |
5 | enum Delegate: Notificationable {
6 | enum defaultKeys: String {
7 | case launched
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Router.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Router.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demo/Demo.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Router.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/Demo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Router.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - URLNavigator (2.5.1)
3 |
4 | DEPENDENCIES:
5 | - URLNavigator (= 2.5.1)
6 |
7 | SPEC REPOS:
8 | trunk:
9 | - URLNavigator
10 |
11 | SPEC CHECKSUMS:
12 | URLNavigator: e9c0426ba6e6ac57f34d018bbf3df840797f984d
13 |
14 | PODFILE CHECKSUM: 4c39aa2b43555aca7ecdab26f2e3b36bbca6fbdf
15 |
16 | COCOAPODS: 1.15.2
17 |
--------------------------------------------------------------------------------
/Sources/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyTracking
6 |
7 | NSPrivacyAccessedAPITypes
8 |
9 | NSPrivacyTrackingDomains
10 |
11 | NSPrivacyCollectedDataTypes
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Demo/Demo/Account.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Account.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/27.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum Account {
12 |
13 | static var isLogin: Bool {
14 | return info != nil
15 | }
16 |
17 | static var info: User?
18 | }
19 |
20 | struct User {
21 | let id: Int
22 | let name: String
23 | let avatar: String
24 | /* ... */
25 | }
26 |
--------------------------------------------------------------------------------
/Demo/Demo/NoneViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NoneViewController.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class NoneViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | view.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/Router.h:
--------------------------------------------------------------------------------
1 | //
2 | // Router.h
3 | // Router
4 | //
5 | // Created by lee on 2019/4/1.
6 | // Copyright © 2019 lee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SwiftRouter.
12 | FOUNDATION_EXPORT double SwiftRouterVersionNumber;
13 |
14 | //! Project version string for SwiftRouter.
15 | FOUNDATION_EXPORT const unsigned char SwiftRouterVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Sources/Context.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Context.swift
3 | // ┌─┐ ┌───────┐ ┌───────┐
4 | // │ │ │ ┌─────┘ │ ┌─────┘
5 | // │ │ │ └─────┐ │ └─────┐
6 | // │ │ │ ┌─────┘ │ ┌─────┘
7 | // │ └─────┐│ └─────┐ │ └─────┐
8 | // └───────┘└───────┘ └───────┘
9 | //
10 | // Created by lee on 2019/4/1.
11 | // Copyright © 2019年 lee. All rights reserved.
12 | //
13 |
14 | import Foundation
15 |
16 | struct Context {
17 | let callback: (Bool) -> Void
18 |
19 | init(_ completion: @escaping (Bool) -> Void = { _ in }) {
20 | callback = completion
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Demo/Demo/NeedLoginViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NeedLoginViewController.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/27.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class NeedLoginViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | view.backgroundColor = #colorLiteral(red: 1, green: 0.3137254902, blue: 0.3137254902, alpha: 1)
17 |
18 | let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction))
19 | view.addGestureRecognizer(tap)
20 | }
21 |
22 | @objc func tapAction() {
23 | close()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Demo/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Router (1.2.0):
3 | - Router/Privacy (= 1.2.0)
4 | - URLNavigator (= 2.5.1)
5 | - Router/Privacy (1.2.0):
6 | - URLNavigator (= 2.5.1)
7 | - SnapKit (5.0.1)
8 | - URLNavigator (2.5.1)
9 |
10 | DEPENDENCIES:
11 | - Router (from `../`)
12 | - SnapKit (~> 5.0.0)
13 |
14 | SPEC REPOS:
15 | trunk:
16 | - SnapKit
17 | - URLNavigator
18 |
19 | EXTERNAL SOURCES:
20 | Router:
21 | :path: "../"
22 |
23 | SPEC CHECKSUMS:
24 | Router: 549a4a08e2a2b3090052be9f9259e43e2c80424c
25 | SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
26 | URLNavigator: e9c0426ba6e6ac57f34d018bbf3df840797f984d
27 |
28 | PODFILE CHECKSUM: d658b085fbfbd40a614dbf87b6d4bd19177d8727
29 |
30 | COCOAPODS: 1.15.2
31 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Router.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "Router"
4 | s.version = "1.2.1"
5 | s.summary = "基于URLNavigator抽象的路由组件 支持任意类型配置 插件机制"
6 |
7 | s.homepage = "https://github.com/lixiang1994/Router"
8 |
9 | s.license = { :type => "MIT", :file => "LICENSE" }
10 |
11 | s.author = { "LEE" => "18611401994@163.com" }
12 |
13 | s.platform = :ios, "11.0"
14 |
15 | s.source = { :git => "https://github.com/lixiang1994/Router.git", :tag => s.version }
16 |
17 | s.source_files = "Sources/**/*.swift"
18 |
19 | s.requires_arc = true
20 |
21 | s.frameworks = "UIKit", "Foundation"
22 |
23 | s.swift_version = "5.0"
24 |
25 | s.dependency "URLNavigator", "2.5.1"
26 |
27 |
28 | s.subspec 'Privacy' do |ss|
29 | ss.resource_bundles = {
30 | s.name => 'Sources/PrivacyInfo.xcprivacy'
31 | }
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/Sources/Plugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Plugin.swift
3 | // ┌─┐ ┌───────┐ ┌───────┐
4 | // │ │ │ ┌─────┘ │ ┌─────┘
5 | // │ │ │ └─────┐ │ └─────┐
6 | // │ │ │ ┌─────┘ │ ┌─────┘
7 | // │ └─────┐│ └─────┐ │ └─────┐
8 | // └───────┘└───────┘ └───────┘
9 | //
10 | // Created by lee on 2019/4/27.
11 | // Copyright © 2019年 lee. All rights reserved.
12 | //
13 | import Foundation
14 |
15 | open class Plugin: RouterPluginable {
16 |
17 | public init() {
18 |
19 | }
20 |
21 | open func should(open type: T) -> Bool {
22 | return true
23 | }
24 |
25 | open func prepare(open type: T, completion: @escaping (Bool) -> Void) {
26 | completion(true)
27 | }
28 |
29 | open func will(open type: T, controller: Routerable) {
30 | }
31 |
32 | open func did(open type: T, controller: Routerable) {
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Demo/Demo/Router/RouterType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterType.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import Router
12 |
13 | private let schemes = "router"
14 |
15 | enum RouterType {
16 | case open_http
17 | case open_https
18 | case open_none
19 | case open_live
20 | case open_fast
21 | case open_needlogin
22 | }
23 |
24 | extension RouterType: RouterTypeable {
25 |
26 | // 所有类型注册时使用的URL模板
27 | var pattern: String {
28 | switch self {
29 | case .open_http: return "http://"
30 | case .open_https: return "https://"
31 | case .open_none: return schemes + "://open/none"
32 | case .open_fast: return schemes + "://open/fast"
33 | case .open_live: return schemes + "://open/live"
34 | case .open_needlogin: return schemes + "://open/needlogin"
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Demo/Demo/Router/Plugins/RouterAccountPlugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterAccountPlugin.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Router
10 |
11 | class RouterAccountPlugin: Plugin {
12 |
13 | /*
14 | 在准备打开阶段 拦截需要登录的类型, 并根据登录状态处理是否需要打开登录页面
15 | 登录成功后可执行回调继续打开流程
16 | */
17 | override func prepare(open type: RouterType, completion: @escaping (Bool) -> Void) {
18 | guard type == .open_needlogin else {
19 | completion(true)
20 | return
21 | }
22 | guard !Account.isLogin else {
23 | completion(true)
24 | return
25 | }
26 | guard let root = AppDelegate.shared.window?.rootViewController else {
27 | completion(false)
28 | return
29 | }
30 | let controller = LoginViewController.init { (result) in
31 | completion(result)
32 | }
33 | root.present(controller, animated: true)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 LEE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Demo/Demo/FastViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FastViewController.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FastViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | view.backgroundColor = #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
17 |
18 | let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction))
19 | view.addGestureRecognizer(tap)
20 | }
21 |
22 | @objc func tapAction() {
23 | close()
24 | }
25 | }
26 |
27 | extension FastViewController: RouterSingleable {
28 |
29 | var single: RouterSingleType {
30 | return .fast
31 | }
32 |
33 | func close(will single: RouterSingleType, completion: @escaping (Bool) -> Void) {
34 | switch single {
35 | case .fast:
36 | completion(false)
37 |
38 | default:
39 | close {
40 | completion(true)
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Demo/Demo/Router/Router.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Router.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/12.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import Router
12 |
13 | enum Router {
14 |
15 | // 初始化Router 并传入需要的插件
16 |
17 | static let router = Provider(
18 | [RouterLaunchPlugin(),
19 | RouterAccountPlugin(),
20 | RouterSinglePlugin()]
21 | )
22 | }
23 |
24 | extension Router {
25 |
26 | /// 打开
27 | ///
28 | /// - Parameters:
29 | /// - url: url
30 | /// - context: context
31 | /// - Returns: true or false
32 | @discardableResult
33 | static func open(_ url: URLConvertible,
34 | completion: ((Bool) -> Void)? = .none) -> Bool {
35 | return router.open(url, completion: completion)
36 | }
37 |
38 | /// 获取视图控制器
39 | ///
40 | /// - Parameters:
41 | /// - url: url
42 | /// - context: context
43 | /// - Returns: 视图控制器
44 | static func viewController(_ url: URLConvertible) -> UIViewController? {
45 | return router.viewController(url)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Demo/Demo/Router/Plugins/RouterLaunchPlugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterLaunchPlugin.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Router
10 |
11 | class RouterLaunchPlugin: Plugin {
12 |
13 | private var completion: ((Bool) -> Void)?
14 |
15 | override init() {
16 | super.init()
17 |
18 | NotificationCenter.Delegate.add(
19 | .launched,
20 | observer: self,
21 | selector: #selector(launched)
22 | )
23 | }
24 |
25 | @objc private func launched() {
26 | completion?(true)
27 | completion = nil
28 | }
29 |
30 | /*
31 | 在准备打开阶段 处理启动状态
32 | 通常在APP启动后 我们需要进行一些必要的操作 例如: 加载必要的配置数据等等,
33 | 这些操作没完成之前就打开了某些页面 是非常危险的.
34 | 这里演示的就是根据启动完成状态延后打开操作, 常见的情景为 外部通过OpenURL启动APP打开某一页面.
35 | */
36 | override func prepare(open type: RouterType, completion: @escaping (Bool) -> Void) {
37 | guard !AppDelegate.shared.isLaunched else {
38 | completion(true)
39 | return
40 | }
41 | self.completion?(false)
42 | self.completion = completion
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Demo/Demo/LiveViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LiveViewController.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LiveViewController: UIViewController {
12 |
13 | var id: String = ""
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 |
18 | view.backgroundColor = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
19 |
20 | let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction))
21 | view.addGestureRecognizer(tap)
22 | }
23 |
24 | @objc func tapAction() {
25 | close()
26 | }
27 | }
28 |
29 | extension LiveViewController: RouterSingleable {
30 |
31 | var single: RouterSingleType {
32 | return .live
33 | }
34 |
35 | func close(will single: RouterSingleType, completion: @escaping (Bool) -> Void) {
36 | close {
37 | completion(true)
38 | }
39 | }
40 |
41 | func open(_ completion: @escaping () -> Void) {
42 | guard let controller = UIViewController.topMost else {
43 | return
44 | }
45 | controller.present(self, animated: true, completion: completion)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Demo/Demo/Utils/Notificationable.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol Notificationable {
4 | associatedtype defaultKeys: RawRepresentable
5 | }
6 |
7 | extension Notificationable where defaultKeys.RawValue == String {
8 |
9 | static func post(_ name: defaultKeys, object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) {
10 |
11 | NotificationCenter.default.post(
12 | name: conversion(name),
13 | object: object,
14 | userInfo: userInfo
15 | )
16 | }
17 |
18 | static func add(_ name: defaultKeys, observer: Any, selector: Selector, object: Any? = nil) {
19 | NotificationCenter.default.addObserver(
20 | observer,
21 | selector: selector,
22 | name: conversion(name),
23 | object: object
24 | )
25 | }
26 |
27 | static func add(_ name: defaultKeys,
28 | _ object: Any? = nil,
29 | queue: OperationQueue = .main,
30 | using block: @escaping (Notification) -> Void) {
31 | NotificationCenter.default.addObserver(
32 | forName: conversion(name),
33 | object: object,
34 | queue: .main,
35 | using: block
36 | )
37 | }
38 |
39 | static func remove(_ name: defaultKeys, observer: Any, object: Any? = nil) {
40 | NotificationCenter.default.removeObserver(
41 | observer,
42 | name: conversion(name),
43 | object: object
44 | )
45 | }
46 |
47 | static private func conversion(_ key: defaultKeys) -> NSNotification.Name {
48 | return NSNotification.Name("\(self).\(key.rawValue)")
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots/**/*.png
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/Demo/Demo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Demo/Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Router
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleURLTypes
22 |
23 |
24 | CFBundleTypeRole
25 | Editor
26 | CFBundleURLSchemes
27 |
28 | router
29 |
30 |
31 |
32 | CFBundleVersion
33 | 1
34 | LSRequiresIPhoneOS
35 |
36 | UILaunchStoryboardName
37 | LaunchScreen
38 | UIMainStoryboardFile
39 | Main
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 |
48 | UISupportedInterfaceOrientations~ipad
49 |
50 | UIInterfaceOrientationPortrait
51 | UIInterfaceOrientationPortraitUpsideDown
52 | UIInterfaceOrientationLandscapeLeft
53 | UIInterfaceOrientationLandscapeRight
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Demo/Demo/Router/RouterOpener.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterOpener.swift
3 | // Route
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import SafariServices
12 | import Router
13 |
14 | extension RouterType {
15 |
16 | // 根据类型或URL 返回对应的视图控制器
17 | func controller(url: URLConvertible, values: [String: Any]) -> Routerable? {
18 | switch self {
19 | case .open_http, .open_https:
20 | guard let url = url.urlValue else { return nil }
21 | return SFSafariViewController(url: url)
22 |
23 | case .open_none:
24 | return NoneViewController()
25 |
26 | case .open_live:
27 | guard let id = url.queryParameters["id"] else { return nil }
28 | let controller = LiveViewController()
29 | controller.id = id
30 | return controller
31 |
32 | case .open_fast:
33 | return FastViewController()
34 |
35 | case .open_needlogin:
36 | return NeedLoginViewController()
37 | }
38 | }
39 |
40 | // 根据类型或URL 返回对应的处理 注: 当上面方法因无需要打开的控制器返回时 才会执行.
41 | func handle(url: URLConvertible, values: [String : Any], completion: @escaping (Bool) -> Void) {
42 | completion(true)
43 | }
44 | }
45 |
46 | // 所有需要支持 Router 的视图控制器都需要实现 Routerable 协议
47 | // Routerable 协议默认实现了通用的打开关闭处理逻辑 如无法满足 可重写
48 |
49 | extension NoneViewController: Routerable { }
50 | extension NeedLoginViewController: Routerable { }
51 |
52 | extension SFSafariViewController: Routerable {
53 |
54 | public func open(_ completion: @escaping () -> Void = {}) {
55 | guard let controller = UIViewController.topMost else {
56 | return
57 | }
58 |
59 | controller.present(self, animated: true, completion: completion)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Demo/Demo/LoginViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginViewController.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/27.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SnapKit
11 |
12 | class LoginViewController: UIViewController {
13 |
14 | lazy var loginButton: UIButton = {
15 | $0.setTitle("Login", for: .normal)
16 | $0.setTitleColor(.black, for: .normal)
17 | $0.addTarget(self, action: #selector(loginAction), for: .touchUpInside)
18 | return $0
19 | } ( UIButton() )
20 |
21 | lazy var cancelButton: UIButton = {
22 | $0.setTitle("Cancel", for: .normal)
23 | $0.setTitleColor(.red, for: .normal)
24 | $0.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
25 | return $0
26 | } ( UIButton() )
27 |
28 | private var completion: ((Bool) -> Void)?
29 |
30 | init(_ completion: @escaping ((Bool) -> Void)) {
31 | self.completion = completion
32 | super.init(nibName: nil, bundle: nil)
33 | }
34 |
35 | required init?(coder aDecoder: NSCoder) {
36 | super.init(coder: aDecoder)
37 | }
38 |
39 | override func viewDidLoad() {
40 | super.viewDidLoad()
41 | setup()
42 | setupLayout()
43 | }
44 |
45 | private func setup() {
46 | view.backgroundColor = .white
47 | view.addSubview(loginButton)
48 | view.addSubview(cancelButton)
49 | }
50 |
51 | private func setupLayout() {
52 | loginButton.snp.makeConstraints { (make) in
53 | make.center.equalToSuperview()
54 | }
55 |
56 | cancelButton.snp.makeConstraints { (make) in
57 | make.centerX.equalToSuperview()
58 | make.top.equalTo(loginButton.snp.bottom).offset(40)
59 | }
60 | }
61 | }
62 |
63 | extension LoginViewController {
64 |
65 | @objc private func loginAction(_ sender: UIButton) {
66 | // 假装登录成功 存储用户信息
67 | Account.info = User(id: 1994, name: "LEE", avatar: "XXXX")
68 |
69 | dismiss(animated: true) {
70 | self.completion?(true)
71 | }
72 | }
73 |
74 | @objc private func cancelAction(_ sender: UIButton) {
75 | dismiss(animated: true) {
76 | self.completion?(false)
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Demo/Demo/Router/Plugins/RouterSinglePlugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterSinglePlugin.swift
3 | // Route
4 | //
5 | // Created by 李响 on 2019/4/10.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import Router
10 |
11 | protocol RouterSingleable: Routerable {
12 |
13 | /// 当前类型
14 | var single: RouterSingleType { get }
15 |
16 | /// 关闭
17 | ///
18 | /// - Parameters:
19 | /// - single: 即将准备打开的类型
20 | /// - completion: 关闭完成回调
21 | func close(will single: RouterSingleType, completion: @escaping (Bool) -> Void)
22 | }
23 |
24 | class RouterSinglePlugin: Plugin {
25 |
26 | /*
27 | 在准备打开阶段 拦截单一特性页面
28 | (在一些业务场景中 最多只能有一个打开, 不能同时打开的页面的这种特性 简称单一特性)
29 |
30 | 判断当前要打开的类型是否为单一特性类型.
31 | 判断当前是否有相同单一特性的页面已经打开.
32 | 告知原来已经打开的页面即将要打开一个新的页面 请求关闭处理.
33 | */
34 | override func prepare(open type: RouterType, completion: @escaping (Bool) -> Void) {
35 | guard let single = make(type) else {
36 | completion(true)
37 | return
38 | }
39 | guard let current = current?.object else {
40 | completion(true)
41 | return
42 | }
43 | current.close(will: single, completion: completion)
44 | }
45 |
46 | /*
47 | 在即将打开的方法中记录新的单一特性页面, 以供下一次打开时进行操作
48 | */
49 | override func will(open type: RouterType, controller: Routerable) {
50 | guard let controller = controller as? Singleable else {
51 | return
52 | }
53 | current = WeakWrapper(controller)
54 | }
55 | }
56 |
57 | extension RouterSinglePlugin {
58 |
59 | typealias Singleable = RouterSingleable
60 | private static var currentWrapper: WeakWrapper?
61 |
62 | private var current: WeakWrapper? {
63 | get { return RouterSinglePlugin.currentWrapper }
64 | set { RouterSinglePlugin.currentWrapper = newValue }
65 | }
66 |
67 | private class WeakWrapper {
68 | weak var object: Singleable?
69 | init(_ object: Singleable?) {
70 | self.object = object
71 | }
72 | }
73 | }
74 |
75 | extension RouterSinglePlugin {
76 |
77 | func make(_ url: RouterType) -> RouterSingleType? {
78 | switch url {
79 | case .open_live: return .live
80 | case .open_fast: return .fast
81 | default: return nil
82 | }
83 | }
84 | }
85 |
86 | enum RouterSingleType {
87 | case live
88 | case fast
89 | }
90 |
--------------------------------------------------------------------------------
/Demo/Demo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/12.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Router
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | static var shared: AppDelegate {
16 | return UIApplication.shared.delegate as! AppDelegate
17 | }
18 |
19 | var window: UIWindow?
20 | var isLaunched: Bool = false
21 |
22 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
23 |
24 | DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
25 | self.isLaunched = true
26 | NotificationCenter.Delegate.post(.launched)
27 | }
28 |
29 | return true
30 | }
31 |
32 | func applicationWillResignActive(_ application: UIApplication) {
33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
35 | }
36 |
37 | func applicationDidEnterBackground(_ application: UIApplication) {
38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
40 | }
41 |
42 | func applicationWillEnterForeground(_ application: UIApplication) {
43 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
44 | }
45 |
46 | func applicationDidBecomeActive(_ application: UIApplication) {
47 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
48 | }
49 |
50 | func applicationWillTerminate(_ application: UIApplication) {
51 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
52 | }
53 |
54 |
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/Demo/Demo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Demo
4 | //
5 | // Created by 李响 on 2019/4/12.
6 | // Copyright © 2019 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | @IBOutlet weak var tableView: UITableView!
14 |
15 | private var list: [String] = [
16 | "打开http/https链接",
17 | "打开一个普通的页面",
18 | "打开一个需要登录的页面",
19 | "打开一个单一特性的页面 4s后打开另一个",
20 | "打开一个单一特性的页面 4s后打开新页面"
21 | ]
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 |
26 | setup()
27 | }
28 |
29 | private func setup() {
30 | tableView.delegate = self
31 | tableView.dataSource = self
32 | }
33 | }
34 |
35 | extension ViewController: UITableViewDelegate {
36 |
37 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
38 | return 50
39 | }
40 | }
41 |
42 | extension ViewController: UITableViewDataSource {
43 |
44 | func numberOfSections(in tableView: UITableView) -> Int {
45 | return 1
46 | }
47 |
48 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
49 | return list.count
50 | }
51 |
52 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
53 | let cell = tableView.dequeueReusableCell(
54 | withIdentifier: "cell",
55 | for: indexPath
56 | )
57 | cell.textLabel?.text = list[indexPath.row]
58 | return cell
59 | }
60 |
61 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
62 | tableView.deselectRow(at: indexPath, animated: true)
63 |
64 | switch indexPath.row {
65 | case 0: // 打开http/https链接
66 | Router.open("https://www.baidu.com")
67 |
68 | case 1: // 打开一个普通的页面
69 | Router.open("router://open/none")
70 |
71 | case 2: // 打开一个需要登录的页面
72 | Router.open("router://open/needlogin")
73 |
74 | case 3: // 打开一个单一特性的页面
75 | /*
76 | LiveViewController 和 FastViewController 在业务场景中为单一特性 (最多只能有一个打开, 不能同时打开 简称单一特性)
77 | 这里模拟 LiveViewController 打开后 因某种原因要打开 FastViewController
78 | 演示的逻辑为 关闭 LiveViewController 后再打开 FastViewController
79 | */
80 | Router.open("router://open/live?id=1")
81 |
82 | DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
83 | Router.open("router://open/fast")
84 | }
85 |
86 | case 4:
87 | /*
88 | LiveViewController 在业务场景中为单一特性 (最多只能有一个打开, 不能同时打开 简称单一特性)
89 | 这里模拟 LiveViewController 打开后 因某种原因要打开另一个 LiveViewController
90 | (比如点击某个推送通知 触发了打开一个新的 LiveViewController)
91 | 演示的逻辑为 关闭 LiveViewController 后再打开新的 LiveViewController
92 | */
93 | Router.open("router://open/live?id=1")
94 |
95 | DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
96 | Router.open("router://open/live?id=1")
97 | }
98 |
99 | default:
100 | break
101 | }
102 | }
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | # Router
2 |
3 | 
4 |
5 | [URLNavigator](https://github.com/devxoul/URLNavigator) 抽象路由组件
6 |
7 | ## 2.0版本移至 [Apis](https://github.com/lixiang1994/Apis)
8 |
9 | ## Features
10 |
11 | - [x] 支持基于插件机制的不同处理 如登录拦截等.
12 | - [x] 配置独立且易于管理.
13 | - [x] 良好的业务可扩展性.
14 | - [x] 安全的页面管理.
15 | - [x] 支持异步完成结果回调.
16 |
17 |
18 | ## 安装
19 |
20 | Router 仅支持CocoaPods.
21 |
22 | **CocoaPods - Podfile**
23 |
24 | ```ruby
25 | source 'https://github.com/lixiang1994/Specs'
26 |
27 | pod 'Router'
28 | ```
29 |
30 | ## 使用
31 |
32 | 首先导入framework:
33 |
34 | ```swift
35 | import Router
36 | ```
37 |
38 | 下面是一些简单示例. 支持所有设备和模拟器:
39 |
40 | ### 创建 router
41 |
42 | ```swift
43 | let router = Provider(
44 | [RouterXXXXXXPlugin(),
45 | RouterXXXXXXPlugin(),
46 | RouterXXXXXXPlugin()]
47 | )
48 | ```
49 |
50 | ### RouterType
51 |
52 | ```swift
53 | // 可以通过枚举声明所有类型
54 | enum RouterType: RouterTypeable {
55 | case open_http
56 | case open_https
57 | case open_xxxx
58 | /* ... */
59 | }
60 |
61 | extension RouterType {
62 |
63 | var pattern: String {
64 | switch self {
65 | case .open_http: return "http://"
66 | case .open_https: return "https://"
67 | case .open_xxxx: return "xxxx://open/xxxx"
68 | /* ... */
69 | }
70 | }
71 |
72 | // 视图控制器获取 当路由打开某一URL, 会在这个方法内获取对应的视图控制器
73 | func controller(url: URLConvertible, values: [String: Any]) -> Routerable? {
74 | switch self {
75 | case .open_http, .open_https:
76 | guard let url = url.urlValue else { return nil }
77 | return SFSafariViewController(url: url)
78 |
79 | case .open_xxxx:
80 | return XXXXViewController()
81 | /* ... */
82 | }
83 | }
84 |
85 | // 打开处理 当路由打开某一URL 例如非打开页面类型业务时 上面的方法可以返回空, 则会执行下面方法处理相关的业务
86 | func handle(url: URLConvertible, values: [String : Any], completion: @escaping (Bool) -> Void) {
87 | /* ... */
88 | completion(true)
89 | }
90 | }
91 |
92 | // 每个支持路由的视图控制器需要实现 Routerable 协议
93 | extension XXXXViewController: Routerable { }
94 | extension SFSafariViewController: Routerable { }
95 | ```
96 |
97 | ### 自定义插件
98 |
99 | ```swift
100 | // 继承自 Plugin , 重写需要的方法 你可以在整个打开过程中做一切你想做的事情
101 | class RouterXXXXPlugin: Plugin {
102 |
103 | // 能否打开
104 | override func should(open type: RouterType) -> Bool {
105 | /* ... */
106 | return true
107 | }
108 |
109 | // 准备打开时
110 | override func prepare(open type: RouterType, completion: @escaping (Bool) -> Void) {
111 | /* ... */
112 | completion(true)
113 | }
114 |
115 | // 即将打开
116 | override func will(open type: RouterType, controller: Routerable) {
117 | /* ... */
118 | }
119 |
120 | // 已经打开
121 | override func did(open type: RouterType, controller: Routerable) {
122 | /* ... */
123 | }
124 | }
125 | ```
126 |
127 | ### 打开
128 |
129 | ```swift
130 | // 根据类型打开页面
131 | router.open(.open_xxxx)
132 |
133 | // 根据URL打开页面
134 | router.open("http://xxxxxxxx")
135 |
136 | // 打开结果回调 打开过程中可能由于各种原因导致打开失败 例如: 这个页面需要登录 但是当前没有登录之类的
137 | router.open("http://xxxxxxxx") { (result) in
138 | // 成功或失败
139 | }
140 | ```
141 |
142 | ## 贡献
143 |
144 | 如果你需要实现特定功能或遇到错误,请打开issue。 如果你自己扩展了Router的功能并希望其他人也使用它,请提交拉取请求。
145 |
146 |
147 | ## 协议
148 |
149 | Router 使用 MIT 协议. 有关更多信息,请参阅 [LICENSE](LICENSE) 文件.
150 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Router
2 |
3 | 
4 |
5 | [URLNavigator](https://github.com/devxoul/URLNavigator) abstract routing component written in Swift
6 |
7 | ## Version 2.0 -> [Apis](https://github.com/lixiang1994/Apis)
8 |
9 | ## [天朝子民](README_CN.md)
10 |
11 | ## Features
12 |
13 | - [x] Support for different processing based on plugin mechanism.
14 | - [x] Configuration is independent and easy to manage.
15 | - [x] Good business scalability.
16 | - [x] Safer page management.
17 | - [x] Support for asynchronous completion of callbacks.
18 |
19 |
20 | ## Installation
21 |
22 | Router officially supports CocoaPods only.
23 |
24 | **CocoaPods - Podfile**
25 |
26 | ```ruby
27 | source 'https://github.com/lixiang1994/Specs'
28 |
29 | pod 'Router'
30 | ```
31 |
32 | ## Usage
33 |
34 | First make sure to import the framework:
35 |
36 | ```swift
37 | import Router
38 | ```
39 |
40 | Here are some usage examples. All devices are also available as simulators:
41 |
42 | ### Create router
43 |
44 | ```swift
45 | let router = Provider(
46 | [RouterXXXXXXPlugin(),
47 | RouterXXXXXXPlugin(),
48 | RouterXXXXXXPlugin()]
49 | )
50 | ```
51 |
52 | ### RouterType
53 |
54 | ```swift
55 | enum RouterType: RouterTypeable {
56 | case open_http
57 | case open_https
58 | case open_xxxx
59 | /* ... */
60 | }
61 |
62 | extension RouterType {
63 |
64 | var pattern: String {
65 | switch self {
66 | case .open_http: return "http://"
67 | case .open_https: return "https://"
68 | case .open_xxxx: return "xxxx://open/xxxx"
69 | /* ... */
70 | }
71 | }
72 |
73 | func controller(url: URLConvertible, values: [String: Any]) -> Routerable? {
74 | switch self {
75 | case .open_http, .open_https:
76 | guard let url = url.urlValue else { return nil }
77 | return SFSafariViewController(url: url)
78 |
79 | case .open_xxxx:
80 | return XXXXViewController()
81 | /* ... */
82 | }
83 | }
84 |
85 | func handle(url: URLConvertible, values: [String : Any], completion: @escaping (Bool) -> Void) {
86 | /* ... */
87 | completion(true)
88 | }
89 | }
90 |
91 |
92 | extension XXXXViewController: Routerable { }
93 | extension SFSafariViewController: Routerable { }
94 | ```
95 |
96 | ### Custom plugins
97 |
98 | ```swift
99 | class RouterXXXXPlugin: Plugin {
100 |
101 | override func should(open type: RouterType) -> Bool {
102 | /* ... */
103 | return true
104 | }
105 |
106 | override func prepare(open type: RouterType, completion: @escaping (Bool) -> Void) {
107 | /* ... */
108 | completion(true)
109 | }
110 |
111 | override func will(open type: RouterType, controller: Routerable) {
112 | /* ... */
113 | }
114 |
115 | override func did(open type: RouterType, controller: Routerable) {
116 | /* ... */
117 | }
118 | }
119 | ```
120 |
121 | ### Open
122 |
123 | ```swift
124 | // Open page based on type
125 | router.open(.open_xxxx)
126 |
127 | // Open page based on url
128 | router.open("http://xxxxxxxx")
129 |
130 | // Result callback
131 | router.open("http://xxxxxxxx") { (result) in
132 | // Success or failure
133 | }
134 |
135 | ```
136 |
137 | ## Contributing
138 |
139 | If you have the need for a specific feature that you want implemented or if you experienced a bug, please open an issue.
140 | If you extended the functionality of Router yourself and want others to use it too, please submit a pull request.
141 |
142 |
143 | ## License
144 |
145 | Router is under MIT license. See the [LICENSE](LICENSE) file for more info.
146 |
--------------------------------------------------------------------------------
/Sources/Provider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Provider.swift
3 | // ┌─┐ ┌───────┐ ┌───────┐
4 | // │ │ │ ┌─────┘ │ ┌─────┘
5 | // │ │ │ └─────┐ │ └─────┐
6 | // │ │ │ ┌─────┘ │ ┌─────┘
7 | // │ └─────┐│ └─────┐ │ └─────┐
8 | // └───────┘└───────┘ └───────┘
9 | //
10 | // Created by lee on 2019/4/1.
11 | // Copyright © 2019年 lee. All rights reserved.
12 | //
13 |
14 | import Foundation
15 | import UIKit
16 | import URLNavigator
17 |
18 | public typealias URLConvertible = URLNavigator.URLConvertible
19 |
20 | public class Provider {
21 |
22 | typealias ViewControllerFactory = (_ url: URLConvertible, _ values: [String: Any], _ context: Any?) -> Routerable?
23 |
24 | private let navigator: Navigator
25 | private let plugins: [Plugin]
26 |
27 | public init(navigator: Navigator = Navigator(), _ plugins: [Plugin]) {
28 | self.navigator = navigator
29 | self.plugins = plugins
30 |
31 | // 注册处理
32 | T.allCases.forEach { registers($0) }
33 | }
34 | }
35 |
36 | extension Provider {
37 |
38 | /// 打开
39 | ///
40 | /// - Parameters:
41 | /// - url: url
42 | /// - completion: 打开完成回调
43 | /// - Returns: true or false
44 | @discardableResult
45 | public func open(_ url: URLConvertible,
46 | completion: ((Bool) -> Void)? = .none) -> Bool {
47 | return navigator.open(url, context: Context(completion ?? { _ in }))
48 | }
49 |
50 | /// 获取视图控制器
51 | ///
52 | /// - Parameters:
53 | /// - url: url
54 | /// - context: context
55 | /// - Returns: 视图控制器
56 | public func viewController(_ url: URLConvertible, _ context: Any? = nil) -> Routerable? {
57 | return navigator.viewController(for: url, context: context) as? Routerable
58 | }
59 | }
60 |
61 | extension Provider {
62 |
63 | private func handle(_ url: T, _ factory: @escaping URLOpenHandlerFactory) {
64 | navigator.handle(url.pattern) { (url, values, context) -> Bool in
65 | return factory(url, values, context)
66 | }
67 | }
68 |
69 | private func register(_ url: T, _ factory: @escaping ViewControllerFactory) {
70 | navigator.register(url.pattern) { (url, values, context) -> UIViewController? in
71 | return factory(url, values, context)
72 | }
73 | }
74 | }
75 |
76 | extension Provider {
77 |
78 | private func registers(_ type: T) {
79 | self.register(type) { (url, values, context) -> Routerable? in
80 | return type.controller(url: url, values: values)
81 | }
82 | self.handle(type) { [weak self] (url, values, context) -> Bool in
83 | guard let self = self else { return false }
84 | let context = context as? Context
85 |
86 | if self.plugins.isEmpty {
87 | if let controller = self.viewController(url, context) {
88 | controller.open {
89 | context?.callback(true)
90 | }
91 |
92 | } else {
93 | type.handle(url: url, values: values) { (result) in
94 | context?.callback(result)
95 | }
96 | }
97 |
98 | } else {
99 | guard self.plugins.contains(where: { $0.should(open: type) }) else {
100 | return false
101 | }
102 |
103 | var result = true
104 | let total = self.plugins.count
105 | var count = 0
106 | let group = DispatchGroup()
107 | self.plugins.forEach { p in
108 | group.enter()
109 | p.prepare(open: type) {
110 | // 防止插件多次回调
111 | defer { count += 1 }
112 | guard count < total else { return }
113 |
114 | result = $0 ? result : false
115 | group.leave()
116 | }
117 | }
118 |
119 | group.notify(queue: .main) { [weak self] in
120 | guard let self = self else {
121 | context?.callback(false)
122 | return
123 | }
124 | guard result else {
125 | context?.callback(false)
126 | return
127 | }
128 |
129 | if let controller = self.viewController(url, context) {
130 | self.plugins.forEach {
131 | $0.will(open: type, controller: controller)
132 | }
133 |
134 | controller.open { [weak self] in
135 | guard let self = self else { return }
136 | self.plugins.forEach {
137 | $0.did(open: type, controller: controller)
138 | }
139 | context?.callback(true)
140 | }
141 |
142 | } else {
143 | type.handle(url: url, values: values) { (result) in
144 | context?.callback(result)
145 | }
146 | }
147 | }
148 | }
149 | return true
150 | }
151 | }
152 | }
153 |
154 |
--------------------------------------------------------------------------------
/Sources/Protocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Protocol.swift
3 | // ┌─┐ ┌───────┐ ┌───────┐
4 | // │ │ │ ┌─────┘ │ ┌─────┘
5 | // │ │ │ └─────┐ │ └─────┐
6 | // │ │ │ ┌─────┘ │ ┌─────┘
7 | // │ └─────┐│ └─────┐ │ └─────┐
8 | // └───────┘└───────┘ └───────┘
9 | //
10 | // Created by lee on 2019/4/1.
11 | // Copyright © 2019年 lee. All rights reserved.
12 | //
13 |
14 | import Foundation
15 | import UIKit
16 |
17 | public protocol RouterPluginable {
18 |
19 | associatedtype T
20 |
21 | /// 是否可以打开
22 | ///
23 | /// - Parameter url: 类型
24 | /// - Returns: true or false
25 | func should(open type: T) -> Bool
26 |
27 | /// 准备打开
28 | ///
29 | /// - Parameters:
30 | /// - url: 类型
31 | /// - completion: 准备完成回调 (无论结果如何必须回调)
32 | func prepare(open type: T, completion: @escaping (Bool) -> Void)
33 |
34 | /// 即将打开
35 | ///
36 | /// - Parameters:
37 | /// - type: 类型
38 | /// - controller: 视图控制器
39 | func will(open type: T, controller: Routerable)
40 |
41 | /// 已经打开
42 | ///
43 | /// - Parameters:
44 | /// - type: 类型
45 | /// - controller: 视图控制器
46 | func did(open type: T, controller: Routerable)
47 | }
48 |
49 | public protocol RouterTypeable: CaseIterable {
50 |
51 | /// 模板 用于注册 例如: xxx://open/
52 | var pattern: String { get }
53 |
54 | /// 打开控制器
55 | ///
56 | /// - Parameters:
57 | /// - url: url
58 | /// - values: 参数值
59 | /// - Returns: 实现了 Routerable 协议的视图控制器 如果返回为空则会调用下面打开处理方法
60 | func controller(url: URLConvertible, values: [String: Any]) -> Routerable?
61 |
62 | /// 打开处理 (当无控制器时执行)
63 | ///
64 | /// - Parameters:
65 | /// - url: url
66 | /// - values: 参数值
67 | /// - completion: 处理完成结果回调 *必须调用
68 | func handle(url: URLConvertible, values: [String: Any], completion: @escaping (Bool) -> Void)
69 | }
70 |
71 | public protocol Routerable: UIViewController {
72 |
73 | /// 打开
74 | ///
75 | /// - Parameter completion: 打开完成回调
76 | func open(with completion: @escaping () -> Void)
77 |
78 | /// 关闭
79 | ///
80 | /// - Parameters:
81 | /// - completion: 关闭完成回调
82 | func close(with completion: @escaping () -> Void)
83 | }
84 |
85 | public extension URL {
86 |
87 | func appending(_ params: [String: String]) -> String {
88 | return absoluteString.appending(params)
89 | }
90 | }
91 |
92 | public extension String {
93 |
94 | func appending(_ params: [String: String]) -> String {
95 | return appending(self, params)
96 | }
97 |
98 | func appending(_ url: String, _ params: [String: String]) -> String {
99 | guard var components = URLComponents(string: url) else {
100 | return url
101 | }
102 |
103 | let query = components.percentEncodedQuery ?? ""
104 | let temp = params.compactMap({
105 | guard !$0.isEmpty, !$1.isEmpty else { return nil }
106 | guard let _ = Foundation.URL(string: $1) else {
107 | let encoded = $1.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? $1
108 | return "\($0)=\(encoded)"
109 | }
110 |
111 | let string = "?!@#$^&%*+,:;='\"`<>()[]{}/\\| "
112 | let character = CharacterSet(charactersIn: string).inverted
113 | let encoded = $1.addingPercentEncoding(withAllowedCharacters: character) ?? $1
114 | return "\($0)=\(encoded)"
115 | }).joined(separator: "&")
116 | components.percentEncodedQuery = query.isEmpty ? temp : query + "&" + temp
117 | return components.url?.absoluteString ?? url
118 | }
119 | }
120 |
121 | extension Routerable {
122 |
123 | public func open(with completion: @escaping () -> Void = {}) {
124 | guard let controller = UIViewController.topMost else {
125 | return
126 | }
127 |
128 | if let navigation = controller as? UINavigationController {
129 | CATransaction.begin()
130 | CATransaction.setCompletionBlock(completion)
131 | navigation.pushViewController(self, animated: true)
132 | CATransaction.commit()
133 |
134 | } else if let navigation = controller.navigationController {
135 | CATransaction.begin()
136 | CATransaction.setCompletionBlock(completion)
137 | navigation.pushViewController(self, animated: true)
138 | CATransaction.commit()
139 |
140 | } else {
141 | let navigation = UINavigationController(rootViewController: self)
142 | controller.present(navigation, animated: true, completion: completion)
143 | }
144 | }
145 |
146 | public func close(with completion: @escaping () -> Void = {}) {
147 | guard
148 | let navigation = navigationController,
149 | navigation.viewControllers.first != self else {
150 | let presenting = presentingViewController ?? self
151 | presenting.dismiss(animated: true, completion: completion)
152 | return
153 | }
154 | guard presentedViewController == nil else {
155 | dismiss(animated: true) { [weak self] in self?.close(with: completion) }
156 | return
157 | }
158 |
159 | func parents(_ controller: UIViewController) -> [UIViewController] {
160 | guard let parent = controller.parent else {
161 | return [controller]
162 | }
163 | return [controller] + parents(parent)
164 | }
165 |
166 | CATransaction.begin()
167 | CATransaction.setCompletionBlock(completion)
168 | if let top = navigation.topViewController, parents(self).contains(top) {
169 | navigation.popViewController(animated: true)
170 |
171 | } else {
172 | let temp = navigation.viewControllers.filter { !parents(self).contains($0) }
173 | navigation.setViewControllers(temp, animated: true)
174 | }
175 | CATransaction.commit()
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/Demo/Demo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/Router.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4A0C4CA6D15A356505695BCF /* Pods_Router.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 433DDBBFBEDCE5F52EB5DA5E /* Pods_Router.framework */; };
11 | C9170B7D2274337000052A4E /* Plugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9170B7C2274337000052A4E /* Plugin.swift */; };
12 | C9D0289522607AD100B5E061 /* Router.h in Headers */ = {isa = PBXBuildFile; fileRef = C9D0289322607AD100B5E061 /* Router.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | C9D0289C22607C9300B5E061 /* Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0289B22607C9300B5E061 /* Provider.swift */; };
14 | C9D0289E22607D3F00B5E061 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0289D22607D3F00B5E061 /* Context.swift */; };
15 | C9D028A022607DB100B5E061 /* Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0289F22607DB100B5E061 /* Protocol.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 1914FB7D28826DD9E48B39CC /* Pods-Router.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Router.release.xcconfig"; path = "Target Support Files/Pods-Router/Pods-Router.release.xcconfig"; sourceTree = ""; };
20 | 21744AB499310C2ECAEBB625 /* Pods-Router.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Router.debug.xcconfig"; path = "Target Support Files/Pods-Router/Pods-Router.debug.xcconfig"; sourceTree = ""; };
21 | 433DDBBFBEDCE5F52EB5DA5E /* Pods_Router.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Router.framework; sourceTree = BUILT_PRODUCTS_DIR; };
22 | C9170B7C2274337000052A4E /* Plugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Plugin.swift; sourceTree = ""; };
23 | C9D0289022607AD100B5E061 /* Router.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Router.framework; sourceTree = BUILT_PRODUCTS_DIR; };
24 | C9D0289322607AD100B5E061 /* Router.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Router.h; sourceTree = ""; };
25 | C9D0289422607AD100B5E061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | C9D0289B22607C9300B5E061 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = ""; };
27 | C9D0289D22607D3F00B5E061 /* Context.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = ""; };
28 | C9D0289F22607DB100B5E061 /* Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Protocol.swift; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | C9D0288D22607AD100B5E061 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | 4A0C4CA6D15A356505695BCF /* Pods_Router.framework in Frameworks */,
37 | );
38 | runOnlyForDeploymentPostprocessing = 0;
39 | };
40 | /* End PBXFrameworksBuildPhase section */
41 |
42 | /* Begin PBXGroup section */
43 | 16AF8AD01863515273703E24 /* Pods */ = {
44 | isa = PBXGroup;
45 | children = (
46 | 21744AB499310C2ECAEBB625 /* Pods-Router.debug.xcconfig */,
47 | 1914FB7D28826DD9E48B39CC /* Pods-Router.release.xcconfig */,
48 | );
49 | path = Pods;
50 | sourceTree = "";
51 | };
52 | 335179C6A7819FE55E984E38 /* Frameworks */ = {
53 | isa = PBXGroup;
54 | children = (
55 | 433DDBBFBEDCE5F52EB5DA5E /* Pods_Router.framework */,
56 | );
57 | name = Frameworks;
58 | sourceTree = "";
59 | };
60 | C9D0288622607AD100B5E061 = {
61 | isa = PBXGroup;
62 | children = (
63 | C9D0289222607AD100B5E061 /* Sources */,
64 | C9D0289122607AD100B5E061 /* Products */,
65 | 16AF8AD01863515273703E24 /* Pods */,
66 | 335179C6A7819FE55E984E38 /* Frameworks */,
67 | );
68 | sourceTree = "";
69 | };
70 | C9D0289122607AD100B5E061 /* Products */ = {
71 | isa = PBXGroup;
72 | children = (
73 | C9D0289022607AD100B5E061 /* Router.framework */,
74 | );
75 | name = Products;
76 | sourceTree = "";
77 | };
78 | C9D0289222607AD100B5E061 /* Sources */ = {
79 | isa = PBXGroup;
80 | children = (
81 | C9D0289322607AD100B5E061 /* Router.h */,
82 | C9D0289422607AD100B5E061 /* Info.plist */,
83 | C9D0289B22607C9300B5E061 /* Provider.swift */,
84 | C9D0289D22607D3F00B5E061 /* Context.swift */,
85 | C9D0289F22607DB100B5E061 /* Protocol.swift */,
86 | C9170B7C2274337000052A4E /* Plugin.swift */,
87 | );
88 | path = Sources;
89 | sourceTree = "";
90 | };
91 | /* End PBXGroup section */
92 |
93 | /* Begin PBXHeadersBuildPhase section */
94 | C9D0288B22607AD100B5E061 /* Headers */ = {
95 | isa = PBXHeadersBuildPhase;
96 | buildActionMask = 2147483647;
97 | files = (
98 | C9D0289522607AD100B5E061 /* Router.h in Headers */,
99 | );
100 | runOnlyForDeploymentPostprocessing = 0;
101 | };
102 | /* End PBXHeadersBuildPhase section */
103 |
104 | /* Begin PBXNativeTarget section */
105 | C9D0288F22607AD100B5E061 /* Router */ = {
106 | isa = PBXNativeTarget;
107 | buildConfigurationList = C9D0289822607AD100B5E061 /* Build configuration list for PBXNativeTarget "Router" */;
108 | buildPhases = (
109 | AB82C90F7CD49468A07CA3C8 /* [CP] Check Pods Manifest.lock */,
110 | C9D0288B22607AD100B5E061 /* Headers */,
111 | C9D0288C22607AD100B5E061 /* Sources */,
112 | C9D0288D22607AD100B5E061 /* Frameworks */,
113 | C9D0288E22607AD100B5E061 /* Resources */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Router;
120 | productName = SwiftRouter;
121 | productReference = C9D0289022607AD100B5E061 /* Router.framework */;
122 | productType = "com.apple.product-type.framework";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | C9D0288722607AD100B5E061 /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1020;
131 | ORGANIZATIONNAME = swift;
132 | TargetAttributes = {
133 | C9D0288F22607AD100B5E061 = {
134 | CreatedOnToolsVersion = 10.2;
135 | LastSwiftMigration = 1020;
136 | };
137 | };
138 | };
139 | buildConfigurationList = C9D0288A22607AD100B5E061 /* Build configuration list for PBXProject "Router" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | );
146 | mainGroup = C9D0288622607AD100B5E061;
147 | productRefGroup = C9D0289122607AD100B5E061 /* Products */;
148 | projectDirPath = "";
149 | projectRoot = "";
150 | targets = (
151 | C9D0288F22607AD100B5E061 /* Router */,
152 | );
153 | };
154 | /* End PBXProject section */
155 |
156 | /* Begin PBXResourcesBuildPhase section */
157 | C9D0288E22607AD100B5E061 /* Resources */ = {
158 | isa = PBXResourcesBuildPhase;
159 | buildActionMask = 2147483647;
160 | files = (
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | };
164 | /* End PBXResourcesBuildPhase section */
165 |
166 | /* Begin PBXShellScriptBuildPhase section */
167 | AB82C90F7CD49468A07CA3C8 /* [CP] Check Pods Manifest.lock */ = {
168 | isa = PBXShellScriptBuildPhase;
169 | buildActionMask = 2147483647;
170 | files = (
171 | );
172 | inputFileListPaths = (
173 | );
174 | inputPaths = (
175 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
176 | "${PODS_ROOT}/Manifest.lock",
177 | );
178 | name = "[CP] Check Pods Manifest.lock";
179 | outputFileListPaths = (
180 | );
181 | outputPaths = (
182 | "$(DERIVED_FILE_DIR)/Pods-Router-checkManifestLockResult.txt",
183 | );
184 | runOnlyForDeploymentPostprocessing = 0;
185 | shellPath = /bin/sh;
186 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
187 | showEnvVarsInLog = 0;
188 | };
189 | /* End PBXShellScriptBuildPhase section */
190 |
191 | /* Begin PBXSourcesBuildPhase section */
192 | C9D0288C22607AD100B5E061 /* Sources */ = {
193 | isa = PBXSourcesBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | C9170B7D2274337000052A4E /* Plugin.swift in Sources */,
197 | C9D0289C22607C9300B5E061 /* Provider.swift in Sources */,
198 | C9D0289E22607D3F00B5E061 /* Context.swift in Sources */,
199 | C9D028A022607DB100B5E061 /* Protocol.swift in Sources */,
200 | );
201 | runOnlyForDeploymentPostprocessing = 0;
202 | };
203 | /* End PBXSourcesBuildPhase section */
204 |
205 | /* Begin XCBuildConfiguration section */
206 | C9D0289622607AD100B5E061 /* Debug */ = {
207 | isa = XCBuildConfiguration;
208 | buildSettings = {
209 | ALWAYS_SEARCH_USER_PATHS = NO;
210 | CLANG_ANALYZER_NONNULL = YES;
211 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
212 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
213 | CLANG_CXX_LIBRARY = "libc++";
214 | CLANG_ENABLE_MODULES = YES;
215 | CLANG_ENABLE_OBJC_ARC = YES;
216 | CLANG_ENABLE_OBJC_WEAK = YES;
217 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
218 | CLANG_WARN_BOOL_CONVERSION = YES;
219 | CLANG_WARN_COMMA = YES;
220 | CLANG_WARN_CONSTANT_CONVERSION = YES;
221 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
223 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
224 | CLANG_WARN_EMPTY_BODY = YES;
225 | CLANG_WARN_ENUM_CONVERSION = YES;
226 | CLANG_WARN_INFINITE_RECURSION = YES;
227 | CLANG_WARN_INT_CONVERSION = YES;
228 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
229 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
230 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
232 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
233 | CLANG_WARN_STRICT_PROTOTYPES = YES;
234 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
235 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
236 | CLANG_WARN_UNREACHABLE_CODE = YES;
237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
238 | CODE_SIGN_IDENTITY = "iPhone Developer";
239 | COPY_PHASE_STRIP = NO;
240 | CURRENT_PROJECT_VERSION = 1;
241 | DEBUG_INFORMATION_FORMAT = dwarf;
242 | ENABLE_STRICT_OBJC_MSGSEND = YES;
243 | ENABLE_TESTABILITY = YES;
244 | GCC_C_LANGUAGE_STANDARD = gnu11;
245 | GCC_DYNAMIC_NO_PIC = NO;
246 | GCC_NO_COMMON_BLOCKS = YES;
247 | GCC_OPTIMIZATION_LEVEL = 0;
248 | GCC_PREPROCESSOR_DEFINITIONS = (
249 | "DEBUG=1",
250 | "$(inherited)",
251 | );
252 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
253 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
254 | GCC_WARN_UNDECLARED_SELECTOR = YES;
255 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
256 | GCC_WARN_UNUSED_FUNCTION = YES;
257 | GCC_WARN_UNUSED_VARIABLE = YES;
258 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
259 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
260 | MTL_FAST_MATH = YES;
261 | ONLY_ACTIVE_ARCH = YES;
262 | SDKROOT = iphoneos;
263 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
264 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
265 | VERSIONING_SYSTEM = "apple-generic";
266 | VERSION_INFO_PREFIX = "";
267 | };
268 | name = Debug;
269 | };
270 | C9D0289722607AD100B5E061 /* Release */ = {
271 | isa = XCBuildConfiguration;
272 | buildSettings = {
273 | ALWAYS_SEARCH_USER_PATHS = NO;
274 | CLANG_ANALYZER_NONNULL = YES;
275 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
277 | CLANG_CXX_LIBRARY = "libc++";
278 | CLANG_ENABLE_MODULES = YES;
279 | CLANG_ENABLE_OBJC_ARC = YES;
280 | CLANG_ENABLE_OBJC_WEAK = YES;
281 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
282 | CLANG_WARN_BOOL_CONVERSION = YES;
283 | CLANG_WARN_COMMA = YES;
284 | CLANG_WARN_CONSTANT_CONVERSION = YES;
285 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
287 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
288 | CLANG_WARN_EMPTY_BODY = YES;
289 | CLANG_WARN_ENUM_CONVERSION = YES;
290 | CLANG_WARN_INFINITE_RECURSION = YES;
291 | CLANG_WARN_INT_CONVERSION = YES;
292 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
293 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
294 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
295 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
296 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
297 | CLANG_WARN_STRICT_PROTOTYPES = YES;
298 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
299 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
300 | CLANG_WARN_UNREACHABLE_CODE = YES;
301 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
302 | CODE_SIGN_IDENTITY = "iPhone Developer";
303 | COPY_PHASE_STRIP = NO;
304 | CURRENT_PROJECT_VERSION = 1;
305 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
306 | ENABLE_NS_ASSERTIONS = NO;
307 | ENABLE_STRICT_OBJC_MSGSEND = YES;
308 | GCC_C_LANGUAGE_STANDARD = gnu11;
309 | GCC_NO_COMMON_BLOCKS = YES;
310 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
311 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
312 | GCC_WARN_UNDECLARED_SELECTOR = YES;
313 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
314 | GCC_WARN_UNUSED_FUNCTION = YES;
315 | GCC_WARN_UNUSED_VARIABLE = YES;
316 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
317 | MTL_ENABLE_DEBUG_INFO = NO;
318 | MTL_FAST_MATH = YES;
319 | SDKROOT = iphoneos;
320 | SWIFT_COMPILATION_MODE = wholemodule;
321 | SWIFT_OPTIMIZATION_LEVEL = "-O";
322 | VALIDATE_PRODUCT = YES;
323 | VERSIONING_SYSTEM = "apple-generic";
324 | VERSION_INFO_PREFIX = "";
325 | };
326 | name = Release;
327 | };
328 | C9D0289922607AD100B5E061 /* Debug */ = {
329 | isa = XCBuildConfiguration;
330 | baseConfigurationReference = 21744AB499310C2ECAEBB625 /* Pods-Router.debug.xcconfig */;
331 | buildSettings = {
332 | CLANG_ENABLE_MODULES = YES;
333 | CODE_SIGN_IDENTITY = "";
334 | CODE_SIGN_STYLE = Automatic;
335 | DEFINES_MODULE = YES;
336 | DEPLOYMENT_POSTPROCESSING = NO;
337 | DEVELOPMENT_TEAM = 683UGRW72Z;
338 | DYLIB_COMPATIBILITY_VERSION = 1;
339 | DYLIB_CURRENT_VERSION = 1;
340 | DYLIB_INSTALL_NAME_BASE = "@rpath";
341 | INFOPLIST_FILE = Sources/Info.plist;
342 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
343 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
344 | LD_RUNPATH_SEARCH_PATHS = (
345 | "$(inherited)",
346 | "@executable_path/Frameworks",
347 | "@loader_path/Frameworks",
348 | );
349 | OTHER_CFLAGS = (
350 | "$(inherited)",
351 | "-isystem",
352 | "\"${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator/URLNavigator.framework/Headers\"",
353 | "-iframework",
354 | "\"${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator\"",
355 | );
356 | OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
357 | PRODUCT_BUNDLE_IDENTIFIER = com.lee.router;
358 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
359 | SKIP_INSTALL = YES;
360 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
361 | SWIFT_VERSION = 5.0;
362 | TARGETED_DEVICE_FAMILY = "1,2";
363 | };
364 | name = Debug;
365 | };
366 | C9D0289A22607AD100B5E061 /* Release */ = {
367 | isa = XCBuildConfiguration;
368 | baseConfigurationReference = 1914FB7D28826DD9E48B39CC /* Pods-Router.release.xcconfig */;
369 | buildSettings = {
370 | CLANG_ENABLE_MODULES = YES;
371 | CODE_SIGN_IDENTITY = "";
372 | CODE_SIGN_STYLE = Automatic;
373 | DEFINES_MODULE = YES;
374 | DEPLOYMENT_POSTPROCESSING = NO;
375 | DEVELOPMENT_TEAM = 683UGRW72Z;
376 | DYLIB_COMPATIBILITY_VERSION = 1;
377 | DYLIB_CURRENT_VERSION = 1;
378 | DYLIB_INSTALL_NAME_BASE = "@rpath";
379 | INFOPLIST_FILE = Sources/Info.plist;
380 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
381 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
382 | LD_RUNPATH_SEARCH_PATHS = (
383 | "$(inherited)",
384 | "@executable_path/Frameworks",
385 | "@loader_path/Frameworks",
386 | );
387 | OTHER_CFLAGS = (
388 | "$(inherited)",
389 | "-isystem",
390 | "\"${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator/URLNavigator.framework/Headers\"",
391 | "-iframework",
392 | "\"${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator\"",
393 | );
394 | OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
395 | PRODUCT_BUNDLE_IDENTIFIER = com.lee.router;
396 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
397 | SKIP_INSTALL = YES;
398 | SWIFT_VERSION = 5.0;
399 | TARGETED_DEVICE_FAMILY = "1,2";
400 | };
401 | name = Release;
402 | };
403 | /* End XCBuildConfiguration section */
404 |
405 | /* Begin XCConfigurationList section */
406 | C9D0288A22607AD100B5E061 /* Build configuration list for PBXProject "Router" */ = {
407 | isa = XCConfigurationList;
408 | buildConfigurations = (
409 | C9D0289622607AD100B5E061 /* Debug */,
410 | C9D0289722607AD100B5E061 /* Release */,
411 | );
412 | defaultConfigurationIsVisible = 0;
413 | defaultConfigurationName = Release;
414 | };
415 | C9D0289822607AD100B5E061 /* Build configuration list for PBXNativeTarget "Router" */ = {
416 | isa = XCConfigurationList;
417 | buildConfigurations = (
418 | C9D0289922607AD100B5E061 /* Debug */,
419 | C9D0289A22607AD100B5E061 /* Release */,
420 | );
421 | defaultConfigurationIsVisible = 0;
422 | defaultConfigurationName = Release;
423 | };
424 | /* End XCConfigurationList section */
425 | };
426 | rootObject = C9D0288722607AD100B5E061 /* Project object */;
427 | }
428 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 6A595E95EAE9E20D30D1A8D6 /* Pods_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF996BB2479B7EE857452E0D /* Pods_Demo.framework */; };
11 | C9170B802274475200052A4E /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9170B7F2274475200052A4E /* LoginViewController.swift */; };
12 | C9170B822274483F00052A4E /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9170B812274483F00052A4E /* Account.swift */; };
13 | C9170B8422744F6300052A4E /* NeedLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9170B8322744F6300052A4E /* NeedLoginViewController.swift */; };
14 | C9D028B222607F8200B5E061 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028B122607F8200B5E061 /* AppDelegate.swift */; };
15 | C9D028B422607F8200B5E061 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028B322607F8200B5E061 /* ViewController.swift */; };
16 | C9D028B722607F8200B5E061 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9D028B522607F8200B5E061 /* Main.storyboard */; };
17 | C9D028B922607F8200B5E061 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9D028B822607F8200B5E061 /* Assets.xcassets */; };
18 | C9D028BC22607F8200B5E061 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9D028BA22607F8200B5E061 /* LaunchScreen.storyboard */; };
19 | C9D028E0226088F600B5E061 /* RouterOpener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028DE226088F600B5E061 /* RouterOpener.swift */; };
20 | C9D028E52260890900B5E061 /* RouterLaunchPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028E22260890900B5E061 /* RouterLaunchPlugin.swift */; };
21 | C9D028E62260890900B5E061 /* RouterSinglePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028E32260890900B5E061 /* RouterSinglePlugin.swift */; };
22 | C9D028E72260890900B5E061 /* RouterAccountPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028E42260890900B5E061 /* RouterAccountPlugin.swift */; };
23 | C9D028EB2260892B00B5E061 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028E92260892B00B5E061 /* Notification.swift */; };
24 | C9D028EC2260892B00B5E061 /* Notificationable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028EA2260892B00B5E061 /* Notificationable.swift */; };
25 | C9D028F02260893500B5E061 /* FastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028ED2260893500B5E061 /* FastViewController.swift */; };
26 | C9D028F12260893500B5E061 /* LiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028EE2260893500B5E061 /* LiveViewController.swift */; };
27 | C9D028F22260893500B5E061 /* NoneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028EF2260893500B5E061 /* NoneViewController.swift */; };
28 | C9D028F42260902E00B5E061 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028F32260902E00B5E061 /* Router.swift */; };
29 | C9D028F62260932E00B5E061 /* RouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D028F52260932E00B5E061 /* RouterType.swift */; };
30 | /* End PBXBuildFile section */
31 |
32 | /* Begin PBXFileReference section */
33 | 4FD45B063BA419F7B2949502 /* Pods-Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.debug.xcconfig"; path = "Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"; sourceTree = ""; };
34 | C9170B7F2274475200052A4E /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; };
35 | C9170B812274483F00052A4E /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; };
36 | C9170B8322744F6300052A4E /* NeedLoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeedLoginViewController.swift; sourceTree = ""; };
37 | C9D028AE22607F8200B5E061 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
38 | C9D028B122607F8200B5E061 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
39 | C9D028B322607F8200B5E061 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
40 | C9D028B622607F8200B5E061 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
41 | C9D028B822607F8200B5E061 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
42 | C9D028BB22607F8200B5E061 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
43 | C9D028BD22607F8200B5E061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
44 | C9D028DE226088F600B5E061 /* RouterOpener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterOpener.swift; sourceTree = ""; };
45 | C9D028E22260890900B5E061 /* RouterLaunchPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterLaunchPlugin.swift; sourceTree = ""; };
46 | C9D028E32260890900B5E061 /* RouterSinglePlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterSinglePlugin.swift; sourceTree = ""; };
47 | C9D028E42260890900B5E061 /* RouterAccountPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterAccountPlugin.swift; sourceTree = ""; };
48 | C9D028E92260892B00B5E061 /* Notification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; };
49 | C9D028EA2260892B00B5E061 /* Notificationable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notificationable.swift; sourceTree = ""; };
50 | C9D028ED2260893500B5E061 /* FastViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FastViewController.swift; sourceTree = ""; };
51 | C9D028EE2260893500B5E061 /* LiveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveViewController.swift; sourceTree = ""; };
52 | C9D028EF2260893500B5E061 /* NoneViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoneViewController.swift; sourceTree = ""; };
53 | C9D028F32260902E00B5E061 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; };
54 | C9D028F52260932E00B5E061 /* RouterType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterType.swift; sourceTree = ""; };
55 | CEB7AEFC933E088EF7C01816 /* Pods-Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.release.xcconfig"; path = "Target Support Files/Pods-Demo/Pods-Demo.release.xcconfig"; sourceTree = ""; };
56 | DF996BB2479B7EE857452E0D /* Pods_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
57 | /* End PBXFileReference section */
58 |
59 | /* Begin PBXFrameworksBuildPhase section */
60 | C9D028AB22607F8200B5E061 /* Frameworks */ = {
61 | isa = PBXFrameworksBuildPhase;
62 | buildActionMask = 2147483647;
63 | files = (
64 | 6A595E95EAE9E20D30D1A8D6 /* Pods_Demo.framework in Frameworks */,
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | /* End PBXFrameworksBuildPhase section */
69 |
70 | /* Begin PBXGroup section */
71 | 3E4CDB657E061C16E3075E06 /* Pods */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 4FD45B063BA419F7B2949502 /* Pods-Demo.debug.xcconfig */,
75 | CEB7AEFC933E088EF7C01816 /* Pods-Demo.release.xcconfig */,
76 | );
77 | path = Pods;
78 | sourceTree = "";
79 | };
80 | C9170B7E227446BB00052A4E /* Router */ = {
81 | isa = PBXGroup;
82 | children = (
83 | C9D028F32260902E00B5E061 /* Router.swift */,
84 | C9D028F52260932E00B5E061 /* RouterType.swift */,
85 | C9D028DE226088F600B5E061 /* RouterOpener.swift */,
86 | C9D028DD226088B300B5E061 /* Plugins */,
87 | );
88 | path = Router;
89 | sourceTree = "";
90 | };
91 | C9D028A522607F8200B5E061 = {
92 | isa = PBXGroup;
93 | children = (
94 | C9D028B022607F8200B5E061 /* Demo */,
95 | C9D028AF22607F8200B5E061 /* Products */,
96 | 3E4CDB657E061C16E3075E06 /* Pods */,
97 | EA37C84C061630303B9B0626 /* Frameworks */,
98 | );
99 | sourceTree = "";
100 | };
101 | C9D028AF22607F8200B5E061 /* Products */ = {
102 | isa = PBXGroup;
103 | children = (
104 | C9D028AE22607F8200B5E061 /* Demo.app */,
105 | );
106 | name = Products;
107 | sourceTree = "";
108 | };
109 | C9D028B022607F8200B5E061 /* Demo */ = {
110 | isa = PBXGroup;
111 | children = (
112 | C9170B7E227446BB00052A4E /* Router */,
113 | C9D028E82260891C00B5E061 /* Utils */,
114 | C9D028B122607F8200B5E061 /* AppDelegate.swift */,
115 | C9D028B322607F8200B5E061 /* ViewController.swift */,
116 | C9D028ED2260893500B5E061 /* FastViewController.swift */,
117 | C9D028EE2260893500B5E061 /* LiveViewController.swift */,
118 | C9D028EF2260893500B5E061 /* NoneViewController.swift */,
119 | C9170B8322744F6300052A4E /* NeedLoginViewController.swift */,
120 | C9170B7F2274475200052A4E /* LoginViewController.swift */,
121 | C9D028B522607F8200B5E061 /* Main.storyboard */,
122 | C9D028B822607F8200B5E061 /* Assets.xcassets */,
123 | C9D028BA22607F8200B5E061 /* LaunchScreen.storyboard */,
124 | C9D028BD22607F8200B5E061 /* Info.plist */,
125 | C9170B812274483F00052A4E /* Account.swift */,
126 | );
127 | path = Demo;
128 | sourceTree = "";
129 | };
130 | C9D028DD226088B300B5E061 /* Plugins */ = {
131 | isa = PBXGroup;
132 | children = (
133 | C9D028E42260890900B5E061 /* RouterAccountPlugin.swift */,
134 | C9D028E22260890900B5E061 /* RouterLaunchPlugin.swift */,
135 | C9D028E32260890900B5E061 /* RouterSinglePlugin.swift */,
136 | );
137 | path = Plugins;
138 | sourceTree = "";
139 | };
140 | C9D028E82260891C00B5E061 /* Utils */ = {
141 | isa = PBXGroup;
142 | children = (
143 | C9D028EA2260892B00B5E061 /* Notificationable.swift */,
144 | C9D028E92260892B00B5E061 /* Notification.swift */,
145 | );
146 | path = Utils;
147 | sourceTree = "";
148 | };
149 | EA37C84C061630303B9B0626 /* Frameworks */ = {
150 | isa = PBXGroup;
151 | children = (
152 | DF996BB2479B7EE857452E0D /* Pods_Demo.framework */,
153 | );
154 | name = Frameworks;
155 | sourceTree = "";
156 | };
157 | /* End PBXGroup section */
158 |
159 | /* Begin PBXNativeTarget section */
160 | C9D028AD22607F8200B5E061 /* Demo */ = {
161 | isa = PBXNativeTarget;
162 | buildConfigurationList = C9D028C022607F8200B5E061 /* Build configuration list for PBXNativeTarget "Demo" */;
163 | buildPhases = (
164 | 9D62DF0D51785BD3712034FB /* [CP] Check Pods Manifest.lock */,
165 | C9D028AA22607F8200B5E061 /* Sources */,
166 | C9D028AB22607F8200B5E061 /* Frameworks */,
167 | C9D028AC22607F8200B5E061 /* Resources */,
168 | 398883A394CE113360F5C960 /* [CP] Embed Pods Frameworks */,
169 | );
170 | buildRules = (
171 | );
172 | dependencies = (
173 | );
174 | name = Demo;
175 | productName = Demo;
176 | productReference = C9D028AE22607F8200B5E061 /* Demo.app */;
177 | productType = "com.apple.product-type.application";
178 | };
179 | /* End PBXNativeTarget section */
180 |
181 | /* Begin PBXProject section */
182 | C9D028A622607F8200B5E061 /* Project object */ = {
183 | isa = PBXProject;
184 | attributes = {
185 | LastSwiftUpdateCheck = 1020;
186 | LastUpgradeCheck = 1020;
187 | ORGANIZATIONNAME = swift;
188 | TargetAttributes = {
189 | C9D028AD22607F8200B5E061 = {
190 | CreatedOnToolsVersion = 10.2;
191 | };
192 | };
193 | };
194 | buildConfigurationList = C9D028A922607F8200B5E061 /* Build configuration list for PBXProject "Demo" */;
195 | compatibilityVersion = "Xcode 9.3";
196 | developmentRegion = en;
197 | hasScannedForEncodings = 0;
198 | knownRegions = (
199 | en,
200 | Base,
201 | );
202 | mainGroup = C9D028A522607F8200B5E061;
203 | productRefGroup = C9D028AF22607F8200B5E061 /* Products */;
204 | projectDirPath = "";
205 | projectRoot = "";
206 | targets = (
207 | C9D028AD22607F8200B5E061 /* Demo */,
208 | );
209 | };
210 | /* End PBXProject section */
211 |
212 | /* Begin PBXResourcesBuildPhase section */
213 | C9D028AC22607F8200B5E061 /* Resources */ = {
214 | isa = PBXResourcesBuildPhase;
215 | buildActionMask = 2147483647;
216 | files = (
217 | C9D028BC22607F8200B5E061 /* LaunchScreen.storyboard in Resources */,
218 | C9D028B922607F8200B5E061 /* Assets.xcassets in Resources */,
219 | C9D028B722607F8200B5E061 /* Main.storyboard in Resources */,
220 | );
221 | runOnlyForDeploymentPostprocessing = 0;
222 | };
223 | /* End PBXResourcesBuildPhase section */
224 |
225 | /* Begin PBXShellScriptBuildPhase section */
226 | 398883A394CE113360F5C960 /* [CP] Embed Pods Frameworks */ = {
227 | isa = PBXShellScriptBuildPhase;
228 | buildActionMask = 2147483647;
229 | files = (
230 | );
231 | inputFileListPaths = (
232 | "${PODS_ROOT}/Target Support Files/Pods-Demo/Pods-Demo-frameworks-${CONFIGURATION}-input-files.xcfilelist",
233 | );
234 | name = "[CP] Embed Pods Frameworks";
235 | outputFileListPaths = (
236 | "${PODS_ROOT}/Target Support Files/Pods-Demo/Pods-Demo-frameworks-${CONFIGURATION}-output-files.xcfilelist",
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | shellPath = /bin/sh;
240 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Demo/Pods-Demo-frameworks.sh\"\n";
241 | showEnvVarsInLog = 0;
242 | };
243 | 9D62DF0D51785BD3712034FB /* [CP] Check Pods Manifest.lock */ = {
244 | isa = PBXShellScriptBuildPhase;
245 | buildActionMask = 2147483647;
246 | files = (
247 | );
248 | inputFileListPaths = (
249 | );
250 | inputPaths = (
251 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
252 | "${PODS_ROOT}/Manifest.lock",
253 | );
254 | name = "[CP] Check Pods Manifest.lock";
255 | outputFileListPaths = (
256 | );
257 | outputPaths = (
258 | "$(DERIVED_FILE_DIR)/Pods-Demo-checkManifestLockResult.txt",
259 | );
260 | runOnlyForDeploymentPostprocessing = 0;
261 | shellPath = /bin/sh;
262 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
263 | showEnvVarsInLog = 0;
264 | };
265 | /* End PBXShellScriptBuildPhase section */
266 |
267 | /* Begin PBXSourcesBuildPhase section */
268 | C9D028AA22607F8200B5E061 /* Sources */ = {
269 | isa = PBXSourcesBuildPhase;
270 | buildActionMask = 2147483647;
271 | files = (
272 | C9170B802274475200052A4E /* LoginViewController.swift in Sources */,
273 | C9D028F62260932E00B5E061 /* RouterType.swift in Sources */,
274 | C9D028B422607F8200B5E061 /* ViewController.swift in Sources */,
275 | C9D028E52260890900B5E061 /* RouterLaunchPlugin.swift in Sources */,
276 | C9D028F12260893500B5E061 /* LiveViewController.swift in Sources */,
277 | C9170B822274483F00052A4E /* Account.swift in Sources */,
278 | C9D028E62260890900B5E061 /* RouterSinglePlugin.swift in Sources */,
279 | C9D028B222607F8200B5E061 /* AppDelegate.swift in Sources */,
280 | C9D028F02260893500B5E061 /* FastViewController.swift in Sources */,
281 | C9D028EB2260892B00B5E061 /* Notification.swift in Sources */,
282 | C9D028EC2260892B00B5E061 /* Notificationable.swift in Sources */,
283 | C9D028E0226088F600B5E061 /* RouterOpener.swift in Sources */,
284 | C9170B8422744F6300052A4E /* NeedLoginViewController.swift in Sources */,
285 | C9D028E72260890900B5E061 /* RouterAccountPlugin.swift in Sources */,
286 | C9D028F22260893500B5E061 /* NoneViewController.swift in Sources */,
287 | C9D028F42260902E00B5E061 /* Router.swift in Sources */,
288 | );
289 | runOnlyForDeploymentPostprocessing = 0;
290 | };
291 | /* End PBXSourcesBuildPhase section */
292 |
293 | /* Begin PBXVariantGroup section */
294 | C9D028B522607F8200B5E061 /* Main.storyboard */ = {
295 | isa = PBXVariantGroup;
296 | children = (
297 | C9D028B622607F8200B5E061 /* Base */,
298 | );
299 | name = Main.storyboard;
300 | sourceTree = "";
301 | };
302 | C9D028BA22607F8200B5E061 /* LaunchScreen.storyboard */ = {
303 | isa = PBXVariantGroup;
304 | children = (
305 | C9D028BB22607F8200B5E061 /* Base */,
306 | );
307 | name = LaunchScreen.storyboard;
308 | sourceTree = "";
309 | };
310 | /* End PBXVariantGroup section */
311 |
312 | /* Begin XCBuildConfiguration section */
313 | C9D028BE22607F8200B5E061 /* Debug */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ALWAYS_SEARCH_USER_PATHS = NO;
317 | CLANG_ANALYZER_NONNULL = YES;
318 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
319 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
320 | CLANG_CXX_LIBRARY = "libc++";
321 | CLANG_ENABLE_MODULES = YES;
322 | CLANG_ENABLE_OBJC_ARC = YES;
323 | CLANG_ENABLE_OBJC_WEAK = YES;
324 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
325 | CLANG_WARN_BOOL_CONVERSION = YES;
326 | CLANG_WARN_COMMA = YES;
327 | CLANG_WARN_CONSTANT_CONVERSION = YES;
328 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
329 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
330 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
331 | CLANG_WARN_EMPTY_BODY = YES;
332 | CLANG_WARN_ENUM_CONVERSION = YES;
333 | CLANG_WARN_INFINITE_RECURSION = YES;
334 | CLANG_WARN_INT_CONVERSION = YES;
335 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
336 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
337 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
338 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
339 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
340 | CLANG_WARN_STRICT_PROTOTYPES = YES;
341 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
342 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
343 | CLANG_WARN_UNREACHABLE_CODE = YES;
344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
345 | CODE_SIGN_IDENTITY = "iPhone Developer";
346 | COPY_PHASE_STRIP = NO;
347 | DEBUG_INFORMATION_FORMAT = dwarf;
348 | ENABLE_STRICT_OBJC_MSGSEND = YES;
349 | ENABLE_TESTABILITY = YES;
350 | GCC_C_LANGUAGE_STANDARD = gnu11;
351 | GCC_DYNAMIC_NO_PIC = NO;
352 | GCC_NO_COMMON_BLOCKS = YES;
353 | GCC_OPTIMIZATION_LEVEL = 0;
354 | GCC_PREPROCESSOR_DEFINITIONS = (
355 | "DEBUG=1",
356 | "$(inherited)",
357 | );
358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
360 | GCC_WARN_UNDECLARED_SELECTOR = YES;
361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
362 | GCC_WARN_UNUSED_FUNCTION = YES;
363 | GCC_WARN_UNUSED_VARIABLE = YES;
364 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
365 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
366 | MTL_FAST_MATH = YES;
367 | ONLY_ACTIVE_ARCH = YES;
368 | SDKROOT = iphoneos;
369 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
370 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
371 | };
372 | name = Debug;
373 | };
374 | C9D028BF22607F8200B5E061 /* Release */ = {
375 | isa = XCBuildConfiguration;
376 | buildSettings = {
377 | ALWAYS_SEARCH_USER_PATHS = NO;
378 | CLANG_ANALYZER_NONNULL = YES;
379 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
381 | CLANG_CXX_LIBRARY = "libc++";
382 | CLANG_ENABLE_MODULES = YES;
383 | CLANG_ENABLE_OBJC_ARC = YES;
384 | CLANG_ENABLE_OBJC_WEAK = YES;
385 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
386 | CLANG_WARN_BOOL_CONVERSION = YES;
387 | CLANG_WARN_COMMA = YES;
388 | CLANG_WARN_CONSTANT_CONVERSION = YES;
389 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
390 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
391 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
392 | CLANG_WARN_EMPTY_BODY = YES;
393 | CLANG_WARN_ENUM_CONVERSION = YES;
394 | CLANG_WARN_INFINITE_RECURSION = YES;
395 | CLANG_WARN_INT_CONVERSION = YES;
396 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
397 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
398 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
399 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
400 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
401 | CLANG_WARN_STRICT_PROTOTYPES = YES;
402 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
403 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
404 | CLANG_WARN_UNREACHABLE_CODE = YES;
405 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
406 | CODE_SIGN_IDENTITY = "iPhone Developer";
407 | COPY_PHASE_STRIP = NO;
408 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
409 | ENABLE_NS_ASSERTIONS = NO;
410 | ENABLE_STRICT_OBJC_MSGSEND = YES;
411 | GCC_C_LANGUAGE_STANDARD = gnu11;
412 | GCC_NO_COMMON_BLOCKS = YES;
413 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
414 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
415 | GCC_WARN_UNDECLARED_SELECTOR = YES;
416 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
417 | GCC_WARN_UNUSED_FUNCTION = YES;
418 | GCC_WARN_UNUSED_VARIABLE = YES;
419 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
420 | MTL_ENABLE_DEBUG_INFO = NO;
421 | MTL_FAST_MATH = YES;
422 | SDKROOT = iphoneos;
423 | SWIFT_COMPILATION_MODE = wholemodule;
424 | SWIFT_OPTIMIZATION_LEVEL = "-O";
425 | VALIDATE_PRODUCT = YES;
426 | };
427 | name = Release;
428 | };
429 | C9D028C122607F8200B5E061 /* Debug */ = {
430 | isa = XCBuildConfiguration;
431 | baseConfigurationReference = 4FD45B063BA419F7B2949502 /* Pods-Demo.debug.xcconfig */;
432 | buildSettings = {
433 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
434 | CODE_SIGN_IDENTITY = "Apple Development";
435 | CODE_SIGN_STYLE = Automatic;
436 | DEVELOPMENT_TEAM = "";
437 | INFOPLIST_FILE = Demo/Info.plist;
438 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
439 | LD_RUNPATH_SEARCH_PATHS = (
440 | "$(inherited)",
441 | "@executable_path/Frameworks",
442 | );
443 | PRODUCT_BUNDLE_IDENTIFIER = com.lee.router.demo;
444 | PRODUCT_NAME = "$(TARGET_NAME)";
445 | PROVISIONING_PROFILE_SPECIFIER = "";
446 | SWIFT_VERSION = 5.0;
447 | TARGETED_DEVICE_FAMILY = "1,2";
448 | };
449 | name = Debug;
450 | };
451 | C9D028C222607F8200B5E061 /* Release */ = {
452 | isa = XCBuildConfiguration;
453 | baseConfigurationReference = CEB7AEFC933E088EF7C01816 /* Pods-Demo.release.xcconfig */;
454 | buildSettings = {
455 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
456 | CODE_SIGN_IDENTITY = "Apple Development";
457 | CODE_SIGN_STYLE = Automatic;
458 | DEVELOPMENT_TEAM = "";
459 | INFOPLIST_FILE = Demo/Info.plist;
460 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
461 | LD_RUNPATH_SEARCH_PATHS = (
462 | "$(inherited)",
463 | "@executable_path/Frameworks",
464 | );
465 | PRODUCT_BUNDLE_IDENTIFIER = com.lee.router.demo;
466 | PRODUCT_NAME = "$(TARGET_NAME)";
467 | PROVISIONING_PROFILE_SPECIFIER = "";
468 | SWIFT_VERSION = 5.0;
469 | TARGETED_DEVICE_FAMILY = "1,2";
470 | };
471 | name = Release;
472 | };
473 | /* End XCBuildConfiguration section */
474 |
475 | /* Begin XCConfigurationList section */
476 | C9D028A922607F8200B5E061 /* Build configuration list for PBXProject "Demo" */ = {
477 | isa = XCConfigurationList;
478 | buildConfigurations = (
479 | C9D028BE22607F8200B5E061 /* Debug */,
480 | C9D028BF22607F8200B5E061 /* Release */,
481 | );
482 | defaultConfigurationIsVisible = 0;
483 | defaultConfigurationName = Release;
484 | };
485 | C9D028C022607F8200B5E061 /* Build configuration list for PBXNativeTarget "Demo" */ = {
486 | isa = XCConfigurationList;
487 | buildConfigurations = (
488 | C9D028C122607F8200B5E061 /* Debug */,
489 | C9D028C222607F8200B5E061 /* Release */,
490 | );
491 | defaultConfigurationIsVisible = 0;
492 | defaultConfigurationName = Release;
493 | };
494 | /* End XCConfigurationList section */
495 | };
496 | rootObject = C9D028A622607F8200B5E061 /* Project object */;
497 | }
498 |
--------------------------------------------------------------------------------