Flutter Integration
This guide covers how to integrate the Hubble SDK into a Flutter application using webview_flutter.
1. Setup the WebView
Add the required dependencies to your pubspec.yaml:
dependencies:
webview_flutter: ^4.0.0
url_launcher: ^6.0.0
Run flutter pub get after adding the dependencies.
2. Initialization
Build the SDK URL 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. |
final params = {
'clientId': 'id_given_by_hubble',
'appSecret': 'secret_given_by_hubble',
'token': 'your_sso_token',
};
final baseUrl = 'https://sdk.dev.myhubble.money/';
// prod: https://sdk.myhubble.money/
final sourceUrl = '$baseUrl?clientId=${params['clientId']}&appSecret=${params['appSecret']}&token=${params['token']}';
3. Load the WebView
Initialize the WebViewController and load the URL:
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Colors.white)
..setNavigationDelegate(NavigationDelegate(/* ... */))
..addJavaScriptChannel("FlutterHost",
onMessageReceived: (message) => _handleEvent(message.message),
)
..loadRequest(Uri.parse(sourceUrl));
The SDK sends messages to a channel named "FlutterHost". If you use a different name, events will not be received.
4. Handling Navigation
Use the NavigationDelegate to control URL handling:
NavigationDelegate(
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith(baseUrl)
|| request.url.startsWith('https://api.razorpay.com')) {
return NavigationDecision.navigate;
} else {
launchUrl(Uri.parse(request.url), mode: LaunchMode.externalApplication);
return NavigationDecision.prevent;
}
},
)
Back Navigation
Use PopScope to handle the Android back button:
PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) async {
if (didPop) return;
if (await _controller.canGoBack()) {
await _controller.goBack();
} else {
if (context.mounted) Navigator.of(context).pop();
}
},
child: Scaffold(
body: SafeArea(child: WebViewWidget(controller: _controller)),
),
)
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 Handler
Parse JSON messages from the FlutterHost channel:
void _handleEvent(String jsonString) {
try {
final data = jsonDecode(jsonString) as Map<String, dynamic>;
final type = data['type'] as String?;
if (type == 'action') {
final action = data['action'] as String?;
if (action == 'close') {
Navigator.of(context).pop();
} else if (action == 'app_ready') {
setState(() => _loading = false);
} else if (action == 'error') {
setState(() => _error = true);
}
} else if (type == 'analytics') {
final event = data['event'] as String?;
final properties = data['properties'] as Map<String, dynamic>?;
// Forward to your analytics provider
}
} catch (e) {
print('Error handling event: $e');
}
}
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 Flutter
Flutter uses a WebView under the hood, so UPI configuration depends on the target platform:
- iOS: Add the
LSApplicationQueriesSchemesto yourInfo.plist(see the iOS Integration Guide for details). - Android: Add the
<queries>block to yourAndroidManifest.xml(see the Android Integration Guide for details).
In your NavigationDelegate, UPI scheme URLs should be launched externally using url_launcher.
Best Practices
- Wrap in SafeArea: Always use
SafeAreato avoid content being hidden behind the notch or system UI. - Dispose properly: The
WebViewControlleris automatically disposed when the widget is removed from the tree. - Show a loading state: Use a
Stackto overlay a loading spinner untilapp_readyfires. - Test on both platforms: Flutter WebView behavior can differ between iOS and Android. Test on both physical devices.