NoMoreDeepLinkHandler 1.0.0

NoMoreDeepLinkHandler 1.0.0

congncif 维护。



  • 作者
  • Nguyen Chi Cong

NoMoreDeepLinkHandler - 深链接处理器

NoMoreDeepLinkHandler SDK 允许应用管理处理打开应用的 URL 处理器。这个 URL 可以是 方案 URL通用链接NoMoreDeepLinkHandler SDK 中的 DeepLinkHandler 是通过 插件机制 设计的,以便可扩展。

NoMoreDeepLinkHandler 处理深链接时,将扫描所有已安装的处理程序,并将该深链接转发给相应的处理程序。这个过程将 顺序 发生,直到找到第一个匹配的处理程序。否则,将调用 notFoundHandler

每个处理程序遵守 DeepLinkHandlerPlugin 协议。

public protocol DeepLinkHandlerPlugin {
    var completionTimeout: TimeInterval { get }

    func shouldHandleDeepLink(_ url: URL) -> DeepLinkHandlerOption

    func handleDeepLink(with data: Data?, completion: @escaping () -> Void)
}
  • 如果处理程序在 completionTimeout 之前被选中,它将有一段时间来处理深链接。

  • shouldHandleDeepLink 方法决定此插件是否会处理深链接。有三种 DeepLinkHandlerOption 选项。

    • no:插件拒绝处理深链接。处理深链接时将忽略它。
    • yes(data: Data?): 插件接受处理深链接,数据应从深链接参数编码。
    • yesWithBarrier(name: String, data: Data?): 插件接受处理深链接,但它必须通过一个以名称安装在 DeepLinkHandler 中的 Barrier。这对于需要由登录用户进行身份验证的深链接很有用。
  • 当插件确认处理深链接时,将调用 handleDeepLink 方法。data 是从深链接解析的参数,它应从 shouldHandleDeepLink 方法传递。通常,插件打开一个与深链接对应的上下文。最后,完成时调用 completion

安装

NoMoreDeepLinkHandler 包含在 MobileNext 标准库中,并在私有 Podspec 中可用。

# Install NoMoreDeepLinkHandler directly
pod "NoMoreDeepLinkHandler", "~> 1.0"

注册处理程序插件

要处理深链接 app:///pay?order_id=123,请创建一个 DeepLinkHandlerPlugin

final class PaymentDeepLinkHandlerPlugin: DeepLinkHandlerPlugin {
    func shouldHandleDeepLink(_ url: URL) -> DeepLinkHandlerOption {
        switch url.path {
        case "pay":
            let data = url.deepLinkExtensions.queryData
            return .yes(data: data)
        default:
            return .no
        }
    }

    func handleDeepLink(with data: Data?, completion: @escaping () -> Void) {
        present(paymentConfirmScreen, with: data, completion: completion)
    }
}

初始化 SDK

NoMoreDeepLinkHandler 必须在使用前初始化。这应该在应用启动时发生。

DeepLinkHandler.configure()
    .install(plugin: PaymentDeepLinkHandlerPlugin())
    .initialize()

处理打开深链接

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return DeepLinkHandler.shared.handle(deepLink: url)
}

设置障碍

许多深链接需要登录用户。因此,我们需要为此设置一个 AuthenticationDeepLinkBarrier

final class AuthenticationDeepLinkBarrier: DeepLinkHandlingBarrier {
    func status(for deepLink: URL) -> DeepLinkBarrierStatus {
        AccessToken.isValid ? .passed : .needToCheck
    }

    func performCheck(deepLink _: URL, completion: @escaping (Bool) -> Void) {
        // Navigate to Login screen
        present(loginScreen, callbackHandler: { data in
            completion(data != nil)
        })
    }
}

将障碍安装到 DeepLinkHandler 中

DeepLinkHandler.configure()
      .install(plugin: PaymentDeepLinkHandlerPlugin())
      .install(barrier: AuthenticationDeepLinkBarrier())
      .initialize()

配置处理程序插件

例如,使用障碍配置上述付款处理程序。

final class PaymentDeepLinkHandlerPlugin: DeepLinkHandlerPlugin {
    func shouldHandleDeepLink(_ url: URL) -> DeepLinkHandlerOption {
        switch url.path {
        case "pay":
            let data = url.deepLinkExtensions.queryData
            return .yesWithBarrier(AuthenticationDeepLinkBarrier.self, data: data)
        default:
            return .no
        }
    }

