Skip to main content

Installation

Prerequisites​

Before integrating the Flex Checkout Flutter SDK, ensure your project meets the following requirements:

  • Flutter 3.3.0+
  • Dart 3.0.0+
  • iOS 13.0+
  • Android API level 26+ (Android 8.0 Oreo)

Package Installation​

Add the Flex Checkout Flutter SDK from pub.dev in your pubspec.yaml:

YAML
dependencies:
flex_checkout_flutter: ^1.3.0

Then install:

Bash
flutter pub get
info

The caret constraint (^1.3.0) resolves to the latest compatible release (>=1.3.0 <2.0.0). Your pubspec.lock keeps builds reproducible; run flutter pub upgrade flex_checkout_flutter to pick up new releases explicitly.


iOS Setup​

After installation, run CocoaPods to link the native iOS dependency:

Bash
cd ios && pod install

The Flutter plugin depends on the FlexCheckout CocoaPod (published on CocoaPods Trunk), which CocoaPods resolves automatically — no extra Podfile entries needed.


Android Setup​

Add the JitPack Maven repository​

The native Flex Checkout Android SDK is distributed via JitPack. Add the JitPack repo to your project's settings.gradle.kts so Gradle can resolve it:

Kotlin
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}

Without this, your Android build will fail to resolve com.github.flexapp:flex-checkout-android.

FlutterFragmentActivity​

The Flex Checkout Android SDK renders its bottom sheet inside a BottomSheetDialogFragment, which requires the host Activity to be a FragmentActivity. The default FlutterActivity is not one — change your MainActivity.kt to extend FlutterFragmentActivity:

Kotlin
import io.flutter.embedding.android.FlutterFragmentActivity

class MainActivity : FlutterFragmentActivity()

Without this, tapping the button fires onError("Requires a FragmentActivity context").

Material theme​

The SDK uses MaterialButton, BottomSheetDialogFragment, and AppCompat vector drawables. Your launch and main themes must inherit from Theme.MaterialComponents.*:

XML
<!-- android/app/src/main/res/values/styles.xml -->
<style name="LaunchTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>

Initializing the SDK​

Initialize the Flex SDK once at app startup by awaiting Flex.initialize(config) and holding the returned FlexSDK reference. The SDK is a singleton — subsequent calls without an intervening cleanup return the same instance.

DART
import 'package:flex_checkout_flutter/flex_checkout_flutter.dart';
import 'package:flutter/material.dart' hide Flex;

void main() async {
WidgetsFlutterBinding.ensureInitialized();

final sdk = await Flex.initialize(
const FlexConfig(
clientId: 'your-flex-client-id',
environment: FlexEnvironment.int, // use FlexEnvironment.prod for production
),
);

runApp(MyApp(sdk: sdk));
}
info

Flutter's widget library also exports a class named Flex. Add hide Flex to your flutter/material.dart import to avoid the ambiguity.

info

You can access the SDK instance anywhere in your app via Flex.instance once initialize has resolved.

FlexConfig Fields​

ParameterTypeDescription
clientIdStringRequired The client id provided by Flex which identifies your Flex client.
environmentFlexEnvironmentThe environment to use — either FlexEnvironment.int (testing) or FlexEnvironment.prod (production). Defaults to FlexEnvironment.int.
developerFlexDeveloperConfig?Developer tool configuration options. Only takes effect in non-production environments.

Developer Tools​

The optional developer field can be configured to enable verbose logging for debugging.

DART
final sdk = await Flex.initialize(
const FlexConfig(
clientId: 'your-flex-client-id',
developer: FlexDeveloperConfig(logs: true),
),
);

Developer Fields​

Fields for the developer object.

ParameterTypeDescription
logsboolDisplays informative logs for debugging the Flex Flutter SDK. Defaults to false.

Environments​

There are only two environments for you to use:

EnvironmentUse it forDescription
FlexEnvironment.intTestingIntegration / sandbox environment. Use it for all development and testing.
FlexEnvironment.prodProductionProduction environment. Use it only for live, production traffic.
warning

