На этой неделе я предпринял новую попытку, интегрировав Dynamsoft JavaScript Barcode SDK в текущий проект Плагин Flutter barcode. Удивительно иметь возможность создавать веб-приложения для чтения штрих-кодов с помощью того же decodeFile()
метода, который используется для разработки мобильных и настольных компьютеров.
То, что вы должны знать
- https://www.dynamsoft.com/barcode-reader/downloads
- https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr
использованная литература
- https://dart.dev/web/js-interop
- https://github.com/grandnexus/firebase-дротик
- https://pub.dev/packages/js
Плагин Flutter Barcode SDK для веб-разработки
Вышеупомянутый firebase_web
является отличным примером того, как научиться соединять API-интерфейсы Dart и JavaScript. Это очень вдохновило меня на реализацию веб-плагина Flutter.
Инициализировать плагин Flutter для Интернета
Давайте добавим шаблон веб-платформы в существующий проект плагина:
flutter create --template=plugin --platforms=web .
Команда создает только файл flutter_barcode_sdk_web.dart
в папке lib
. В отличие от шаблонов других платформ, которые генерируют независимые папки, содержащие некоторые языковые файлы для конкретной платформы, команда веб-плагина не создает для нас никаких файлов JavaScript.
Кроме того, нам нужно добавить описание веб-плагина в файл pubspec.yaml
:
flutter:
plugin:
platforms:
android:
package: com.dynamsoft.flutter_barcode_sdk
pluginClass: FlutterBarcodeSdkPlugin
windows:
pluginClass: FlutterBarcodeSdkPlugin
web:
pluginClass: FlutterBarcodeSdkWeb
fileName: flutter_barcode_sdk_web.dart
Внедрение Dart API для взаимодействия с JavaScript
Подобно платформам Android и Windows, мы находим handleMethodCall()
в качестве отправной точки в flutter_barcode_sdk_web.dart
:
Future<dynamic> handleMethodCall(MethodCall call) async {
switch (call.method) {
case 'getPlatformVersion':
return getPlatformVersion();
default:
throw PlatformException(
code: 'Unimplemented',
details:
'flutter_barcode_sdk for web doesn\'t implement \'${call.method}\'',
);
}
}
Поскольку Dynamsoft JavaScript Barcode SDK предоставляет класс Barcode Reader
для статических изображений и класс Barcode Scanner
для видеопотока, я создаю метод decodeFile()
и метод decodeVideo()
соответственно:
BarcodeManager _barcodeManager = BarcodeManager();
/// Decode barcodes from an image file.
Future<List<Map<dynamic, dynamic>>> decodeFile(String file) async {
return _barcodeManager.decodeFile(file);
}
/// Decode barcodes from real-time video stream.
Future<void> decodeVideo() async {
_barcodeManager.decodeVideo();
}
Метод decodeVideo()
является новым и доступен только для Интернета. Он запускает встроенное средство просмотра камеры HTML5 SDK штрих-кода JavaScript. Мы можем зарегистрировать функцию обратного вызова для получения результатов декодирования штрих-кода. Метод вызова определен в flutter_barcode_sdk.dart
:
Future<void> decodeVideo(Function callback) async {
globalCallback = callback;
await _channel.invokeMethod('decodeVideo');
}
Здесь немного сложно. Поскольку invokeMethod
не может передать ссылку на функцию, мой обходной путь — назначить функцию обратного вызова глобальной переменной. Чтобы избежать конфликта сборки между разными платформами, глобальная переменная определена в одном файле global.dart
:
Function globalCallback = () => {};
Теперь мы сосредоточимся на самом важном файле barcode_manager.dart
, который определяет классы и функции Dart для вызова API-интерфейсов JavaScript.
@JS('Dynamsoft')
library dynamsoft;
import 'dart:convert';
import 'dart:js';
import 'package:flutter_barcode_sdk/barcode_result.dart';
import 'package:flutter_barcode_sdk/global.dart';
import 'package:js/js.dart';
import 'utils.dart';
/// BarcodeScanner class
@JS('DBR.BarcodeScanner')
class BarcodeScanner {
external static PromiseJsImpl<BarcodeScanner> createInstance();
external void show();
external set onFrameRead(Function func);
}
/// BarcodeReader class
@JS('DBR.BarcodeReader')
class BarcodeReader {
external static PromiseJsImpl<BarcodeReader> createInstance();
external PromiseJsImpl<List<dynamic>> decode(dynamic file);
}
Следующий код взят из firebase_web
. Добавьте их в файл utils.dart
для обработки JavaScript Promise
.
import 'dart:async';
import 'dart:js_util';
import 'package:js/js.dart';
typedef Func1<A, R> = R Function(A a);
@JS('JSON.stringify')
external String stringify(Object obj);
@JS('console.log')
external void log(Object obj);
@JS('Promise')
class PromiseJsImpl<T> extends ThenableJsImpl<T> {
external PromiseJsImpl(Function resolver);
external static PromiseJsImpl<List> all(List<PromiseJsImpl> values);
external static PromiseJsImpl reject(error);
external static PromiseJsImpl resolve(value);
}
@anonymous
@JS()
abstract class ThenableJsImpl<T> {
external ThenableJsImpl then([Func1 onResolve, Func1 onReject]);
}
Future<T> handleThenable<T>(ThenableJsImpl<T> thenable) =>
promiseToFuture(thenable);
Инициализация объектов Barcode Reader
и Barcode Scanner
осуществляется следующим образом:
/// Initialize Barcode Scanner.
void initBarcodeScanner(BarcodeScanner scanner) {
_barcodeScanner = scanner;
_barcodeScanner.onFrameRead = allowInterop((results) =>
{globalCallback(callbackResults(_resultWrapper(results)))});
}
/// Initialize Barcode Reader.
void initBarcodeReader(BarcodeReader reader) {
_barcodeReader = reader;
}
BarcodeManager() {
handleThenable(BarcodeScanner.createInstance())
.then((scanner) => {initBarcodeScanner(scanner)});
handleThenable(BarcodeReader.createInstance())
.then((reader) => {initBarcodeReader(reader)});
}
Реализация метода decodeFile()
довольно проста:
Future<List<Map<dynamic, dynamic>>> decodeFile(String filename) async {
List<dynamic> barcodeResults =
await handleThenable(_barcodeReader.decode(filename));
return _resultWrapper(barcodeResults);
}
Что касается метода decodeVideo()
, чтобы сделать функцию Dart вызываемой из JavaScript, мы используем allowInterop()
для переноса функции обратного вызова Dart:
_barcodeScanner.onFrameRead = allowInterop((results) =>
{globalCallback(callbackResults(_resultWrapper(results)))});
Создайте веб-считыватель штрих-кода и сканер штрих-кода
На данный момент плагин веб-штрихкода Flutter готов. Мы можем проверить это, написав простое приложение Flutter с image_picker.
Создайте новый веб-проект Flutter и добавьте <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/dbr.js" data-productKeys="PRODUCT-KEYS"></script>
к web/index.html
:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/dbr.js" data-productKeys="PRODUCT-KEYS"></script>
<script src="main.dart.js" type="application/javascript"></script>
Создайте две кнопки материала. Один для декодирования штрих-кодов из статических изображений, а другой для сканирования штрих-кодов из видеопотока в реальном времени.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Dynamsoft Barcode Reader'),
),
body: Column(children: [
Container(
height: 100,
child: Row(children: <Widget>[
Text(
_platformVersion,
style: TextStyle(fontSize: 14, color: Colors.black),
)
]),
),
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
_file == null
? Image.asset('images/default.png')
: Image.network(_file),
Text(
_barcodeResults,
style: TextStyle(fontSize: 14, color: Colors.black),
),
],
),
),
),
Container(
height: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MaterialButton(
child: Text('Barcode Reader'),
textColor: Colors.white,
color: Colors.blue,
onPressed: () async {
final pickedFile =
await picker.getImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_file = pickedFile.path;
} else {
print('No image selected.');
}
_barcodeResults = '';
});
if (_file != null) {
List<BarcodeResult> results =
await _barcodeReader.decodeFile(_file);
updateResults(results);
}
}),
MaterialButton(
child: Text('Barcode Scanner'),
textColor: Colors.white,
color: Colors.blue,
onPressed: () async {
_barcodeReader.decodeVideo(
(results) => {updateResults(results)});
}),
]),
),
])),
);
Наконец, мы запускаем веб-приложение в Chrome:
flutter run -d chrome
Исходный код
https://github.com/yushulx/flutter_barcode_sdk
Первоначально опубликовано на https://www.dynamsoft.com 11 мая 2021 г.