    func handleDeepLink(with data: Data?, completion: @escaping () -> Void) {
        present(paymentConfirmScreen, with: data, completion: completion)
    }
}

使用障碍工作流程打开付款深链接

打开付款 URL检查障碍是否通过打开付款屏幕

深链接分类

有时,您需要在单个插件中处理一组深层链接,或者您需要预先处理查询数据以进行分类从URL中获取的查询数据。通过这种方式,DeepLinkHandlerPlugin定义关联的参数类型,然后您可以在handleDeepLink时通过该参数进行切换。因此,您不需要符合DeepLinkHandlerPlugin规范,而是需要符合DeepLinkHandlerCodingPlugin规范。

例如,您需要处理以下两个Payment深层链接

  • app:///pay?order_id=123
  • app:///transaction/789,其中789是transaction_id
enum PaymentDeepLinkPoint: Codable {
    case makePayment(data: Data?)
    case transaction(id: String?)

    init?(url: URL) {
        let paths = url.deepLinkExtensions.pathComponents
        var iterator = paths.makeIterator()
        switch (iterator.next(), iterator.next()) {
        case ("pay", nil):
            self = .makePayment(data: url.deepLinkExtensions.queryData)
        case ("transaction", let transactionID?):
            self = .transaction(id: transactionID)
        default:
            return nil
        }
    }
}

final class PaymentDeepLinkHandlerPlugin: DeepLinkHandlerCodingPlugin {
    func shouldHandleCodingDeepLink(_ url: URL) -> DeepLinkHandlerCodingOption<PaymentDeepLinkPoint> {
        guard let point = PaymentDeepLinkPoint(url: url) else {
            return .no
        }
        return .yesWithBarrier(AuthenticationDeepLinkBarrier.self, parameters: point)
    }

    func handleCodingDeepLink(with parameters: PaymentDeepLinkPoint, completion: @escaping () -> Void) {
        switch parameters {
        case let .makePayment(data):
            present(paymentConfirmScreen, with: data, completion: completion)
        case let .transaction(id):
            present(transactionDetailScreen, with data: id?.data(using: .utf8), completion: completion)
        }
    }
}

深层链接路径匹配

定义一个具有动态参数的DeepLinkHandlerPlugin参数在URL路径中。

了解更多关于 路径参数

👉 使用DeepLinkHandlerPathMatchingPlugin协议而不是DeepLinkHandlerPlugin

例如,您需要处理以下Transaction深层链接

  • app:///transaction/789
final class TransactionDeepLinkPlugin: DeepLinkHandlerPathMatchingPlugin {
    var matchingPath: String {
        // Return path parameters pattern here
        "/transaction/{transaction_id}"
    }

    func handleDeepLink(with data: Data?, completion: @escaping () -> Void) {
        // The data is the encoded value of ["transaction_id": "789"]
        present(transactionDetailScreen, completion: completion)
    }
}

DeepLinkHandler更多设置

  • notFoundHandler:没有注册适当处理器的处理程序时调用的处理器。
DeepLinkHandler.configure()
    .withNotFoundHandler({ url in
        // Open not found screen
    })
    .install(plugin: PaymentDeepLinkHandlerPlugin())
    .initialize()
  • excludedSchemesexcludedHosts:将筛选出将不会被NoMoreDeepLinkHandler处理的方案和主机。

  • blacklistSchemesblacklistHostswhitelistHostswhitelistSchemes:在处理深层链接之前进行筛选,如果设置了此字段的值,则仅处理白名单中的主机或方案。否则,将调用forbiddenHandler。优先级是blacklist >> whitelist

DeepLinkHandler.configure()
    .set(blacklistHosts: ["localhost"])
    .set(whitelistSchemes: ["first-scheme", "second-sechme"])
    .set(whitelistHosts: ["sample-domain.vn"])
    .with(forbiddenHandler: { url in
        print("The deep link is forbidden: \(url)")
    })
    ...
    .initialize()
  • mandatoryBarrier:在处理深层链接之前,所有深层链接必须通过的所有障碍。

这对于需要用户登录才能使用所有其他功能的App可能很有用。

DeepLinkHandler.configure()
    .set(mandatoryBarrier: AuthenticationDeepLinkBarrier())
    ...
    .initialize()