iOS Integration Guide
This guide covers how to integrate the Hubble SDK into an iOS application using WKWebView.
1. Setup the WebView
Use WKWebView with a WKUserContentController configured for the message bridge:
iOS offers two WebView options: WKWebView and SFSafariViewController. You must use WKWebView for the Hubble SDK integration. Using SFSafariViewController will cause Hubble's fraud detection checks to fail, resulting in blocked transactions and a broken user experience.
var webview: WKWebView!
override func loadView() {
let userContentController = WKUserContentController()
userContentController.add(self, name: "bridge") // web-to-native handler
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
webview = WKWebView(frame: .zero, configuration: configuration)
webview.navigationDelegate = self
webview.uiDelegate = self
view = webview
}
The SDK sends messages to a handler named "bridge". If you register with a different name, events will not be received.
2. Initialization
Initialize the view controller with your credentials:
| Parameter | Required | Description |
|---|---|---|
clientId | Yes | Client ID provided by the Hubble team |
appSecret | Yes | App secret provided by the Hubble team |
token | Conditional | SSO token for the current user. Required unless lazy login is enabled. |
appVersion | No | App version string. Defaults to "10000". |
deviceId | No | Device identifier for analytics. |
For iOS, set wrap-plt=ios.
init(clientId: String, appSecret: String, token: String? = nil) {
self.clientId = clientId
self.appSecret = appSecret
self.token = token
super.init(nibName: nil, bundle: nil)
}
3. Load the WebView
Build the URL and load it:
override func viewDidLoad() {
var components = URLComponents(string: "https://sdk.myhubble.money/")!
// For dev: use "https://sdk.dev.myhubble.money/"
var queryItems = [
URLQueryItem(name: "clientId", value: clientId),
URLQueryItem(name: "appSecret", value: appSecret),
URLQueryItem(name: "wrap-plt", value: "ios"),
]
if let token = token {
queryItems.append(URLQueryItem(name: "token", value: token))
}
components.queryItems = queryItems
webview.load(URLRequest(url: components.url!))
webview.allowsBackForwardNavigationGestures = true
webview.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
}
4. Handling Navigation
Implement decidePolicyFor navigationAction to keep Hubble and payment URLs in the WebView:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
}
let baseUrl = URL(string: "https://sdk.myhubble.money")!
let paymentUrl = URL(string: "https://api.razorpay.com")!
if url.absoluteString.hasPrefix(baseUrl.absoluteString)
|| url.absoluteString.hasPrefix(paymentUrl.absoluteString) {
decisionHandler(.allow)
} else {
UIApplication.shared.open(url)
decisionHandler(.cancel)
}
}
Enable swipe-to-go-back navigation with: webview.allowsBackForwardNavigationGestures = true
5. Handling Events
The SDK communicates with your application by sending events. There are two types:
Action Events
SDK lifecycle and navigation:
| Action | When It Fires | What You Should Do |
|---|---|---|
app_ready | SDK has finished loading | Show the WebView / iframe. Hide your loading spinner. |
close | User tapped the close or back button in the SDK | Dismiss the WebView / iframe. Navigate the user back. |
error | SDK failed to load (invalid credentials, network error, SSO failure) | Hide the WebView. Show a user-friendly error with a retry option. |
The close action is the only way the SDK tells your application that the user wants to leave. If you do not handle it, the user will be stuck inside the SDK with no way to navigate back. This is one of the most common integration issues.
Analytics Events
User interaction tracking:
{ "type": "analytics", "event": "payment_success", "properties": { "amount": 500 } }
Forward analytics events to your analytics provider (Mixpanel, CleverTap, Amplitude, etc.) to track SDK usage.
For a complete list of events, see the Full Events Reference.
Setting Up the Event Bridge
Conform to WKScriptMessageHandler and parse incoming JSON messages:
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let body = message.body as? String,
let data = body.data(using: .utf8),
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let type = json["type"] as? String else { return }
if type == "action" {
let action = json["action"] as? String
if action == "close" {
self.dismiss(animated: true)
} else if action == "app_ready" {
print("Hubble SDK is ready")
} else if action == "error" {
print("Hubble SDK failed to load")
}
} else if type == "analytics" {
let event = json["event"] as? String ?? ""
let properties = json["properties"] as? [String: Any] ?? [:]
// Forward to your analytics provider
}
}
6. Payment Configuration
The Hubble SDK supports UPI and credit/debit card payments. Credit/debit card payments are not enabled by default - contact Hubble support to enable them.
UPI on iOS
On iOS, a WebView cannot detect which UPI apps are installed on the user's device. This is a platform restriction. Because of this, the SDK displays icons for popular UPI apps (Google Pay, PhonePe, Paytm, CRED, BHIM) regardless of whether they are actually installed.
Passing Installed UPI Apps (Recommended)
To improve the user experience, your native iOS app can detect which UPI apps are installed and pass this list to the SDK. The SDK will then display only the UPI apps available on the device.
Add the following to your app's Info.plist under LSApplicationQueriesSchemes:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>phonepe</string>
<string>tez</string>
<string>paytmmp</string>
<string>cred</string>
<string>bhim</string>
</array>
With these schemes declared, use UIApplication.shared.canOpenURL() to check which apps are installed and pass the list to the SDK.
Without passing the installed apps list, users may tap a UPI app icon only to find it is not installed. This creates a poor payment experience.
iOS WebView Background Behavior
When a user taps a UPI app, they leave your app to complete the payment. iOS may suspend the WKWebView's JavaScript execution while your app is in the background. When the user returns, the SDK resumes polling. In most cases this works fine, but the payment screen may appear stuck for a few seconds.
Listen for applicationDidBecomeActive or sceneDidBecomeActive and reload the WebView if the payment screen appears stuck.
Best Practices
- Remove the script message handler: In
deinit, calluserContentController.removeScriptMessageHandler(forName: "bridge")to avoid memory leaks. - Create a fresh WebView each time: Do not cache or reuse the WebView between sessions.
- Show a loading state: Keep the WebView hidden until
app_readyfires. - Handle new window requests: Implement
createWebViewWithin yourWKUIDelegateto handle payment gateways that open in a new window.