int and prod are the only environments supported for partner integrations. Any other value on the FlexEnvironment enum is reserved for Flex-internal use and must not be used.


Token​

sdk.loadToken takes an async function that the SDK calls to fetch a token from your backend.

DART
sdk.loadToken(() async {
final response = await http.get(Uri.parse('https://your-api.com/flex-token'));
final body = jsonDecode(response.body) as Map<String, dynamic>;
return body['token'] as String;
});
warning

loadToken must be called before checkout can be opened. The SDK fires onError with "No token loader provided..." if no loader has been registered.


Lifecycle Management​

User state (form input, scroll position, partial flow progress) is preserved across opens — if a user starts onboarding, closes the sheet, and reopens, they resume right where they left off. The native WebView is pre-warmed automatically when you call Flex.initialize, so the first openCheckout is fast on both platforms.

Cleanup​

Call cleanup only when the user signs out of your app. The SDK's WebView retains the previous user's in-flight UI state (form input, partial flow, cached client-side data), so if the next user signs in without cleanup, they would land into the previous user's session inside the WebView. Calling cleanup on sign-out wipes that state.

DART
void signOut() {
Flex.instance.cleanup();
// ...your sign-out logic
}

After cleanup, the next call to Flex.initialize rebuilds the native SDK from scratch.

warning

Do not call cleanup from a screen's dispose() or whenever the user navigates away from your checkout screen. Doing that destroys the warm WebView every time and the user loses any in-progress onboarding state on every re-entry.

For most apps the sign-out hook is the only place cleanup is needed.


Analytics​

logImpression(data)​

Logs an impression event when the Flex checkout entry point becomes visible to the user. Call this from initState or whenever the checkout entry point appears on screen.

DART
import 'package:flex_checkout_flutter/flex_checkout_flutter.dart';


void initState() {
super.initState();
Flex.instance.logImpression({
'residentId': 'xyz',
'propertyId': 'prop-12345',
'placement': 'homepage',
'element': 'split_rent_button',
});
}

Recommended fields for impression data:

ParameterTypeDescription
residentIdStringid associated with the resident.
propertyIdStringid associated with the property.
placement'homepage'
'payments'
'checkout'
Where the user interaction takes place in your portal.
element'split_rent_button'
'learn_more'
'awareness_banner'
Element displayed for the interaction.

Error Reference​

Setup​

Flex.initialize will throw if clientId is blank (the underlying native SDK raises a fatal error / exception immediately). There are no other setup-time errors; everything else surfaces via onError at runtime.

Runtime (onError messages)​

The onError checkout callback receives a descriptive String whenever something goes wrong. For load failures, the SDK already displays its own retry UI inside the sheet (see Checkout → Error Handling) — these messages are for your logging and analytics.

MessageWhen it occurs
"No token loader provided. Call loadToken() before opening checkout."openCheckout invoked before loadToken was registered
"FlexCheckout not configured — call Flex.initialize first."openCheckout invoked before Flex.initialize
"Flex checkout host not ready. Try again momentarily."openCheckout invoked at app launch before the SDK's host has attached
"Checkout is temporarily unavailable. Please try again later."Flex kill-switch is active for your client
"Checkout failed to load: <reason>"WebView load, JS handshake, or token loader failed — SDK shows its own retry UI in the sheet

For "Checkout failed to load: <reason>", the <reason> suffix is one of:

  • "The Internet connection appears to be offline." — no network
  • "Checkout did not load in time" — 15-second JS handshake timeout
  • "Failed to load token: <your loader's error>" — your loadToken callback threw
  • "Token loader returned an empty token" — your loadToken callback returned ""
DART
sdk.checkout(CheckoutConfig(
onError: (error) {
// Log + report — the SDK already shows the user-facing error UI.
analytics.track('flex_checkout_error', {'message': error});
},
));

Next Steps​

Now that the SDK is installed and configured: