blusalt_liveness_native 1.4.9 copy "blusalt_liveness_native: ^1.4.9" to clipboard
blusalt_liveness_native: ^1.4.9 copied to clipboard

Liveness SDK for Android and IOS

example/lib/main.dart

import 'dart:convert';
import 'dart:io';

import 'package:blusalt_liveness_native/enums.dart';
import 'package:blusalt_liveness_native/liveness.dart';
import 'package:blusalt_liveness_native/model.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:liveness_example/json_viewer_widget.dart';

void main() {
  runApp(const MyApp());
}

enum VerificationCompletedType { comparison, detection, none }

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _livenessPlugin = BlusaltLivenessNative();

  String? imageUri;
  TextEditingController clientIdController = TextEditingController();
  TextEditingController appNameController = TextEditingController();
  TextEditingController apiKeyController = TextEditingController();
  TextEditingController webHookUrlController = TextEditingController();
  TextEditingController referenceController = TextEditingController();
  TextEditingController thresholdController = TextEditingController();
  TextEditingController timeoutDurationController = TextEditingController();
  bool isDev = false;

  // If you want to show the score of facial comparison result
  bool isShowScore = false;

  // If you want to show the min required score of facial comparison result
  bool isShowThreshold = false;

  // If you want to start the SDK on getting to the SDK homepage rather than making user click continue button
  bool startProcessOnGettingToFirstScreen = false;

  VerificationCompletedType verificationType = VerificationCompletedType.none;
  final ImagePicker _picker = ImagePicker();

  BlusaltLivenessResultResponse? resultResponse;

  @override
  void dispose() {
    super.dispose();
    clientIdController.dispose();
    appNameController.dispose();
    apiKeyController.dispose();
    webHookUrlController.dispose();
    referenceController.dispose();
    thresholdController.dispose();
    timeoutDurationController.dispose();
  }

  Future<BlusaltLivenessResultResponse?> startFaceComparison() async {
    final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
    if (image != null) {
      setState(() {
        imageUri = image.path;
      });

      resultResponse = await _livenessPlugin.startFacialComparisonSDK(
          apiKey: apiKeyController.text,
          appName: appNameController.text,
          clientId: clientIdController.text,
          isDev: isDev,
          webhookUrl: webHookUrlController.text.isEmpty
              ? null
              : webHookUrlController.text,
          reference: referenceController.text,
          imageData: await image.readAsBytes(),
          startProcessOnGettingToFirstScreen:
              startProcessOnGettingToFirstScreen,
          showScore: isShowScore,
          showThreshold: isShowThreshold,
          thresholdInPercent: validateNumber(thresholdController.text),
          timeoutDurationInSec:
              validateDurationNumber(timeoutDurationController.text));
      if (resultResponse?.blusaltLivenessProcess ==
          BlusaltLivenessProcess.completed) {
        //   Face comparison is successful
        setState(() {
          verificationType = VerificationCompletedType.comparison;
        });
      } else {
        //   Face comparison failed
        debugPrint(resultResponse?.code ?? '');
        debugPrint(resultResponse?.message ?? '');
      }
      return resultResponse;
    }

    return null;
  }

  Future<BlusaltLivenessResultResponse?> startLivenessDetectionOnly() async {
    resultResponse = await _livenessPlugin.startLivenessDetectionOnlySDK(
        apiKey: apiKeyController.text,
        appName: appNameController.text,
        clientId: clientIdController.text,
        isDev: isDev,
        webhookUrl: webHookUrlController.text.isEmpty
            ? null
            : webHookUrlController.text,
        reference: referenceController.text,
        startProcessOnGettingToFirstScreen: startProcessOnGettingToFirstScreen,
        timeoutDurationInSec:
            validateDurationNumber(timeoutDurationController.text));

    if (resultResponse?.blusaltLivenessProcess ==
        BlusaltLivenessProcess.completed) {
      //   Liveness detection is successful
      setState(() {
        verificationType = VerificationCompletedType.detection;
      });
    } else {
      //   Liveness detection failed
      debugPrint(resultResponse?.code ?? '');
      debugPrint(resultResponse?.message ?? '');
    }
    return resultResponse;
  }

  double? validateNumber(String value) {
    if (value.isEmpty) {
      return null;
    }

    return double.tryParse(value);
  }

  int? validateDurationNumber(String value) {
    if (value.isEmpty) {
      return null;
    }

    return int.tryParse(value);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              if (imageUri != null)
                Image.file(
                  File(imageUri!),
                  width: 100,
                  height: 100,
                )
              else
                const Padding(
                  padding: EdgeInsets.only(top: 20),
                  child: Text("No image selected"),
                ),
              const SizedBox(height: 14),
              TextField(
                controller: clientIdController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter client id",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                onChanged: (text) => setState(() {}),
              ),
              const SizedBox(height: 14),
              TextField(
                controller: appNameController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter app name",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                onChanged: (text) => setState(() {}),
              ),
              const SizedBox(height: 14),
              TextField(
                controller: apiKeyController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter api key",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                onChanged: (text) => setState(() {}),
              ),
              const SizedBox(height: 14),
              TextField(
                controller: webHookUrlController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter webhook url (Optional)",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                onChanged: (text) => setState(() {}),
              ),
              const SizedBox(height: 14),
              TextField(
                controller: referenceController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText: "Enter reference (Optional)",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                onChanged: (text) => setState(() {}),
              ),
              const SizedBox(height: 14),
              TextField(
                controller: timeoutDurationController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText:
                      "Enter a duration you want SDK to timeout in seconds (Optional)",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                keyboardType: TextInputType.number,
                inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                maxLines: 2,
              ),
              const SizedBox(height: 4),
              CustomCheckbox(
                label: "Point to Development Environment?",
                value: isDev,
                onCheck: (value) => setState(() => isDev = value),
              ),
              const SizedBox(height: 2),
              CustomCheckbox(
                label: "Start Process On Getting To First Screen?",
                value: startProcessOnGettingToFirstScreen,
                onCheck: (value) =>
                    setState(() => startProcessOnGettingToFirstScreen = value),
              ),
              const SizedBox(height: 34),
              const Text(
                'More Options Specific to Facial Comparison:',
                textAlign: TextAlign.center,
                style: TextStyle(fontSize: 17, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 2),
              CustomCheckbox(
                label: "Show Percent on completion",
                value: isShowScore,
                onCheck: (value) => setState(() => isShowScore = value),
              ),
              const SizedBox(height: 2),
              CustomCheckbox(
                label: "Show Threshold on completion",
                value: isShowThreshold,
                onCheck: (value) => setState(() => isShowThreshold = value),
              ),
              const SizedBox(height: 14),
              TextField(
                controller: thresholdController,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  hintText:
                      "Enter a threshold number for facial comparison which ranges from 0-100 (Optional)",
                  hintStyle: TextStyle(color: Color(0xFFCCCCCC)),
                ),
                keyboardType: TextInputType.number,
                inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                maxLines: 2,
              ),
              const SizedBox(height: 24),
              Row(
                children: [
                  Expanded(
                    child: ElevatedButton(
                      onPressed: startLivenessDetectionOnly,
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.blue,
                        minimumSize: const Size(double.infinity, 50),
                      ),
                      child: const Text(
                        "Start SDK Liveness Detection",
                        textAlign: TextAlign.center,
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ),
                  const SizedBox(width: 16),
                  Expanded(
                    child: ElevatedButton(
                      onPressed: startFaceComparison,
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.blue,
                        minimumSize: const Size(double.infinity, 50),
                      ),
                      child: const Text(
                        "Start SDK Facial Comparison",
                        textAlign: TextAlign.center,
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ),
                ],
              ),
              if (verificationType != VerificationCompletedType.none)
                const SizedBox(height: 34),
              if (verificationType != VerificationCompletedType.none)
                Text(
                  "Result: (${verificationType == VerificationCompletedType.comparison ? 'Facial Comparison' : 'Face Detection'})",
                  textAlign: TextAlign.center,
                  style: const TextStyle(fontWeight: FontWeight.w500),
                ),
              if (verificationType != VerificationCompletedType.none)
                const SizedBox(height: 4),
              if (verificationType != VerificationCompletedType.none)
                JsonViewerWidget(jsonData: resultResponse?.toJson()),
              const SizedBox(height: 34),
              Image.asset(
                'assets/images/blusalt_logo.png',
                width: 100,
                height: 100,
                color: Colors.black,
              ),
              const SizedBox(height: 24),
            ],
          ),
        ),
      ),
    );
  }
}

class CustomCheckbox extends StatelessWidget {
  final String label;
  final bool value;
  final Function(bool) onCheck;

  const CustomCheckbox({
    Key? key,
    required this.label,
    required this.value,
    required this.onCheck,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Checkbox(
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
          value: value,
          onChanged: (newValue) => onCheck(newValue ?? false),
        ),
        Expanded(
            child: Text(
          label,
          style: const TextStyle(fontWeight: FontWeight.w500),
        )),
      ],
    );
  }
}
2
likes
140
points
28
downloads

Publisher

unverified uploader

Weekly Downloads

Liveness SDK for Android and IOS

Homepage

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, flutter_web_plugins

More

Packages that depend on blusalt_liveness_native

Packages that implement blusalt_liveness_native