This guide covers the required steps to integrate and run the LeapMobile SDK in an iOS application.
LeapMobile SDK allows host applications to embed Leap experiences inside their app, including navigation, deep link handling, analytics, logging, and SSO authentication.
- Xcode 16+
- iOS 16+
- Access to the private repository (SSH key or GitHub token)
- File with assets and initial content
content_vN.zipandrunConfig.json. Do not unzipcontent_vN.zip.- Unzip
images_full_vN.zipinto a folder so that you can delete and replace it later when you get a new version. - Do not put
buildConfig.jsonanywhere in the code. You'll need to reference this file, but it should never end up in the build. - This content, including images, must be bundled with the app to ensure offline support.
LeapMobile SDK is distributed as a private Swift Package.
- Open Xcode
- Go to File > Add Package Dependecies
- Search for the repository SSH url: <git@github.com:patrontech/LeapMobileSDK-iOS.git>
- To support the .nib files included in the SDK, you must add the -ObjC flag under Build Settings β Other Linker Flags for your target.
The SDK must be initialized before any other method is called. Due to internal SDK constraints, the initialization process must be performed asynchronously.
secrets:[Secret: String]metricsProviders:[AnalyticsProvider]logging:LoggingConfiguration
- The first parameter requires some configuration ids and information that need to be exported in this secrets collection. This particular example is the one that we used inside our sample app.
- A more detailed documentation for those parameters will be created.
let secrets: [Secret: String] = [
.otaZip: "15bf9cb77aa74de693cd678ebcbbec05",
.notificationRegistrationApi: "foo",
.notificationInboxApi: "bar",
.remoteStateApi: "baz",
.showclixApi: "biz",
.accountDeletionApi: "boz"
]- If you want a custom logger or to wrap an existing logger from the target codebase, implement the
CustomLoggerprotocol from theLeapMobilemodule. A more detailed documentation will be created for this. - If you want a custom analytics provider, implement the
MappedProviderprotocol from theLeapMobileBasemodule. A more detailed documentation will be created for this.
let logger = DemoLogger()
let analytics = DemoAnalyticsProvider(logger: logger) try await LeapMobileSDK.initialize(
secrets: secrets,
metricsProviders: [analytics],
logging: .logger(logger)
)The SDK have a property called initialization that return what is the state of the SDK based on its initialization. It can be three different states:
- uninitialized -> When the SDK still have not started the initialization
- initializing -> When the SDK is in the middle of the process to initialize
- initialized -> When the SDK have finished initializing.
After the SDK was initialized you can use some of the methods to be able to show the SDK on your application.
- Root Presentation
The SDK provides a main rootViewController that serves as its entry point. Retrieve it asynchronously, then present it using your preferred navigation method (modal, push, etc.). In our example, the SDK is presented modally.
func openSDK(style: SDKPresentationStyle) {
Task {
let rootVC = try await LeapMobileSDK.rootViewController
openSDK(with: rootVC, style: style)
}
}
private func openSDK(with viewController: UIViewController, style: SDKPresentationStyle) {
closeActiveSheet()
switch(style) {
case .bottomSheet:
let nav = UINavigationController(rootViewController: viewController)
activeBottomSheet = Sheet(nav)
case .fullScreen:
activeFullScreenSheet = Sheet(viewController)
}
}In this particular example from our sample app, it shows that you might or not embed our SDK Root View Controller in a navigation controller. If its embedded it will have an extra bar that may be used for some of our features. Some internal features may require a NavigationController to be able to be reached as well. So it's a good practice to have this implemented. But for some cases as Deeplinks you might not need as we are going to show in the next example.
- Deeplinks
The SDK provides a mechanism to resolve and handle deep links received by the host application. You need to call the resolvedDeepLink method asynchronous and wait for its response. If a deeplink was not able to be resolved it will return a nil view controller so remember to take this in consideration when implemented.
Task {
let urlResolved = try await LeapMobileSDK.resolveDeepLink(url)
openSDK(with: urlResolved, style: .bottomSheet)
}
- Webview DataStore
To share information between webviews from the main app and the SDK, we need some configuration needed for the usage of the webview. The WKWebsiteDataStore needs to be set for the .default one. So we can guarantee its going to be shared to any webview opened inside the SDK. Here is the sample method we used to show this:
func openWebView(urlString: String) -> some View {
let url = URL(string: urlString)!
let dataStore: WKWebsiteDataStore = .default()
return CustomWebView(url: url, dataStore: dataStore)
}
``
4. SSO Login
This part of the documentation will be done when we develop this feature.
5. SSO Logout
This part of the documentation will be done when we develop this feature.
6. SSO State Listener
This part of the documentation will be done when we develop this feature.
## Error Handling
All async SDK methods may throw errors.
Make sure to handle errors gracefully and provide fallback UI to the user.
The types of error that the SDK might throw are the ones listed here:
1. sdkNotInitialized -> Error that is throw if you want to use a function of the SDK that needs it to be initialized but it's not.
2. noSuchDeepLink -> Error that is throw if you a deeplink was not found inside the SDK resolver.
3. sdkInitialized -> This is a generic error if an error was thrown while the sdk was already initialized.
4. sdkInitializing -> This is a generic error if an error was thrown while the sdk was initializing.
## Common Pitfalls
- Forgetting to initialize the SDK before accessing any method
- Shipping `buildConfig.json` in the app bundle
- Not embedding the rootViewController in a UINavigationController when required by internal flows
---
# 3. Push Notifications & Deeplink Testing
This demo app includes built-in tools to test push notifications and deeplink handling.
## In-App Notification Simulator
The app includes filter chip buttons that trigger local push notifications with deeplink payloads:
- **π Schedule** - Sends a notification that opens `fanaticssdkstaging://schedule`
- **π Talents** - Sends a notification that opens `fanaticssdkstaging://talents`
- **π Brands** - Sends a notification that opens `fanaticssdkstaging://brands`
- **π Sample** - Sends a notification that opens `sampleapp://test`
### How it works:
1. Tap any notification test button
2. A local notification will be scheduled (3 second delay)
3. The notification appears in the notification center
4. Tap the notification to open the app with the deeplink
5. The SDK resolves the deeplink and displays the appropriate content
### Permission Handling
On first launch, the app automatically requests notification permissions. If denied, you can enable them in:
**Settings app β Notifications β LeapMobileSDKDemo β Allow Notifications**
## Available Deeplink Schemes
1. **LeapSDK Scheme**: `fanaticssdkstaging://`
- Resolves through the LeapMobileSDK
- Examples: `fanaticssdkstaging://schedule`, `fanaticssdkstaging://talents`, `fanaticssdkstaging://brands`
2. **Sample App Scheme**: `sampleapp://`
- Opens the demo deeplink view
- Example: `sampleapp://test`
## Testing Flow
1. Build and run the app in simulator
2. Grant notification permissions when prompted
3. Tap any "π" button to schedule a test notification
4. Wait 3 seconds for the notification to appear
5. Tap the notification to test the deeplink flow
### Debugging Tips:
- Check console logs for SDK initialization status and deeplink processing
- Verify notification permissions in Settings app
- Ensure SDK is fully initialized before testing deeplinks
- Use the "Deeplink" button to manually test URL input