• About TrustVision
  • Android SDK
  • iOS SDK
  • React Native SDK
  • Web SDK
  • API Client Libraries
  • eKYC Platform
  • Integration Case Studies
  • TS eKYC/FA App
TrustVision API Documentation

Flutter 3.3.x uionly

Environment

Flutter

Flutter SDK ">=2.12.0 <3.0.0"

iOS

iOS 11 and above

Xcode ">=12 <=14.2"

Android

  • Gradle Version 7.2.2
  • Tested with Gradle Plugin for Android Studio - version Android Studio Electric Eel | 2022.1.1 Patch 2
  • minSdkVersion 21
  • targetSdkVersion 33

Installation

Common

1. Add Trust Vision Flutter lib

Add to pubspec.yaml file under dependencies group:

  trust_vision_plugin:
    git:
     # Replace the below with your specific info
      url: to_be_replaced
      ref: to_be_replaced

2. Precompile

$ flutter pub get

iOS

1. Add to podfile

# Add below lines to the end of podfile
post_install do |installer|
    installer.pods_project.targets.each do |target|
        // you can add more modules which have the error "Undefined symbol" into the list
        if ['CocoaLumberjack', 'TensorFlowLiteC', 'TensorFlowLiteSwift', 'PromiseKit', 'lottie-ios'].include? "#{target}"
            target.build_configurations.each do |config|
                config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
            end
        end
    end
end

2. Setup Xcode

Set Build Libraries for Distribution in Build Settings to No

alt text

3. Precompile

$ pod install

Android

Add to root-level build.gradle file (host app):

groovy
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

allprojects {
    repositories {
        google()
        mavenCentral()

        /*
        Replace the below with your path to `trust_vision_plugin` Android repo which downloaded by `flutter pub get`.
        */
        maven { url "$flutterRoot/.pub-cache/git/replace_by_git_repo_name-replace_by_commit_hash/android/repo" }
        /*
        For example:
        maven { url "$flutterRoot/.pub-cache/git/tv_flutter_sdk_xyz-1a5eb61ccb44ffafa4d3557f4d9d8087bc1a4666/android/repo" }
        */
    }
}

Add to app/build.gradle:

groovy
aaptOptions {
    noCompress "tflite"
    noCompress "lite"
}

Usage

dart
import 'package:trust_vision_plugin/enums.dart';
import 'package:trust_vision_plugin/trust_vision_plugin.dart';

1. Initialize SDK

Before using any TV SDK functions, it needs to be successfully initialized once.

dart
  void _initSDK() async {
    try {
      var initResult = await TrustVisionPlugin.instance.initialize(
        jsonConfigurationByServer: jsonConfigurationByServer,
        languageCode: 'vi',
      );
      print("Init Result: $initResult");
    } catch (exception) {
      print("Handle exception: $exception");
    }
  }

where:

  • jsonConfigurationByServer: String. It's the setting specialized for each client from TS server. It's the response json string get by API https://ekyc.trustingsocial.com/api-reference/customer-api/#get-client-settings. When it's null or unmatched with the expected type then the default setting in the SDK will be used.
  • languageCode: String the code of the language that will show and sound to user. E.g Vietnamese (vi), English (en).

2. ID card capturing

2.1. Configuration

Change the following parameters to suit your needs.

dart

void _captureIdCard() async {
    try {

      TVCardType cardType = TVCardType(
        id: "vn.national_id",
        name: "CMND cũ / CMND mới / CCCD / Hộ chiếu",
        hasBackSide: true,
        orientation: TVCardOrientation.HORIZONTAL,
      );

      CardSide cardSide = CardSide.front; // CardSide.back

      Map<String, dynamic> idCardConfig = {
        "cardTypes": [cardType.toMap()],
        "cardSide": cardSide.name,
        "isEnableSound": true,
        "isEnableSanityCheck": true,
        "isReadBothSide": false,
        "skipConfirmScreen": true,
        "isEnableDetectingIdCardTampering": true,
      };

      // Start ID card capturing
      TVDetectionResult? result = await TrustVisionPlugin.instance.captureIdCard(idCardConfig);

      print("_captureIdCard result: $result");

    } catch (exception) {
      print("Handle exception: $exception");
    }
  }

