Usage

This guide describes how to integrate and operate the KLP Flutter SDK in your application: initialization, session management, the loyalty WebView, UI components, event handling, and error management.

Usage

This guide describes how to integrate and operate the KLP Flutter SDK in your
application: initialization, session management, the loyalty WebView, UI
components, event handling, and error management.

Integration lifecycle

The SDK expects methods to be called in a defined order. Calling an API before
initialization completes results in KlpNotInitializedException.

Application start
  └─ initialize()       once, at cold start
       └─ setUser()     after your app authenticates the user
            ├─ launch()       present the loyalty WebView
            ├─ widgets          entry button, reward banner
            ├─ logEvent()     report business events
            └─ event streams  rewards, deep links, and more
       └─ logout()      when the user signs out of your app

Initialize the SDK

Call initialize() once after WidgetsFlutterBinding.ensureInitialized().

Environment
Use the test environment for development and staging builds to avoid
unintended transactions on the production loyalty platform.

import 'package:flutter/foundation.dart';
import 'package:klp_flutter_sdk/klp_flutter_sdk.dart';

Future<void> bootstrapKlp() async {
  try {
    await Klp.instance.initialize(
      KlpInitializeConfig(
        environment: kReleaseMode ? KlpEnvironment.prod : KlpEnvironment.test,
        debugMode: !kReleaseMode,
        showDebugScreen: false,
      ),
    );
  } on KlpSecurityException catch (e) {
    // The device did not pass mandatory integrity checks.
    // Restrict access to sensitive loyalty features.
  }
}

Configuration options

FieldTypeDescription
environmentKlpEnvironmentTarget environment: test, or prod
debugModeboolEnables verbose native logging. Set to false in production
showDebugScreenboolfalseWhen true, shows a floating debug button that opens the SDK debug interface. Security checks remain active. Must be false in production

During initialization, the SDK performs native device-integrity checks, including
detection of rooted or jailbroken devices, emulators, debugging tools, and
application tampering. If mandatory checks fail, KlpSecurityException is thrown
and the result property contains detailed probe information.

Debug tools (integration testing)

Set showDebugScreen: true during development to display a floating debug
button. Tapping the button opens the SDK debug interface, where you can inspect security results, API logs, and trigger test
actions. Security checks remain enabled — unlike debugMode, which disables them.

You can also open the debug interface programmatically:

await Klp.instance.openDebugScreen();

Both options must remain disabled in production builds (showDebugScreen: false;
do not call openDebugScreen() in release).

Manage the user session

After your application authenticates the user, bind their session to the SDK:

await Klp.instance.setUser(userId, accessToken);
ParameterDescription
userIdStable identifier from your identity system
accessTokenSession token forwarded to the loyalty platform

When the user signs out of your application, end the loyalty session:

await Klp.instance.logout();

Security
Do not log or persist the access token outside your existing session
management. The SDK forwards it to the native layer and does not store it in
Dart.

Loyalty WebView

The full loyalty experience is presented through a native modal WebView. Open it
programmatically with launch(). An optional route parameter navigates to a
specific section:

await Klp.instance.launch();          // default entry point
await Klp.instance.launch('rewards'); // specific route

The loyalty interface itself is rendered natively — it is not embedded inside
your Flutter widget tree. Your application triggers presentation from Dart and
responds to lifecycle events on the surrounding screen.

Requirements

  • The SDK must be initialized
  • A user session should be established (per your loyalty configuration)
  • On iOS, an active view controller must be available — call from a mounted screen
  • On Android, a foreground Activity is required

WebView lifecycle events

Klp.instance.onWebViewClosed.listen((_) {
  // The user closed the loyalty experience
});

Klp.instance.onDeepLink.listen((link) {
  if (isAllowedDeepLink(link)) {
    // Navigate within your application
  }
});

Treat deep link payloads as untrusted input. Validate scheme, host, and
path against an allowlist before routing.

Opening the WebView securely

Verify device integrity before presenting the loyalty experience on sensitive
screens:

final result = await Klp.instance.performSecurityChecks();
if (result.allPassed) {
  await Klp.instance.launch();
}

UI components

Depending on your integration, you may work with Ready to use Flutter components that connect to Klp.instance for loyalty entry points and reward feedback in your application shell. These components are developed for your organization
APIs, visual design, and behaviour are shaped around your brand and agreed
requirements, not shipped as a fixed universal module. Where included in your delivery, import them from the same package:

