Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - congncif/NoMoreDeepLinkHandler: Deep link management · GitHub
Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - congncif/NoMoreDeepLinkHandler: Deep link management · GitHub
Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - congncif/NoMoreDeepLinkHandler: Deep link management · GitHub
Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - congncif/NoMoreDeepLinkHandler: Deep link management · GitHub
Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - congncif/NoMoreDeepLinkHandler: Deep link management · GitHub
Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - congncif/NoMoreDeepLinkHandler: Deep link management · GitHub
Skip to content

Repository files navigation

NoMoreDeepLinkHandler - Deep Link Handler

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 shouldHandleDeepLink decides if this plugin will handle the deep link or not? There are 3 options of DeepLinkHandlerOption.

    • 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 handleDeepLink will be called when the plugin confirmed handling the deep link. data is the parameters parsed from the deep link and it should be passed from shouldHandleDeepLink method. Normally a plugin opens a context corresponding to the deep link. Finally calls completion once done.

Installation

NoMoreDeepLinkHandler includes in MobileNext standard library and is available in private pod specs.

# Install NoMoreDeepLinkHandler directlypod"NoMoreDeepLinkHandler","~> 1.0"

Register a handler plugin

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)}}

Initialize SDK

NoMoreDeepLinkHandler must be initialized before use. This should occur at the app launch.

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

Handle open a deep link

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

Set up a barrier

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)})}}

Install barrier to DeepLinkHandler

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

Configure handler plugin

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 the payment deep link with barrier workflow

Open pay URLCheck the barrier passedOpen Payment screen

Deep link classification

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=123
  • app://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)}}}

Deep link path matching

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)}}

DeepLinkHandler more settings

  • 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 forbiddenHandler will be called. The priority is blacklist >> 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()

About

Deep link management

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages