iOS - Continuity Lifecycle Module
Overview
Use ContinuityLifecycleModule when your module needs to handle module-owned deep links
from custom URL schemes or Universal Links.
This is the iOS module hook for links that should be inspected and handled by your module.
The closest Android equivalent is LifecycleModule, which receives new intents and lets
a module decide whether to handle them.
For built-in FI app deeplink contracts, see Deep Linking.
When To Use ContinuityLifecycleModule
Use ContinuityLifecycleModule when:
- your module owns the incoming link format
- your module needs to inspect the link directly
- the link should trigger module-specific behavior instead of built-in FI app routing
- your module needs to respond to either custom URL schemes or Universal Links
When Not To Use It
Do not use ContinuityLifecycleModule when:
- the link should route into an existing FI app screen or UUX route
- the built-in FI app deeplink contract is sufficient
- your module does not own the incoming link format
Built-in FI app deep links get the first chance to handle the link. Your module only receives the link when built-in handling does not consume it.
Supported Entry Points
ContinuityLifecycleModule can receive:
application(_:shouldOpenURL:withOptions:)Handles custom URL scheme deep links.application(_:willContinueUserActivityWithType:)Optional preflight hook before continuing a user activity.application(_:continue:restorationHandler:)Handles Universal Links.application(_:didFailToContinueUserActivityWithType:error:)Handles failures for continued user activities.application(_:handleEventsForBackgroundURLSession:completionHandler:)Handles background URL session continuation callbacks.
For callback methods that return Bool?:
truemeans the module handled the eventfalsemeans the module did not handle the eventnilmeans no module decision, soQ2MobileAppcan continue default handling
URL Shapes Your Module May Inspect
Your module can be triggered in two common ways:
- Custom URL Scheme
Format:
urlScheme://moduleIdentifier/pathExample:q2mob://com.q2.mobile.module.demo/path - Universal Link
Format:
https://{associated-domain}/...#/moduleIdentifier/pathExample:https://demo.q2.com/experimental/uux.aspx#/com.q2.mobile.module.demo/path
These are module-owned link examples. They are different from the built-in FI app deeplink contract.
Implementation
Implement ContinuityLifecycleModule when your module needs to examine incoming links and
return true only when it owns and handles the link.
In the following example:
- the module accepts custom URL scheme and Universal Link targets for
com.q2.mobile.module.demo/path - the module normalizes incoming URLs before matching
- the module returns
nilwhen the link is malformed or does not belong to the module - the module returns
truewhen it claims the link
import Q2ModuleInterfaces
import UIKit
final class CustomContinuityLifecycleModule: ContinuityLifecycleModule {
private let moduleTarget = "com.q2.mobile.module.demo/path"
var moduleDelegate: ModuleDelegate?
var moduleDataSource: ModuleDataSource?
func application(
_ application: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void
) {
completionHandler()
}
func application(
_ application: UIApplication,
shouldOpenURL url: URL,
withOptions options: [UIApplication.OpenURLOptionsKey: Any]
) -> Bool? {
handle(url: url)
}
func application(
_ application: UIApplication,
willContinueUserActivityWithType userActivityType: String
) -> Bool? {
false
}
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool? {
guard let webpageURL = userActivity.webpageURL else {
return nil
}
return handle(url: webpageURL)
}
func application(
_ application: UIApplication,
didFailToContinueUserActivityWithType userActivityType: String,
error: Error
) {
// no-op
}
}
private extension CustomContinuityLifecycleModule {
func handle(url: URL) -> Bool? {
guard let target = normalizedTarget(from: url) else {
return nil
}
guard target == moduleTarget else {
return nil
}
// Process the module-owned deep link here.
return true
}
func normalizedTarget(from url: URL) -> String? {
if let fragment = url.fragment?.lowercased(), !fragment.isEmpty {
return fragment.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
}
guard let host = url.host?.lowercased() else {
return nil
}
let path = url.path
.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
.lowercased()
return path.isEmpty ? host : "\(host)/\(path)"
}
}
Handling Rules
- built-in FI app link handling runs first
- module continuity handling runs only if built-in handling declines the link
- return
trueonly when your module owns and handled the link - return
nilwhen the link is malformed or clearly not for your module
Test In Q2DevApp
Custom URL Scheme
- Set the FI
urlSchemeinsettings.json. - Set the same value in
Q2DevAppInfo.plistunderCFBundleURLSchemes. - Run
Q2DevApp. - In Safari, open a link such as:
q2mob://com.q2.mobile.module.demo/path - Confirm your module handles the link.
Universal Links
- Configure the associated domain in
Q2DevApp.entitlements. - Run
Q2DevApp. - In Safari, open a link such as:
https://demo.q2.com/experimental/uux.aspx#/com.q2.mobile.module.demo/path - Confirm your module handles the link.
Troubleshooting
- If your module never receives the link, confirm the link is not being consumed by the built-in FI app deeplink contract.
- If custom URL scheme handling does not fire, confirm the FI
urlSchemematches the value inQ2DevAppInfo.plist. - If Universal Link handling does not fire, confirm Associated Domains, provisioning, and Apple App Site Association configuration for the exact host being tested.
- If your module receives the callback but should not claim the link, return
nilorfalseinstead oftrue.
DevApp Notes
Q2DevApp is the development app partners use to build and test modules locally.
Starting in Mobile SDK iOS 26.3.0, Q2DevApp is scene-based. The continuity lifecycle
APIs and examples on this page remain valid, but your Q2DevApp must also include the
required scene manifest and Q2DevAppSceneDelegate wiring described in
Setup DevApp.