Skip to main content

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:

Use WKWebView Only

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
}
Bridge Name Must Be "bridge"

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:

ParameterRequiredDescription
clientIdYesClient ID provided by the Hubble team
appSecretYesApp secret provided by the Hubble team
tokenConditionalSSO token for the current user. Required unless lazy login is enabled.
appVersionNoApp version string. Defaults to "10000".
deviceIdNoDevice 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:

ActionWhen It FiresWhat You Should Do
app_readySDK has finished loadingShow the WebView / iframe. Hide your loading spinner.
closeUser tapped the close or back button in the SDKDismiss the WebView / iframe. Navigate the user back.
errorSDK failed to load (invalid credentials, network error, SSO failure)Hide the WebView. Show a user-friendly error with a retry option.
Always Handle the close Event

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.

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.

Why This Matters

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.

Handling Background Resumption

Listen for applicationDidBecomeActive or sceneDidBecomeActive and reload the WebView if the payment screen appears stuck.

Best Practices

  • Remove the script message handler: In deinit, call userContentController.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_ready fires.
  • Handle new window requests: Implement createWebViewWith in your WKUIDelegate to handle payment gateways that open in a new window.