import 'package:klp_flutter_sdk/klp_flutter_sdk.dart';

KlpLoyaltyButton

A ready-made entry button that opens the loyalty WebView props and style will be change depends on need:

KlpLoyaltyButton(
  label: 'My Rewards',
  route: 'rewards',
  icon: Icons.card_giftcard,
  onError: (error) => handleLaunchError(error),
)
ParameterDefaultDescription
label'My Rewards'Button label text
routenullOptional route passed to launch()
iconIcons.card_giftcardLeading icon
onErrornullCallback invoked if the launch fails (e.g. SDK not initialized)

The button uses KlpLoyaltyTheme.primaryButtonStyle for consistent styling with
the SDK design system.

KlpRewardBanner

A stream-driven banner that surfaces the most recent reward. It renders nothing
until the first onRewardEarned event arrives:

KlpRewardBanner(
  onTap: (reward) => Klp.instance.launch('rewards'),
)
ParameterDescription
onTapOptional callback when the banner is tapped; receives the KlpReward

The banner displays the reward name, description, and point value. It listens
to Klp.instance.onRewardEarned internally — no manual stream wiring is required.

KlpLoyaltyTheme

Design tokens for loyalty surfaces in your application:

TokenDescription
primaryPrimary brand color for actions
primaryDarkText and icon emphasis
accentHighlight color
surfaceCard and banner backgrounds
cornerRadiusShared border radius
primaryButtonStylePre-configured ButtonStyle for loyalty buttons

Use these tokens when building custom loyalty UI alongside the provided widgets.

Complete screen example

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await bootstrapKlp();
  runApp(const MyApp());
}
class LoyaltySection extends StatelessWidget {
  const LoyaltySection({super.key});

  @override
  Widget build(BuildContext context) {
    return const Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        KlpRewardBanner(),
        SizedBox(height: 12),
        KlpLoyaltyButton(label: 'My Rewards'),
      ],
    );
  }
}

Connect session management to your authentication flow:

// After login
await Klp.instance.setUser(session.userId, session.accessToken);

// On logout
await Klp.instance.logout();

Custom widget integration

You can build your own entry points and notifications using the same underlying
APIs the SDK widgets use:

ElevatedButton(
  onPressed: () => Klp.instance.launch(),
  child: const Text('My Rewards'),
)
StreamBuilder<KlpReward>(
  stream: Klp.instance.onRewardEarned,
  builder: (context, snapshot) {
    final reward = snapshot.data;
    if (reward == null) return const SizedBox.shrink();
    return ListTile(
      title: Text(reward.name),
      subtitle: Text(reward.description),
      trailing: Text('+${reward.value.toStringAsFixed(0)}'),
    );
  },
)

Report engagement events

Send business events to the loyalty platform:

await Klp.instance.logEvent('MoneyTransfer', {
  'amount': 500,
  'currency': 'TRY',
});

Include only data approved for transmission to the loyalty backend. Avoid
personal identifiable information and secrets in event attributes unless
explicitly authorized in your data processing agreement.

Theme and language

await Klp.instance.setTheme(KlpTheme.dark);

final appearance = await Klp.instance.getAppearance();
// appearance.theme, appearance.resolvedTheme, appearance.languageTag

await Klp.instance.setLanguage('tr-TR'); // pass null to use the system locale

Subscribe to onThemeChanged and onLanguageChanged to reflect changes made
by the user within the loyalty experience.

Event streams

All event streams are broadcast streams backed by a single native channel.
Multiple listeners are supported. Cancel subscriptions when they are no longer
needed to prevent memory leaks.

class LoyaltyController {
  LoyaltyController() {
    _subscriptions.add(Klp.instance.onRewardEarned.listen(_onReward));
    _subscriptions.add(Klp.instance.onDeepLink.listen(_onDeepLink));
    _subscriptions.add(
      Klp.instance.onError.listen((e) => handleSdkError(e.message)),
    );
    _subscriptions.add(Klp.instance.onSecurityError.listen(_onSecurityError));
  }

  final _subscriptions = <StreamSubscription<dynamic>>[];

  void dispose() {
    for (final subscription in _subscriptions) {
      subscription.cancel();
    }
    _subscriptions.clear();
  }

