NoMoreDeepLinkHandler SDK enables the app to manage URL Handlers which handle the URLs to open the app. This URL might be a schemed URL or a Universal link. The DeepLinkHandler in NoMoreDeepLinkHandler SDK is designed with the plugin mechanism to enable scalability.
When NoMoreDeepLinkHandler handles a deep link, it will scan through all installed handlers, and forward that deep link to the appropriate handler. This process happens sequentially until the first matching handler is found. Otherwise, notFoundHandler will be called.
Each handler conforms to the protocol DeepLinkHandlerPlugin.
publicprotocolDeepLinkHandlerPlugin{varcompletionTimeout:TimeInterval{get}func shouldHandleDeepLink(_ url:URL)->DeepLinkHandlerOptionfunc handleDeepLink(with data:Data?, completion:@escaping()->Void)}A handler has a certain amount of time to process the deep link if it is selected before
completionTimeout.The method
shouldHandleDeepLinkdecides if this plugin will handle the deep link or not? There are 3 options ofDeepLinkHandlerOption.- no: the plugin declines to handle the deep link. This will be ignored when processing the deep link.
- yes(data: Data?): the plugin accepts to handle the deep link, the data should be encoded from the parameters of the deep link.
- yesWithBarrier(name: String, data: Data?): the plugin accepts to handle the deep link but it has to pass a Barrier which is also installed into DeepLinkHandler with name. This is useful with the deep link needed to authenticate by a logged-in user.
The method
handleDeepLinkwill be called when the plugin confirmed handling the deep link.datais the parameters parsed from the deep link and it should be passed fromshouldHandleDeepLinkmethod. Normally a plugin opens a context corresponding to the deep link. Finally callscompletiononce done.
NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.
# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"To register to handle a deep link app://localhost/pay?order_id=123, create a DeepLinkHandlerPlugin.
finalclassPaymentDeepLinkHandlerPlugin:DeepLinkHandlerPlugin{func shouldHandleDeepLink(_ url:URL)->DeepLinkHandlerOption{switch url.path {case"pay":letdata= url.deepLinkExtensions.queryData
return.yes(data: data)default:return.no
}}func handleDeepLink(with data:Data?, completion:@escaping()->Void){present(paymentConfirmScreen, with: data, completion: completion)}}NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.
DeepLinkHandler.configure().install(plugin:PaymentDeepLinkHandlerPlugin()).initialize()func application(_ app:UIApplication, open url:URL, options:[UIApplication.OpenURLOptionsKey:Any]=[:])->Bool{returnDeepLinkHandler.shared.handle(deepLink: url)}Many deep links require a logged-in user. So we need to set up an AuthenticationDeepLinkBarrier for this.
finalclassAuthenticationDeepLinkBarrier: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 incompletion(data !=nil)})}}DeepLinkHandler.configure().install(plugin:PaymentDeepLinkHandlerPlugin()).install(barrier:AuthenticationDeepLinkBarrier()).initialize()For example, configure the above Payment handler with the barrier.
finalclassPaymentDeepLinkHandlerPlugin:DeepLinkHandlerPlugin{func shouldHandleDeepLink(_ url:URL)->DeepLinkHandlerOption{switch url.path {case"pay":letdata= 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)}}Open pay URL ⏩ Check the barrier passed ⏩ Open Payment screen
Sometime, you need to handle a group deep links in a single plugin or you need to pre-process to classify query data gotten from URL. By that way, DeepLinkHandlerPlugin defines an associated parameters type, then you can switch by that parameters when handleDeepLink. So instead of conforming DeepLinkHandlerPlugin, you conform DeepLinkHandlerCodingPlugin.
For example, you need to handle two below deep links of Payment:
app://localhost/pay?order_id=123app://localhost/transaction/789,with 789 is transaction_id
enumPaymentDeepLinkPoint:Codable{case makePayment(data:Data?)case transaction(id:String?)init?(url:URL){letpaths= url.deepLinkExtensions.pathComponents
variterator= 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:returnnil}}}finalclassPaymentDeepLinkHandlerPlugin:DeepLinkHandlerCodingPlugin{func shouldHandleCodingDeepLink(_ url:URL)->DeepLinkHandlerCodingOption<PaymentDeepLinkPoint>{guardlet point =PaymentDeepLinkPoint(url: url)else{return.no
}return.yesWithBarrier(AuthenticationDeepLinkBarrier.self, parameters: point)}func handleCodingDeepLink(with parameters:PaymentDeepLinkPoint, completion:@escaping()->Void){switch parameters {caselet.makePayment(data):present(paymentConfirmScreen, with: data, completion: completion)caselet.transaction(id):present(transactionDetailScreen, with data: id?.data(using:.utf8), completion: completion)}}}Define a DeepLinkHandlerPlugin with a dynamic path which has parameters value in the URL path.
Read more aboutPath Parameters
👉 Conforms the protocol DeepLinkHandlerPathMatchingPlugin instead of DeepLinkHandlerPlugin.
For example, you need to handle the below deep link of Transaction:
app://localhost/transaction/789
finalclassTransactionDeepLinkPlugin:DeepLinkHandlerPathMatchingPlugin{varmatchingPath: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)}}- notFoundHandler: Handle when no appropriate handlers are registered to handle the deep link.
DeepLinkHandler.configure().withNotFoundHandler({ url in
// Open not found screen
}).install(plugin:PaymentDeepLinkHandlerPlugin()).initialize()excludedSchemes & excludedHosts: Filter the schemes and hosts which will be not handled by NoMoreDeepLinkHandler
blacklistSchemes & blacklistHosts & whitelistHosts & whitelistSchemes: Filter before handing the deep link, only the hosts or schemes in the whitelist will be handled if this field is set. Otherwise the
forbiddenHandlerwill be called. The priority isblacklist>>whitelist.
DeepLinkHandler.configure().set(blacklistHosts:["localhost"]).set(whitelistSchemes:["first-scheme","second-sechme"]).set(whitelistHosts:["sample-domain.vn"]).with(forbiddenHandler:{ url inprint("The deep link is forbidden: \(url)")})....initialize()- mandatoryBarrier: The barrier that requires all of deep links must pass before they are handled.
This might be useful for apps that require the user have to login to use every other features.
DeepLinkHandler.configure().set(mandatoryBarrier:AuthenticationDeepLinkBarrier())....initialize()