Where:

  • cardType: TVCardType
  • cardSide: CardSide (back, front)
  • isEnableSound: bool. enable/disable guiding sound
  • isEnableSanityCheck: bool. Id card sanity checking should be enabled or not
  • isReadBothSide: bool. whether or not read both sides of the selected id card at one flow
  • skipConfirmScreen: bool. Whether or not TV SDK should skip its own confirmation screen.
  • isEnableDetectingIdCardTampering: bool. enable/disable ID card tampering detection

2.2. Start ID card capturing

dart
TVDetectionResult? result = await TrustVisionPlugin.instance.captureIdCard(idCardConfig);

2.2. Handle id result

2.2.1 Get front image

dart
var idFrontImage = result?.idFrontImage;
 // TODO call your api to upload image

2.2.2 Get back image

dart
var idBackImage = result?.idBackImage;
 // TODO call your api to upload image

2.2.3 Get qr image

dart
 var frontIdQr = result?.frontIdQr;
  // TODO call your api to upload image

3. Selfie capturing

3.1. Configuration

Change the following parameters to suit your needs.

dart
 void _captureSelfie() async {
    try {

      LivenessMode livenessMode = LivenessMode.active; // or LivenessMode.passive
      SelfieCameraMode selfieCameraMode = SelfieCameraMode.back; // or SelfieCameraMode.front, SelfieCameraMode.back

      final selfieConfig = {
        "cameraOption": selfieCameraMode.name,
        "livenessMode": livenessMode.name,
        "isEnableSound": true,
        "isEnableSanityCheck": false,
        "isEnableVerifyLiveness": false,
        "skipConfirmScreen": true
      };

      // Start Selfie capturing
       TVDetectionResult? result = await TrustVisionPlugin.instance.captureSelfie(
        selfieConfig,
        onNewFrameBatch: (TvFrameBatch frameBatch) {
          // Handle frame batch
          // Refer: https://ekyc.trustingsocial.com/sdks/Android-SDK#303-handle-onnewframebatch-callback
        },
      );

      print("_captureSelfie result: $result");
    } catch (exception) {
      print("Handle exception: $exception");
    }
  }

Where:

  • onNewFrameBatch: Function(TvFrameBatch)?. This callback function can be called multiple times during the capturing process to return frames.
  • livenessMode: LivenessMode. Liveness mode
  • cameraOption: SelfieCameraMode. Camera side
  • isEnableSound: bool. enable/disable guiding sound
  • isEnableSanityCheck: bool. Selfie sanity checking should be enabled or not
  • skipConfirmScreen: bool. Whether or not TV SDK should skip its own confirmation screen.

3.2. Start Selfie capturing

dart
TVDetectionResult? result = await TrustVisionPlugin.instance.captureSelfie(selfieConfig);

3.3. Handle selfie result

Please don't remove any item from result.selfieImages list

3.3.1. Get frontal images
dart
    var selfieImages = result?.selfieImages;
    var frontalImages = <TVImageClass?>[];
    selfieImages?.forEach((item) {
      if(item.frontalImage?.rawImageBase64 != null) {
        // Get frontal image
        frontalImages.add(item.frontalImage);
      }
    });
    // TODO call your api to upload image
3.3.2. Get final frontal image (frontal step)
dart
    var selfieImages = result?.selfieImages;
    var finalFrontalImage = selfieImages?.firstWhere((item) => item.gestureType?.toLowerCase() == 'frontal').frontalImage;
3.3.3. Get gesture images
dart
    var selfieImages = result?.selfieImages;
    var gestureImages = <TVImageClass?>[];
    selfieImages?.forEach((item) {
      if(item.gestureImage?.rawImageBase64 != null) {
        // Get gesture image
        gestureImages.add(item.gestureImage);
      }
    });
     // TODO call your api to upload image

