6.4 KiB
Deeplink API
TIDeeplink добавляет сервис TIDeeplinksService для обработки диплинков
Как настроить
- Создать объект, представляющий диплинк. Такой объект должен соответствовать протоколу
Hashable
import Foundation
import TIDeeplink
import TIFoundationUtils
import TISwiftUtils
import UIKit
enum ProjectDeeplink: Hashable {
case editProfile
case office(id: String)
}
- Создать объект, соответствующий протоколу
DeeplinkMapper. Его задачей будет - преобразование URL в диплинк
final class ProjectDeeplinkMapper: DeeplinkMapper {
func map(url: URL) -> ProjectDeeplink? {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return nil
}
switch components.host {
case "office":
if let id = components.path.split(separator: "/").last {
return .office(id: String(id))
}
return nil
case "editProfile":
return .editProfile
default:
return nil
}
}
}
- Реализовать у объекта отвечающего за навигацию протокол
DeeplinkHandler. В необходимом для реализации методеhandle(deeplink:)нужно обработать передаваемый диплинк и вернуть соответствующее действие
class MainCoordinator: DeeplinkHandler {
func openEditProfileScreen() {
print("Presenting edit profile view controller")
}
func openOfficesScreen(completion: VoidClosure?) {
print("Presenting offices view controller")
completion?()
}
func openOfficesScreen(forId id: String) {
print("Presenting offices view controller by id: \(id)")
}
// MARK: DeeplinkHandler
func handle(deeplink: ProjectDeeplink) -> Operation? {
switch deeplink {
case .editProfile:
return BlockOperation { [weak self] in
self?.openEditProfileScreen()
}
case let .office(id):
return ClosureAsyncOperation<Void, Never> { [weak self] completion in
self?.openOfficesScreen {
self?.openOfficesScreen(forId: id)
completion(.success(()))
}
return Cancellables.nonCancellable()
}
}
}
}
Опционально 4. Создать сабкласс TIDeeplinksService для удобного использования по проекту
final class ProjectDeeplinksService: TIDeeplinksService<ProjectDeeplink> {
static let shared = ProjectDeeplinksService()
convenience init(mapper: ProjectDeeplinkMapper = .init(), handler: MainCoordinator = .init()) {
self.init(mapper: mapper, handler: handler, operationQueue: .main)
}
}
Создаем и передаем в сервис Mapper и Handler.
Так же можно воспользоваться инициализатором
init(mapper:handler:operationQueue:). Если Mapper и Handler передаются не в инициализаторе, то их самостоятельно необходимо привести к видуAnyDeeplinkHandlerиAnyDeeplinkMapperс момощью методов:eraseToAnyDeeplinkHandler()иeraseToAnyDeeplinkMapper()
let coordinator = MainCoordinator()
let mapper = ProjectDeeplinkMapper()
ProjectDeeplinksService.shared.deeplinkMapper = mapper.eraseToAnyDeeplinkMapper()
ProjectDeeplinksService.shared.deeplinkHandler = coordinator.eraseToAnyDeeplinkHandler()
В AppDelegate использвуем методы deferredHandle(url:) и handlePendingDeeplinks() для обработки диплинков.
deferredHandle(url:): пытается создать из URL диплинк и добавить его в очередь на обработкуhandlePendingDeeplinks(): обрабатывает первый в череди диплинк
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
ProjectDeeplinksService.shared.deferredHandle(url: url)
ProjectDeeplinksService.shared.handlePendingDeeplinks()
return true
}
guard let url = URL(string: "app://office/123") else {
fatalError()
}
application(.shared, open: url)
В качестве DeeplinkHandler можно использовать базовую реализацию BaseNavigationStackDeeplinkHandler, которая позволяет искать handler в иерархии view, способный обработать диплинк.
protocol ProjectDeeplinkHandler: DeeplinkHandler where Deeplink == ProjectDeeplink {
}
class ViewController: UIViewController, ProjectDeeplinkHandler {
func handle(deeplink: ProjectDeeplink) -> Operation? {
switch deeplink {
case .editProfile:
return BlockOperation {
print("Presenting edit profile view controller")
}
case let .office(id):
return BlockOperation {
print("Presenting offices view controller by id: \(id)")
}
}
}
}
Создание Handler. Для настройки передается rootViewController, который должен наследоваться от UIViewController С этого контроллера будет начинаться поиск обработчика
let viewController = ViewController()
let navigationController = UINavigationController(rootViewController: viewController)
let handler = BaseNavigationStackDeeplinkHandler<ProjectDeeplink>(rootViewController: navigationController) {
guard let projectHandler = $0 as? (any ProjectDeeplinkHandler) else {
return nil
}
return projectHandler.eraseToAnyDeeplinkHandler()
}
Далее handler может передаваться для использования в TIDeeplinksService
let mapper = ProjectDeeplinkMapper()
let service = TIDeeplinksService(mapper: mapper, handler: handler)
service.deferredHandle(url: url)
service.handlePendingDeeplinks()
RunLoop.main.run()