SDK Reference

Flutter / Dart

Native Flutter SDK with widget integration, reactive flag rendering, and automatic Flutter error capture. Works on iOS, Android, web, and desktop.

Installation

pubspec.yaml
dependencies:
  toggleai: ^1.0.0
  # Or use path for local development:
  # toggleai:
  #   path: ../dart_sdk
bash
flutter pub get

Basic Setup

The Flutter SDK is designed to work in fluid harmony with ToggleAI backend services, fully optimizing mobile performance, battery usage, and network efficiency. Flag resolutions are handled through two powerful patterns:

⚡ In-Memory Evaluation (60fps widget rebuilds)

When wrapped in ToggleAIProvider, the SDK fetches the environment config payload from GET /sdk/config on startup. In-memory local evaluations (e.g. within a reactive FlagBuilder) are calculated instantly under sub-millisecond speeds—ensuring silky, jank-free 60fps widget rendering.

🛰️ Edge Remote Evaluation

For security-sensitive actions demanding absolute, real-time resolution (bypassing client-side caches entirely), client.evaluateFlagRemote() makes a direct network query to the edge endpoint POST /sdk/evaluate, returning fresh determinations.

main.dart
import 'package:flutter/material.dart';
import 'package:toggleai/dart_sdk.dart';

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

  final client = ToggleAIClient(
    options: ToggleAIOptions(
      clientId: 'pk_live_xxx',
      secret: 'sk_live_xxx',
      pollingInterval: Duration(seconds: 30),
      onReady: () => print('ToggleAI ready'),
      onError: (e) => print('ToggleAI error: $e'),
    ),
  );

  // Capture Flutter framework errors
  final logger = client.getLogger();
  FlutterError.onError = logger.captureFlutterError;

  runApp(
    ToggleAIProvider(
      client: client,
      loadingBuilder: (_) => const MaterialApp(
        home: Scaffold(body: Center(child: CircularProgressIndicator())),
      ),
      child: const MyApp(),
    ),
  );
}

Widget Integration

FlagBuilder

Reactive widget that rebuilds when a flag value changes (on config refresh).

dart
FlagBuilder(
  flagKey: 'new-checkout-ui',
  userId: 'user_42',
  attributes: {'plan': 'pro', 'country': 'US'},
  builder: (context, enabled, evaluation) {
    print('Reason: ${evaluation.reason}');
    return enabled
        ? const NewCheckoutScreen()
        : const LegacyCheckoutScreen();
  },
)

ConfigBuilder

Reactive widget for remote config values.

dart
ConfigBuilder<String>(
  configKey: 'app_theme',
  defaultValue: 'light',
  builder: (context, theme) => Text('Current theme: $theme'),
)

Access Client Anywhere

dart
// In any widget below ToggleAIProvider:
final client = ToggleAIProvider.of(context);
final isDarkMode = client.getFlag('dark-mode');
final timeout = client.getConfig<int>('api_timeout_ms', defaultValue: 5000);

ToggleAIMixin

Convenience mixin for StatefulWidgets — provides getFlag() and getConfig() directly.

dart
class _HomeState extends State<HomeScreen> with ToggleAIMixin {
  @override
  Widget build(BuildContext context) {
    final showBanner = getFlag(context, 'promo-banner');
    final bannerText = getConfig<String>(context, 'promo_text', defaultValue: '');

    return Column(
      children: [
        if (showBanner) PromoBanner(text: bannerText),
        // ... rest of UI
      ],
    );
  }
}

Android Configuration

The Flutter SDK works on Android out of the box. For optimal performance:

Minimum SDK Version

android/app/build.gradle
android {
    defaultConfig {
        minSdkVersion 21  // Required for HTTP/2 support
    }
}

// If using ProGuard/R8, no special rules needed —
// the SDK uses only dart:core and package:http.

Network Security (Debug)

If testing against a local backend over HTTP (not HTTPS):

android/app/src/debug/AndroidManifest.xml
<application android:usesCleartextTraffic="true">
  <!-- Only for local development -->
</application>

iOS Configuration

No special iOS configuration needed. The SDK uses package:http which relies onNSURLSession under the hood.

ios/Runner/Info.plist
<!-- Only if you need to connect to non-HTTPS endpoints (dev) -->
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Flutter Error Capture

The SDK provides native Flutter error interception:

dart
// Capture Flutter widget/layout errors
FlutterError.onError = logger.captureFlutterError;

// Capture Dart zone errors (uncaught async exceptions)
runZonedGuarded(() {
  runApp(const MyApp());
}, (error, stackTrace) {
  logger.captureError(error, stackTrace: stackTrace);
});

// Manual exception capture
try {
  await riskyOperation();
} catch (error, stackTrace) {
  logger.captureError(
    error,
    stackTrace: stackTrace,
    context: {'screen': 'checkout', 'userId': 'u_42'},
  );
}

ToggleAIOptions

OptionTypeDefault
clientIdStringrequired
secretStringrequired
baseUrlStringhosted URL
pollingIntervalDuration30 seconds
evaluationModeEvaluationMode.local
disableCacheboolfalse
defaultContextEvaluationContext?null
timeoutDuration10 seconds
onReadyFunction?null
onConfigUpdateFunction?null
onErrorFunction?null

API Reference

MethodReturnsDescription
init()Future<void>Fetch config, start polling
close()Future<void>Stop polling, flush logs
refresh()Future<void>Manually refresh config
waitForReady()Future<void>Wait for initialization
getFlag(key, {userId, attrs, default})boolBoolean flag, local
getFlagAsync(key, ...)Future<bool>Boolean flag, server if needed
getFlagValue<T>(key, ...)T?Typed flag value
getEvaluation(key, {context})FlagEvaluationResultFull evaluation
evaluateAllFlags({context})Map<String, ...>All flags, local
evaluateFlagRemote(key, ...)Future<...>Server-side eval
getConfig<T>(key, {default})T?Typed config value
getAllConfigs()Map<String, dynamic>All configs
hasConfig(key)boolCheck if key exists
getLogger()ToggleAILoggerGet attached logger