4. NFC reader

4.1. Configuration

Change the following parameters to suit your needs.

dart
void _readNfc() async {

  try {
     var nfcCode = "last 6 digits of CCCD number";
      final nfcConfig = {
        "nfcCode": nfcCode,
        "isRequestReadImageNfc": true,
        "isRequestCloneDetectionNfc": true,
        "isRequestIntegrityCheckNfc": true,
        "nfcMaxRetries": 5
      };

      // Start NFC reader
      TVDetectionResult? result = await TrustVisionPlugin.instance.readNfc(nfcConfig);

      print("_captureSelfie result: $result");
    } catch (exception) {
      print("Handle exception: $exception");
    }
  }

Where:

  • nfcCode: String. Last 6 digits of CCCD number
  • isRequestReadImageNfc: bool. enable/disable read image from CCCD
  • isRequestCloneDetectionNfc: bool. enable/disable check clone check
  • isRequestIntegrityCheckNfc: bool. enable/disable integrity check
  • nfcMaxRetries: bool. Retry count when NFC error

4.2. Start NFC reader

dart
  TVDetectionResult? result = await TrustVisionPlugin.instance.readNfc(nfcConfig);

5. Result Handling:

5.1. Result Object:

  • result: .TVDetectionResult:

    • cardType: TVCardType. Card type
    • actionMode: TVActionMode. Action Mode
    • cardInfoResult: TVCardInfoResult. Card information result
    • livenessResult: TVLivenessResult. Liveness result
    • idSanityResult: TVSanityResult. Id card sanity result
    • selfieSanityResult: TVSanityResult. Selfie sanity result
    • idTamperingResult: TVSanityResult. ID tampering result
    • selfieImages: [SelfieImage]. List of selfie image objects
    • idFrontImage: TVImageClass. Id front image object
    • idBackImage: TVImageClass. Id back image object
    • frontIdQr: TVCardQr. Card's QR Code image.
    • nfcInfoResult: TVNfcInfoResult. Card NFC information
    • selfieVideos: [Uint8List]. Liveness video data
    • livenessFrameBatchIds: [String]. Liveness valid frame batch id
  • SelfieImage:

    • gestureImage: String. UP | DOWN | LEFT | RIGHT | FRONTAL
    • frontalImage: TVImageClass. Frontal image object
    • gestureImage: TVImageClass. Gesture image object
  • TVImageClass:

    • rawImageBase64: String. Base64 string of image data
    • encryptedImageHexString: String. Encrypted base64 string of image data
    • imageId: String. Image id
    • metadata:Map<String, dynamic>. Metadata of the image
  • TVCardInfoResult:

    • infos: [Info] array of Info
    • requestId: String. Id of request
  • Info:

    • field: String. Name of field example name, address...
    • value: String. The value of each field
  • TVLivenessResult:

    • score: float. The score from 0 to 1
    • isLive: bool. Selfie image is live or not
    • requestId: String. Id of request
  • TVSanityResult:

    • isGood: bool. Sanity is good or not
    • score: float. The score from 0 to 1
    • requestId: String. Id of request
    • error: String. Error message
    • details: [Detail]. List of result detail
  • Detail:

    • name: String. Name of field
    • score: String. The score from 0 to 1
    • verdict: String. Verdict of field
  • TVCardQr:

    • images: [TVImageClass]. List of image
    • isRequired: bool.

    if isRequired is true then images array should be non-empty. Otherwise, clients should be warned to re-capture id card photos.

  • TVNfcInfoResult:

    • requestId: String. Id of request
    • com: String. Com data
    • sod: String. Sod data
    • dg1: String. Dg1 data
    • dg2: String. Dg2 data
    • dg13: String. Dg13 data
    • dg14: String. Dg14 data
    • dg15: String. Dg15 data
    • infos: [Info]. array of Info
    • verificationResult: TVNfcVerificationStatus. Verification result data
  • TVNfcVerificationResult:

    • verdict: String. Result's verdict
    • cloneStatus: TVNfcVerificationStatus. Clone status
    • integrityStatus: TVNfcVerificationStatus. Integrity status
    • bcaStatus: TVNfcVerificationStatus. BCA status (BCA is Bộ Công An)
  • TVNfcVerificationStatus:

    • verdict: TVNfcVerificationStatusVerdict | UNKNOWN,NOT_PRESENT,NOT_CHECKED,ALERT,GOOD,ERROR. Result's verdict
    • error: TVDetectionError. Error detail
  • TvFrameBatch:

    • id: String?. Frame's id
    • frames: [TvFrameClass]. Batch of framed to be pushed
    • metadata: Map<String, dynamic>. Batch metadata to push
    • validVideoIds: [String]. For debugging purpose only
  • TvFrameClass:

    • index: int?. Index of this frame in the list of recorded frames
    • base64: String?. The data of the frame as a base64 String
    • label: String. Label of this frame
  • TVDetectionError:

    • errorCode: int. Error code
    • detailErrorCode: String. Detail for error code
    • errorDescription: String. Error description