  void _onReward(KlpReward reward) { /* ... */ }
  void _onDeepLink(KlpDeepLink link) { /* ... */ }
  void _onSecurityError(KlpSecurityCheckResult result) { /* ... */ }
}

Available streams

StreamPayloadDescription
onEventKlpEventPayloadGeneral events from the loyalty WebView
onRewardEarnedKlpRewardUser earned a reward
onErrorKlpErrorPayloadRecoverable SDK error
onSecurityErrorKlpSecurityCheckResultRuntime security verification failure
onSseEffectsList<KlpSseEffect>Real-time gamification effects
onDeepLinkKlpDeepLinkNavigation request from the loyalty WebView
onWebViewClosedvoidUser dismissed the loyalty WebView
onThemeChangedKlpThemeChangedTheme changed within the experience
onLanguageChangedKlpLanguageChangedLanguage changed within the experience

Payload reference

KlpReward

FieldTypeDescription
idStringReward identifier
nameStringDisplay name
descriptionStringDescription text
imageUrlStringImage URL
valuedoublePoint value
typeStringReward category
earnedAtintTimestamp in milliseconds

KlpDeepLink

FieldTypeDescription
urlStringFull URL
schemeString?URL scheme
hostString?Host name
pathString?Path
queryParametersMap<String, String>?Query parameters

KlpSecurityCheckResult

FieldTypeDescription
allPassedboolWhether all checks passed
checksList<KlpSecurityCheck>Individual probe results (name, passed, errorMessage)

KlpEventPayloadtype, data (map or string), timestamp (ms).

KlpSseEffect — gamification effects with id, ruleName, missionId,
levelId, actionType, and a typed detail object for point grants and
mission progress.

API reference

MethodReturnsDescription
initialize(config)Future<bool>Initialize the SDK and run security checks
setUser(userId, accessToken)Future<bool>Start a user session
logout()Future<bool>End the user session
launch([path])Future<bool>Present the loyalty WebView
logEvent(name, [attributes])Future<bool>Send an engagement event
setTheme(theme)Future<bool>Set theme: system, light, or dark
getAppearance()Future<KlpAppearance>Read current theme and language
setLanguage(languageTag)Future<bool>Set language; null restores system locale
isInitialized()Future<bool>Whether initialization completed
isDeviceSecure()Future<bool>Device integrity verdict
performSecurityChecks()Future<KlpSecurityCheckResult>Detailed security probe results
openDebugScreen()Future<bool>Open the SDK debug interface programmatically

Error handling

SDK errors are surfaced through a typed exception hierarchy:

try {
  await Klp.instance.initialize(
    KlpInitializeConfig(environment: KlpEnvironment.prod),
  );
  await Klp.instance.launch();
} on KlpSecurityException catch (e) {
  for (final check in e.result?.checks ?? const []) {
    if (!check.passed) {
      logSecurityFailure(check.name, check.errorMessage);
    }
  }
} on KlpNotInitializedException {
  // A method was called before initialize() completed
} on KlpPlatformException catch (e) {
  logPlatformError(e.code, e.message);
}
ExceptionError codesTypical cause
KlpSecurityExceptionKLP_INIT_SECURITY_ERROR, KLP_SECURITY_ERRORDevice integrity check failed
KlpNotInitializedExceptionKLP_NOT_INITIALIZEDSDK used before initialization
KlpPlatformExceptionKLP_LAUNCH_ERROR, KLP_SET_USER_ERROR, and othersNative bridge operation failed

Security guidelines

  • Set debugMode: false and showDebugScreen: false in production
  • openDebugScreen() and showDebugScreen are intended for integration testing
    builds only — never enable them in production releases
  • Validate all deep links before acting on them
  • Gate sensitive flows on performSecurityChecks() before calling launch()

Release readiness

Before shipping to production, confirm the following:

  • initialize() is called once before any other SDK method
  • environment is set to prod in release builds
  • debugMode and showDebugScreen are false in release builds
  • Event stream subscriptions are cancelled when no longer needed
  • setUser and logout are connected to your authentication lifecycle
  • Deep links are validated before navigation
  • Sensitive flows are gated on performSecurityChecks()
  • The SDK version is pinned to a release tag in pubspec.yaml


Did this page help you?