How to Build a Flutter MRZ and VIN Scanner for Android, iOS, Web, Windows, and Linux
Benefiting from the cross-platform nature of Dynamsoft Capture Vision, we created flutter_ocr_sdk to enable MRZ recognition across Android, iOS, Web, Windows, and Linux. With the latest version of Dynamsoft Capture Vision, the plugin now supports VIN scanning as well, offering unified APIs across all platforms. In this article, we’ll cover how to add VIN capabilities to the existing Flutter plugin and how to build a cross-platform MRZ and VIN scanner app for Android, iOS, Web, Windows, and Linux. Flutter MRZ/VIN Scanner Demo Android iOS Web Windows Linux Integrating Dynamsoft Capture Vision SDKs In the following sections, we’ll walk through how to integrate Dynamsoft Capture Vision SDKs for each supported platform. Desktop Integration Download and unzip the Dynamsoft Capture Vision C++ SDK. Due to the 100MB size limitation on pub.dev, we compress the model and template files into a zip archive and download it at runtime on on Windows and Linux. import 'dart:io'; import 'package:path/path.dart' as p; import 'package:http/http.dart' as http; import 'package:archive/archive.dart'; const _zipUrl = 'https://github.com/yushulx/flutter_ocr_sdk/releases/download/v2.0.0/resources.zip'; const _zipName = 'resources.zip'; Future download() async { final execDir = Directory(p.dirname(Platform.resolvedExecutable)); final targetDir = Platform.isWindows ? execDir : Directory(p.join(execDir.path, 'lib')); targetDir.createSync(recursive: true); final cacheDir = Directory(p.join(Directory.systemTemp.path, 'flutter_ocr_sdk')); cacheDir.createSync(recursive: true); final zipCacheFile = File(p.join(cacheDir.path, _zipName)); if (!zipCacheFile.existsSync()) { stdout.writeln('Downloading resources.zip to ${zipCacheFile.path} …'); final resp = await http.get(Uri.parse(_zipUrl)); if (resp.statusCode != 200) { stderr.writeln('Failed to download ($_zipUrl): HTTP ${resp.statusCode}'); exit(1); } zipCacheFile.writeAsBytesSync(resp.bodyBytes); stdout.writeln('✅ Cached zip in temp.'); } else { stdout.writeln('✅ Using cached zip: ${zipCacheFile.path}'); } final bytes = zipCacheFile.readAsBytesSync(); final archive = ZipDecoder().decodeBytes(bytes); for (final file in archive) { final outPath = p.join(targetDir.path, file.name); if (file.isFile) { final outFile = File(outPath); outFile.createSync(recursive: true); outFile.writeAsBytesSync(file.content as List); } else { Directory(outPath).createSync(recursive: true); } } stdout.writeln('✅ Resources unpacked to: ${targetDir.path}'); } Windows Copy *.h, *.lib and *.dll files to your Flutter project Windows directory. flutter_ocr_sdk/windows/include flutter_ocr_sdk/windows/lib. flutter_ocr_sdk/windows/bin Update CMakeLists.txt in the windows directory: cmake_minimum_required(VERSION 3.14) set(PROJECT_NAME "flutter_ocr_sdk") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "flutter_ocr_sdk_plugin") link_directories("${PROJECT_SOURCE_DIR}/lib/") list(APPEND PLUGIN_SOURCES "flutter_ocr_sdk_plugin.cpp" "flutter_ocr_sdk_plugin.h" ) add_library(${PLUGIN_NAME} SHARED "include/flutter_ocr_sdk/flutter_ocr_sdk_plugin_c_api.h" "flutter_ocr_sdk_plugin_c_api.cpp" ${PLUGIN_SOURCES} ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_compile_options(${PLUGIN_NAME} PRIVATE /wd4121 /W3 /WX-) target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin "DynamsoftCorex64" "DynamsoftLicensex64" "DynamsoftCaptureVisionRouterx64" "DynamsoftUtilityx64") set(flutter_ocr_sdk_bundled_libraries "${PROJECT_SOURCE_DIR}/bin/" PARENT_SCOPE ) Linux Copy *.h, *.so files to your Flutter project Linux directory. flutter_ocr_sdk/linux/include flutter_ocr_sdk/linux/lib Update CMakeLists.txt in the linux directory: cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "flutter_ocr_sdk") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "flutter_ocr_sdk_plugin") link_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib") add_library(${PLUGIN_NAME} SHARED "flutter_ocr_sdk_plugin.cc" ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter "DynamsoftCore" "DynamsoftLicense" "DynamsoftCaptureVisionRouter" "DynamsoftUtility") target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) set_target_properties(${PLUGIN_NAME} P