5.2. Sanity result error handling

5.2.1. Id sanity
dart
 String? error = result?.idSanityResult?.error;
if (error != null) {
    switch (result.idSanityResult.error) {
        case 'image_too_blur':
            // Image is too blurry
            break;
        case 'image_too_dark':
            // Image is too dark
            break;
        case 'image_too_bright':
            // Image is too bright
            break;
        case 'image_has_hole':
            // Image has holes
            break;
        case 'image_has_cut':
            // Images has been cut
            break;
        case 'image_has_hole_and_cut':
            // Images has holes and has been cut
            break;
    }
}
5.2.2. Selfie sanity
dart
 String? error = result?.selfieSanityResult?.error;
if (error != null) {
    switch (selfieSanityResult["error"]) {
        case 'image_too_blur':
            // Image is too blurry
            break;
        case 'image_too_dark':
            // Image is too dark
            break;
        case 'image_too_bright':
            // Image is too bright
            break;
        case 'not_white_background':
            // The background is not white enough
            break;
        case 'not_qualified':
            // The face is not qualified, could be occluded, covered or having something unusal
            break;
        case 'image_has_multiple_faces':
            // Image has multiple faces
            break;
        case 'image_has_no_faces':
            // Image does not have any face
            break;
        case 'right':
            // Face is looking to the right
            break;
        case 'left':
            // Face is looking to the left
            break;
        case 'open_eye,closed_eye':
            // Right eye is closed
            break;
        case 'closed_eye,open_eye':
            // Left eye is closed
            break;
        case 'open_eye,sunglasses':
            // Sunglass covers the right eye
            break;
        case 'sunglasses,open_eye':
            // Sunglass covers the left eye
            break;
        case 'closed_eye,closed_eye':
            // Both eyes are closed
            break;
        case 'closed_eye,sunglasses':
            // Left eye is closed, sunglass covers the right eye
            break;
        case 'sunglasses,closed_eye':
            // Sunglass covers the right eye, right eye is closed
            break;
        case 'sunglasses,sunglasses':
            // Sunglasses cover both eyes
            break;
    }
}

6. Error handling

dart
 switch (e.code) {
            // connection errors
            case 'timeout_error'
            break;
                // Network timeout. Poor internet connection.
            case 'network_error':
                // Network error. No internet connection
            break;
            // Id capturing
            case 'incorrect_card_type':
                // the input image is not same type with selected card
                break;
            case 'nocard_or_multicard_image':
                // the input image is no card or multicard detected
                break;

            // Selfie capturing
            case 'image_has_no_faces':
                // face not detected in selfie image
                break;
            case 'image_has_multipe_faces':
                // multiple faces are detected in selfie image
                break;

            // Common errors
            case 'access_denied_exception':
                break;
            case 'invalid_parameter_exception':
                break;
            case 'rate_limit_exception':
                break;
            case 'internal_server_error':
                break;

            case: 'sdk_canceled':
              break;
        }