feat: complete deeplink api

This commit is contained in:
Nikita Semenov 2023-01-10 19:26:46 +03:00
parent a7e44a3d9a
commit aff54859eb
8 changed files with 255 additions and 9 deletions

View File

@ -21,7 +21,7 @@ let package = Package(
.library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]),
.library(name: "TITableKitUtils", targets: ["TITableKitUtils"]),
.library(name: "TILogging", targets: ["TILogging"]),
.library(name: "TIDeepLink", targets: ["TIDeepLink"]),
.library(name: "TIDeeplink", targets: ["TIDeeplink"]),
// MARK: - Networking
@ -33,7 +33,7 @@ let package = Package(
.library(name: "TIMapUtils", targets: ["TIMapUtils"]),
.library(name: "TIAppleMapUtils", targets: ["TIAppleMapUtils"]),
// MARK: - Elements
.library(name: "OTPSwiftView", targets: ["OTPSwiftView"]),
.library(name: "TITransitions", targets: ["TITransitions"]),
@ -66,7 +66,7 @@ let package = Package(
.target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"),
.target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
.target(name: "TILogging", dependencies: ["TIUIElements", "TISwiftUtils", "TIUIKitCore"], path: "TILogging/Sources"),
.target(name: "TIDeepLink", dependencies: [], path: "TIDeepLink/Sources"),
.target(name: "TIDeeplink", dependencies: ["TIFoundationUtils"], path: "TIDeeplink/Sources"),
// MARK: - Networking
.target(name: "TINetworking", dependencies: ["TIFoundationUtils", "Alamofire"], path: "TINetworking/Sources"),
@ -76,7 +76,7 @@ let package = Package(
// MARK: - Maps
.target(name: "TIMapUtils", dependencies: [], path: "TIMapUtils/Sources"),
.target(name: "TIAppleMapUtils", dependencies: ["TIMapUtils"], path: "TIAppleMapUtils/Sources"),
// MARK: - Elements
.target(name: "OTPSwiftView", dependencies: ["TIUIElements"], path: "OTPSwiftView/Sources"),
.target(name: "TITransitions", path: "TITransitions/Sources"),

View File

@ -0,0 +1,48 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
import UIKit
open class BaseNavigationStackDeeplinkHandler: DeeplinkHandler {
// MARK: - DeeplinkHandler
open func canHandle(deeplink: DeeplinkType) -> Bool {
findHandler(for: deeplink) != nil
}
open func handle(deeplink: DeeplinkType) -> Operation? {
let handler = findHandler(for: deeplink)
return handler?.handle(deeplink: deeplink)
}
// MARK: - Open methods
open func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandler? {
guard let rootController = UIApplication.shared.keyWindow?.rootViewController else {
return nil
}
return rootController.findHandler(for: deeplink)
}
}

View File

@ -0,0 +1,28 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
public protocol DeeplinkHandler {
func canHandle(deeplink: DeeplinkType) -> Bool
func handle(deeplink: DeeplinkType) -> Operation?
}

View File

@ -0,0 +1,37 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import UIKit
public typealias DeeplinkHandlerViewController = DeeplinkHandler & UIViewController
public extension UIViewController {
func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? {
if let deeplinksHandler = self as? DeeplinkHandlerViewController,
deeplinksHandler.canHandle(deeplink: deeplink) {
return deeplinksHandler
}
let deeplinksHandler = presentedViewController?.findHandler(for: deeplink)
return deeplinksHandler
}
}

View File

@ -0,0 +1,27 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
public protocol DeeplinkMapper {
func map(url: URL) -> DeeplinkType?
}

View File

@ -0,0 +1,24 @@
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public protocol DeeplinkType {
}

View File

@ -1,9 +1,88 @@
final class DeeplinksService {
//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
static let shared = DeeplinksService()
import Foundation
import TIFoundationUtils
public final class TIDeeplinksService {
public static let shared = TIDeeplinksService()
// MARK: - Private properties
private let operationQueue = OperationQueue.main
private var pendingDeeplink: DeeplinkType?
private(set) var isProcessDeeplink = false
// MARK: - Public properties
public var deeplinkMapper: DeeplinkMapper?
public var deeplinkHandler = BaseNavigationStackDeeplinkHandler()
// MARK: - Init
private init() {
}
}
// MARK: - Public methods
@discardableResult
public func deferredHandle(url: URL) -> Bool {
pendingDeeplink = deeplinkMapper?.map(url: url)
return pendingDeeplink != nil
}
public func reset() {
operationQueue.cancelAllOperations()
pendingDeeplink = nil
isProcessDeeplink = false
}
public func tryHandle() {
guard let deeplink = pendingDeeplink,
deeplinkHandler.canHandle(deeplink: deeplink) else {
return
}
handle()
}
public func handle() {
guard let deeplink = pendingDeeplink,
let lastOperation = deeplinkHandler.handle(deeplink: deeplink) else {
return
}
operationQueue.addOperation { [weak self] in
self?.isProcessDeeplink = true
self?.pendingDeeplink = nil
}
operationQueue.addOperations(lastOperation.flattenDependencies + [lastOperation],
waitUntilFinished: false)
operationQueue.addOperation { [weak self] in
self?.isProcessDeeplink = false
}
}
}

View File

@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = 'TIDeepLink'
s.name = 'TIDeeplink'
s.version = '1.33.0'
s.summary = 'Deep link service API'
s.summary = 'Deeplink service API'
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru',
@ -12,4 +12,7 @@ Pod::Spec.new do |s|
s.swift_versions = ['5.3']
s.source_files = s.name + '/Sources/**/*'
s.dependency 'TIFoundationUtils', s.version.to_s
end