Benefiting from the cross-platform nature of Dynamsoft Capture Vision, we created flutter_ocr_sdk to enable MRZ recognition across Android, iOS, Web, Windows, and Linux. With the latest version of Dynamsoft Capture Vision, the plugin now supports VIN scanning as well, offering unified APIs across all platforms. In this article, we’ll cover how to add VIN capabilities to the existing Flutter plugin and how to build a cross-platform MRZ and VIN scanner app for Android, iOS, Web, Windows, and Linux.
Flutter MRZ/VIN Scanner Demo
-
Android
-
iOS
-
Web
-
Windows
-
Linux
Integrating Dynamsoft Capture Vision SDKs
In the following sections, we’ll walk through how to integrate Dynamsoft Capture Vision SDKs for each supported platform.
Desktop Integration
Download and unzip the Dynamsoft Capture Vision C++ SDK.
Due to the 100MB size limitation on pub.dev, we compress the model and template files into a zip archive and download it at runtime on on Windows and Linux.
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:http/http.dart' as http;
import 'package:archive/archive.dart';
const _zipUrl =
'https://github.com/yushulx/flutter_ocr_sdk/releases/download/v2.0.0/resources.zip';
const _zipName = 'resources.zip';
Future<void> download() async {
final execDir = Directory(p.dirname(Platform.resolvedExecutable));
final targetDir =
Platform.isWindows ? execDir : Directory(p.join(execDir.path, 'lib'));
targetDir.createSync(recursive: true);
final cacheDir =
Directory(p.join(Directory.systemTemp.path, 'flutter_ocr_sdk'));
cacheDir.createSync(recursive: true);
final zipCacheFile = File(p.join(cacheDir.path, _zipName));
if (!zipCacheFile.existsSync()) {
stdout.writeln('Downloading resources.zip to ${zipCacheFile.path} …');
final resp = await http.get(Uri.parse(_zipUrl));
if (resp.statusCode != 200) {
stderr.writeln('Failed to download ($_zipUrl): HTTP ${resp.statusCode}');
exit(1);
}
zipCacheFile.writeAsBytesSync(resp.bodyBytes);
stdout.writeln('✅ Cached zip in temp.');
} else {
stdout.writeln('✅ Using cached zip: ${zipCacheFile.path}');
}
final bytes = zipCacheFile.readAsBytesSync();
final archive = ZipDecoder().decodeBytes(bytes);
for (final file in archive) {
final outPath = p.join(targetDir.path, file.name);
if (file.isFile) {
final outFile = File(outPath);
outFile.createSync(recursive: true);
outFile.writeAsBytesSync(file.content as List<int>);
} else {
Directory(outPath).createSync(recursive: true);
}
}
stdout.writeln('✅ Resources unpacked to: ${targetDir.path}');
}
Windows
-
Copy
*.h
,*.lib
and*.dll
files to your Flutter project Windows directory.-
flutter_ocr_sdk/windows/include
-
flutter_ocr_sdk/windows/lib
. flutter_ocr_sdk/windows/bin
-
-
Update
CMakeLists.txt
in thewindows
directory:
cmake_minimum_required(VERSION 3.14) set(PROJECT_NAME "flutter_ocr_sdk") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "flutter_ocr_sdk_plugin") link_directories("${PROJECT_SOURCE_DIR}/lib/") list(APPEND PLUGIN_SOURCES "flutter_ocr_sdk_plugin.cpp" "flutter_ocr_sdk_plugin.h" ) add_library(${PLUGIN_NAME} SHARED "include/flutter_ocr_sdk/flutter_ocr_sdk_plugin_c_api.h" "flutter_ocr_sdk_plugin_c_api.cpp" ${PLUGIN_SOURCES} ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_compile_options(${PLUGIN_NAME} PRIVATE /wd4121 /W3 /WX-) target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin "DynamsoftCorex64" "DynamsoftLicensex64" "DynamsoftCaptureVisionRouterx64" "DynamsoftUtilityx64") set(flutter_ocr_sdk_bundled_libraries "${PROJECT_SOURCE_DIR}/bin/" PARENT_SCOPE )
Linux
-
Copy
*.h
,*.so
files to your Flutter project Linux directory.-
flutter_ocr_sdk/linux/include
flutter_ocr_sdk/linux/lib
-
-
Update
CMakeLists.txt
in thelinux
directory:
cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "flutter_ocr_sdk") project(${PROJECT_NAME} LANGUAGES CXX) set(PLUGIN_NAME "flutter_ocr_sdk_plugin") link_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib") add_library(${PLUGIN_NAME} SHARED "flutter_ocr_sdk_plugin.cc" ) apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter "DynamsoftCore" "DynamsoftLicense" "DynamsoftCaptureVisionRouter" "DynamsoftUtility") target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) set_target_properties(${PLUGIN_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN" ) set(flutter_ocr_sdk_bundled_libraries "" PARENT_SCOPE ) install(DIRECTORY "${PROJECT_SOURCE_DIR}/../linux/lib/" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" )
Mobile Integration
Android
Add the following dependencies in android/build.gradle
:
dependencies {
implementation "com.dynamsoft:dynamsoftcapturevisionbundle:2.6.1003"
implementation "com.dynamsoft:dynamsoftmrz:3.4.20"
implementation "com.dynamsoft:dynamsoftvin:3.4.20"
}
The dynamsoftcapturevisionbundle
contains the core engine, while dynamsoftmrz
and dynamsoftvin
provide models for MRZ and VIN recognition respectively.
iOS
Add the following dependencies in ios/flutter_ocr_sdk.podspec
:
s.dependency 'DynamsoftVIN', '3.4.20'
s.dependency 'DynamsoftMRZ', '3.4.20'
s.dependency 'DynamsoftCaptureVisionBundle', '2.6.1004'
Web Integration
Include the JavaScript library in index.html
:
API Overview and Implementation
The Flutter plugin provides the following four methods:
Method | Description | Parameters | Return Type |
---|---|---|---|
Future |
Initializes the OCR SDK with a license key. |
key : License string |
Future |
Future |
Performs OCR on a raw image buffer. |
bytes : RGBA image buffer width , height : Image dimensions stride : Row bytes format : Pixel format index rotation : 0/90/180/270 |
Future |
Future |
Performs OCR on an image file. |
filename : Path to the image file |
Future |
Future |
Loads the OCR model by type (mrz or vin ). |
modelType : Optional, defaults to ModelType.mrz
|
Future |
To switch between MRZ and VIN scanning, call loadModel
with the appropriate ModelType
before using the recognition methods. Both recognizeBuffer
and recognizeFile
return a list of recognized lines, each containing either MRZ or VIN data.
The OcrLine
class is defined as follows:
import 'mrz_result.dart';
import 'vin_result.dart';
class OcrLine {
int confidence = 0;
String text = '';
int x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0, x4 = 0, y4 = 0;
MrzResult? mrzResult;
VinResult? vinResult;
@override
String toString() {
String result = '';
result += 'Confidence: $confidence\n';
result += 'Text: $text\n';
result += 'x1: $x1\n';
result += 'y1: $y1\n';
result += 'x2: $x2\n';
result += 'y2: $y2\n';
result += 'x3: $x3\n';
result += 'y3: $y3\n';
result += 'x4: $x4\n';
if (mrzResult != null) {
result += mrzResult.toString();
}
if (vinResult != null) {
result += vinResult.toString();
}
return result;
}
}
class MrzResult {
String? type;
String? nationality;
String? surname;
String? givenName;
String? docNumber;
String? issuingCountry;
String? birthDate;
String? gender;
String? expiration;
String? lines;
MrzResult(
{String? type,
String? nationality,
String? surname,
String? givenName,
String? docNumber,
String? issuingCountry,
String? birthDate,
String? gender,
String? expiration,
String? lines})
: this.type = type ?? 'N/A',
this.nationality = nationality ?? 'N/A',
this.surname = surname ?? 'N/A',
this.givenName = givenName ?? 'N/A',
this.docNumber = docNumber ?? 'N/A',
this.issuingCountry = issuingCountry ?? 'N/A',
this.birthDate = birthDate ?? 'N/A',
this.gender = gender ?? 'N/A',
this.expiration = expiration ?? 'N/A',
this.lines = lines ?? 'N/A';
@override
String toString() {
if (type == null || type!.isEmpty) return "No results";
String result = '';
result += 'Type: $type\n\n';
result += 'Nationality: $nationality\n\n';
result += 'Surname: $surname\n\n';
result += 'Given name: $givenName\n\n';
result += 'Passport Number: $docNumber\n\n';
result += 'Issue Country: $issuingCountry\n\n';
result += 'Date of birth: $birthDate\n\n';
result += 'Gender: $gender\n\n';
result += 'Expiration: $expiration\n\n';
return result;
}
Map<String, dynamic> toJson() => {
'type': type ?? '',
'nationality': nationality ?? '',
'surname': surname ?? '',
'givenName': givenName ?? '',
'docNumber': docNumber ?? '',
'issuingCountry': issuingCountry ?? '',
'birthDate': birthDate ?? '',
'gender': gender ?? '',
'expiration': expiration ?? '',
'lines': lines,
};
factory MrzResult.fromJson(Map<String, dynamic> json) {
return MrzResult(
type: json['type'],
nationality: json['nationality'],
surname: json['surname'],
givenName: json['givenName'],
docNumber: json['docNumber'],
issuingCountry: json['issuingCountry'],
birthDate: json['birthDate'],
gender: json['gender'],
expiration: json['expiration'],
lines: json['lines'],
);
}
}
class VinResult {
String? vinString;
String? wmi;
String? region;
String? vds;
String? checkDigit;
String? modelYear;
String? plantCode;
String? serialNumber;
VinResult({
String? vinString,
String? wmi,
String? region,
String? vds,
String? checkDigit,
String? modelYear,
String? plantCode,
String? serialNumber,
}) : vinString = vinString ?? 'N/A',
wmi = wmi ?? 'N/A',
region = region ?? 'N/A',
vds = vds ?? 'N/A',
checkDigit = checkDigit ?? 'N/A',
modelYear = modelYear ?? 'N/A',
plantCode = plantCode ?? 'N/A',
serialNumber = serialNumber ?? 'N/A';
@override
String toString() {
return "VIN String: " +
vinString! +
"\n" +
"WMI: " +
wmi! +
"\n" +
"Region: " +
region! +
"\n" +
"VDS: " +
vds! +
"\n" +
"Check Digit: " +
checkDigit! +
"\n" +
"Model Year: " +
modelYear! +
"\n" +
"Manufacturer plant: " +
plantCode! +
"\n" +
"Serial Number: " +
serialNumber!;
}
Map<String, dynamic> toJson() => {
'vinString': vinString,
'wmi': wmi,
'region': region,
'vds': vds,
'checkDigit': checkDigit,
'modelYear': modelYear,
'plantCode': plantCode,
'serialNumber': serialNumber,
};
factory VinResult.fromJson(Map<String, dynamic> json) {
return VinResult(
vinString: json['vinString'],
wmi: json['wmi'],
region: json['region'],
vds: json['vds'],
checkDigit: json['checkDigit'],
modelYear: json['modelYear'],
plantCode: json['plantCode'],
serialNumber: json['serialNumber'],
);
}
}
Dart Method Implementation
-
init()
initializes the SDK with a license key. It should be called before any recognition methods. For Windows and Linux, it also downloads the model and template files if they are not already present.
@override Future<int?> init(String key) async { if (Platform.isLinux || Platform.isWindows) { await download(); } return await methodChannel.invokeMethod<int>('init', {'key': key}); }
-
loadModel()
sets the OCR mode by loading the appropriate template:
enum ModelType { mrz, vin } @override Future<int?> loadModel({ModelType modelType = ModelType.mrz}) async { String templateName = "ReadPassportAndId"; if (modelType == ModelType.vin) { templateName = "ReadVINText"; } int ret = await methodChannel .invokeMethod('loadModel', {'template': templateName}); return ret; }
-
recognizeFile()
performs OCR on an image file. It takes the file path as a parameter and returns a list of recognized lines.
@override Future<List<List<OcrLine>>?> recognizeFile(String filename) async { List<dynamic>? results = await methodChannel.invokeMethod('recognizeFile', { 'filename': filename, }); if (results == null || results.isEmpty) return []; return _resultWrapper(results); }
-
recognizeBuffer()
performs OCR on a raw image buffer. It takes the image data, dimensions, stride, pixel format, and rotation as parameters. The method returns a list of recognized lines.
@override Future<List<List<OcrLine>>?> recognizeBuffer(Uint8List bytes, int width, int height, int stride, int format, int rotation) async { List<dynamic>? results = await methodChannel.invokeMethod('recognizeBuffer', { 'bytes': bytes, 'width': width, 'height': height, 'stride': stride, 'format': format, 'rotation': rotation }); if (results == null || results.isEmpty) return []; return _resultWrapper(results); }
Platform-Specific Code
Dynamsoft Capture Vision provides both synchronous (capture()
) and asynchronous (startCapturing()
) recognition APIs. On the web, both are asynchronous.
Desktop (Windows/Linux)
CCaptureVisionRouter *cvr = new CCaptureVisionRouter;
CFileFetcher *fileFetcher = new CFileFetcher();
// File
fileFetcher->SetFile(filename);
// Buffer
CImageData *imageData = new CImageData(stride * height, buffer, width, height, stride, getPixelFormat(format), rotation);
fileFetcher->SetFile(imageData);
// Start capturing
char errorMsg[512] = {0};
int errorCode = cvr->StartCapturing(modelName.c_str(), false, errorMsg, 512);
if (errorCode != 0)
{
printf("StartCapturing: %s\n", errorMsg);
}
Android & iOS
-
Android
// File final Result r = result; mExecutor.execute(new Runnable() { @Override public void run() { ArrayList<ArrayList<HashMap<String, Object>>> ret = null; CapturedResult results = null; try { results = mRouter.capture(fileName, templateName); ret = wrapResults(results); } catch (Exception e) { Log.e(TAG, e.toString()); } final ArrayList<ArrayList<HashMap<String, Object>>> finalResults = ret; mHandler.post(new Runnable() { @Override public void run() { r.success(finalResults); } }); } }); // Buffer final Result r = result; mExecutor.execute(new Runnable() { @Override public void run() { ArrayList<ArrayList<HashMap<String, Object>>> ret = null; CapturedResult results = null; try { ImageData imageData = new ImageData(); imageData.bytes = bytes; imageData.width = width; imageData.height = height; imageData.stride = stride; imageData.format = format; imageData.orientation = rotation; results = mRouter.capture(imageData, templateName); ret = wrapResults(results); } catch (Exception e) { Log.e(TAG, e.toString()); } final ArrayList<ArrayList<HashMap<String, Object>>> finalResults = ret; mHandler.post(new Runnable() { @Override public void run() { r.success(finalResults); } }); } });
-
iOS
// File DispatchQueue.global().async { let filename: String = arguments.value(forKey: "filename") as! String let res = self.cvr.captureFromFile(filename, templateName: self.templateName) result(self.wrapResults(result: res)) } // Buffer DispatchQueue.global().async { let buffer: FlutterStandardTypedData = arguments.value(forKey: "bytes") as! FlutterStandardTypedData let width: Int = arguments.value(forKey: "width") as! Int let height: Int = arguments.value(forKey: "height") as! Int let stride: Int = arguments.value(forKey: "stride") as! Int let format: Int = arguments.value(forKey: "format") as! Int let rotation: Int = arguments.value(forKey: "rotation") as! Int let enumImagePixelFormat = ImagePixelFormat(rawValue: format) let imageData = ImageData.init() imageData.bytes = buffer.data imageData.width = UInt(width) imageData.height = UInt(height) imageData.stride = UInt(stride) imageData.format = enumImagePixelFormat! imageData.orientation = rotation let res = self.cvr.captureFromBuffer(imageData, templateName: self.templateName) result(self.wrapResults(result: res)) }
Web
@JS()
@anonymous
class CapturedItem {
external int get type;
external String get text;
external String get formatString;
external Location get location;
external int get angle;
external Uint8List get bytes;
external int get confidence;
}
@JS()
@anonymous
class CapturedResult {
external List<CapturedItem> get items;
}
@JS('CVR.CaptureVisionRouter')
class CaptureVisionRouter {
external static PromiseJsImpl<CaptureVisionRouter> createInstance();
external PromiseJsImpl<CapturedResult> capture(dynamic data, String template);
}
// File
CapturedResult capturedResult = await handleThenable(_cvr!.capture(file, modelName));
// Buffer
final dsImage = jsify({
'bytes': bytes,
'width': width,
'height': height,
'stride': stride,
'format': format,
'orientation': rotation
});
CapturedResult capturedResult = await handleThenable(_cvr!.capture(dsImage, modelName));
Updating the Example for MRZ and VIN Recognition
-
Add
ToggleButtons
to switch between MRZ and VIN modes inhome_page.dart
:
return Scaffold( body: Column( children: [ title, description, Center( child: ToggleButtons( borderRadius: BorderRadius.circular(10), isSelected: [isMrzSelected, !isMrzSelected], selectedColor: Colors.white, fillColor: Colors.orange, color: Colors.grey, children: const [ Padding( padding: EdgeInsets.symmetric(horizontal: 20), child: Text('MRZ'), ), Padding( padding: EdgeInsets.symmetric(horizontal: 20), child: Text('VIN'), ), ], onPressed: (index) { setState(() { isMrzSelected = (index == 0); if (isMrzSelected) { switchModel(ModelType.mrz); } else { switchModel(ModelType.vin); } }); }, ), ), ... ], ), );
-
Request a trial license key for Dynamsoft Capture Vision and set it in
global.dart
:
Future<int> initSDK() async { int? ret = await detector.init( "LICENSE-KEY"); if (ret == 0) isLicenseValid = true; return await detector.loadModel(modelType: model) ?? -1; }
-
Run the app on the target platform:
cd example flutter run -d chrome # Run on Web flutter run -d linux # Run on Linux flutter run -d windows # Run on Windows flutter run # Run on default connected device (e.g., Android)