entrust_idvsdk_flutter 100.10.0 copy "entrust_idvsdk_flutter: ^100.10.0" to clipboard
entrust_idvsdk_flutter: ^100.10.0 copied to clipboard

Entrust Identity SDK Flutter plugin for document and biometric capture.

example/lib/main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:entrust_idvsdk_flutter/entrust_idvsdk_flutter.dart';

import 'smoke_test_page.dart';

const String devtoolVersion = 'main';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Resolved before the first frame so DevToolsPage knows, synchronously, not
  // to build its WebView on an automated run.
  final sdkToken = await readLaunchSdkToken();
  runApp(MyApp(sdkToken: sdkToken));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key, this.sdkToken});

  final String? sdkToken;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'IDV SDK Flutter Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: DevToolsPage(sdkToken: sdkToken),
    );
  }
}

class DevToolsPage extends StatefulWidget {
  const DevToolsPage({super.key, this.sdkToken});

  /// Set only when Maestro launched the app with a token, i.e. on an E2E run.
  final String? sdkToken;

  @override
  State<DevToolsPage> createState() => _DevToolsPageState();
}

class _DevToolsPageState extends State<DevToolsPage> {
  late final WebViewController _webViewController;
  late EntrustIdv _idv;
  bool _isLoading = true;

  /// Mirrors the native demo apps, which only pass `onMedia` through when
  /// DevTools asked for it. Registering it costs a full serialisation of every
  /// captured image across the bridge, so it stays off until requested.
  bool _mediaCallbacksEnabled = false;

  /// The DevTools WebView pulls https://sdk.onfido.com and runs a Chromium
  /// renderer in its own process. On a loaded CI emulator that renderer gets
  /// killed, which takes the whole app down with it. The smoke test needs
  /// neither the network nor a WebView, so it never builds one.
  bool get _isAutomatedRun => widget.sdkToken?.isNotEmpty ?? false;

  @override
  void initState() {
    super.initState();
    _idv = _createIdv();
    if (!_isAutomatedRun) {
      _initializeWebView();
    }
  }

  EntrustIdv _createIdv() {
    return EntrustIdv(
      callbacks: Callbacks(
        onComplete: (result) {
          debugPrint('SDK completed: $result');
          SmokeEvents.publish(const SmokeEvent(SmokeEventKind.complete));
          _injectJavaScript(
            'devtools.callbacks.onComplete(${jsonEncode(_captureResultsToJson(result))})',
          );
        },
        onError: (error) {
          debugPrint('SDK error: ${error.message}');
          SmokeEvents.publish(
            SmokeEvent(SmokeEventKind.error, message: error.message),
          );
          _injectJavaScript(
            'devtools.callbacks.onError(${jsonEncode(error.toJson())})',
          );
        },
        onUserExit: (userAction) {
          debugPrint('User exited: ${userAction.value}');
          SmokeEvents.publish(const SmokeEvent(SmokeEventKind.exit));
          _injectJavaScript(
            'devtools.callbacks.onExit(${jsonEncode(userAction.value)})',
          );
        },
        onMedia: _mediaCallbacksEnabled
            ? (media) {
                debugPrint('Media received: ${media.key}');
                _injectJavaScript(
                  'devtools.callbacks.onMedia(${jsonEncode(media.toJson())})',
                );
              }
            : null,
        onAnalytics: (analytics) {
          debugPrint('Analytics event: ${analytics.identifier}');
          SmokeEvents.publish(const SmokeEvent(SmokeEventKind.analytics));
          _injectJavaScript(
            'devtools.callbacks.onAnalytics(${jsonEncode(analytics.toJson())})',
          );
        },
        biometricsTokenHandler: BiometricsTokenHandler(
          onTokenGenerated: (customerUserHash, encryptedBiometricToken) {
            debugPrint('Biometric token generated for: $customerUserHash');
            _injectJavaScript(
              "devtools.callbacks.biometricsTokenHandler.onTokenGenerated('$customerUserHash', '$encryptedBiometricToken')",
            );
          },
          onTokenRequested: (customerHash) {
            debugPrint('Biometric token requested for: $customerHash');
            _injectJavaScript(
              "devtools.callbacks.biometricsTokenHandler.onTokenRequested('$customerHash')",
            );
            // Return a placeholder token - in real app this would come from storage
            return 'new wrong token';
          },
        ),
      ),
    );
  }

  /// Applies the DevTools `enableMediaCallbacks` switch.
  ///
  /// The callback set is fixed when [EntrustIdv] is constructed and is handed
  /// to the native SDK there, so the instance is replaced rather than mutated.
  /// Disposing first matters: both instances share one method channel, and the
  /// old one clears its handler on the way out.
  void _applyMediaCallbacks({required bool enabled}) {
    if (enabled == _mediaCallbacksEnabled) {
      return;
    }
    _mediaCallbacksEnabled = enabled;
    _idv.dispose();
    _idv = _createIdv();
  }

  void _initializeWebView() {
    _webViewController = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageFinished: (String url) {
            setState(() {
              _isLoading = false;
            });
          },
          onWebResourceError: (WebResourceError error) {
            debugPrint('WebView error: ${error.description}');
          },
        ),
      )
      ..addJavaScriptChannel(
        '_devtools',
        onMessageReceived: (JavaScriptMessage message) {
          _handleWebViewMessage(message.message);
        },
      )
      ..loadRequest(
        Uri.parse(
          'https://sdk.onfido.com/capture/devtools/$devtoolVersion?mode=webview',
        ),
      );
  }

  void _handleWebViewMessage(String message) {
    try {
      final devtoolsConfig = jsonDecode(message) as Map<String, dynamic>;
      debugPrint('Flutter webview received config: $devtoolsConfig');

      if (devtoolsConfig.containsKey('parameter')) {
        final configuration = devtoolsConfig['configuration'];
        if (configuration is Map) {
          _applyMediaCallbacks(
            enabled: configuration['enableMediaCallbacks'] == true,
          );
        }

        final parameter = devtoolsConfig['parameter'] as Map<String, dynamic>;
        final sdkParams = sdkParametersFromJson(parameter);
        _idv.start(sdkParams);
      }
    } catch (e) {
      debugPrint('Error parsing webview message: $e');
    }
  }

  void _injectJavaScript(String script) {
    if (_isAutomatedRun) {
      return;
    }
    _webViewController.runJavaScript(script);
  }

  Map<String, dynamic> _captureResultsToJson(
    Map<String, CaptureResult> results,
  ) {
    return results.map((key, value) => MapEntry(key, value.toJson()));
  }

  @override
  void dispose() {
    _idv.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('IDV SDK DevTools'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        actions: [
          TextButton(
            key: const Key('open-smoke-test'),
            onPressed: () => Navigator.of(context).push(
              MaterialPageRoute<void>(
                builder: (_) => SmokeTestPage(idv: _idv),
              ),
            ),
            child: const Text('Smoke test'),
          ),
        ],
      ),
      body: _isAutomatedRun
          ? const Center(child: Text('DevTools disabled for the automated run'))
          : Stack(
              children: [
                WebViewWidget(controller: _webViewController),
                if (_isLoading)
                  const Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        CircularProgressIndicator(),
                        SizedBox(height: 16),
                        Text('Loading DevTools...'),
                      ],
                    ),
                  ),
              ],
            ),
    );
  }
}
0
likes
140
points
30
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Entrust Identity SDK Flutter plugin for document and biometric capture.

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on entrust_idvsdk_flutter

Packages that implement entrust_idvsdk_flutter