Flutter扫码插件scanwedge的使用

发布于 1周前 作者 phonegap100 来自 Flutter

Flutter扫码插件Scanwedge的使用

简介

Scanwedge 是一个用于 Android 设备的 Flutter 插件,支持具有硬件条形码扫描功能的设备。目前它支持 Honeywell、Datalogic 和 Zebra 设备。这个插件仅适用于这些 Android 设备,但不会对其他设备产生负面影响。代码灵感来源于 Honeywell、Zebra 的示例代码以及 Flutter 社区。

快速上手

命令说明

以下是 Scanwedge 提供的主要命令及其描述:

命令 描述
createProfile 创建一个新的扫描配置文件,输入是一个 ProfileModel 对象
disableScanner 禁用扫描仪,对于 Honeywell 设备,它仍然会“读取”但不会发送结果
enableScanner 启用扫描仪
initialize 请求并初始化 Scanwedge,必须在使用 Scanwedge 之前调用
isDeviceSupported 返回设备是否受支持(Honeywell 或 Zebra),如果返回 false,其他方法将被忽略
manufacturer 返回设备制造商
modelName 返回设备型号
osVersion 返回设备的操作系统版本
packageName 返回主机应用程序的包名,也将作为 [ScanProfile] 的默认包名
productName 返回设备的产品名称
supportedDevice 返回一个 SupportedDevice 对象,包含设备是否受支持及类型信息
stream 请求条形码扫描流,返回带有 ScanResult 的条形码
toggleScanning 触发一次扫描(软触发)
创建一个新的基础配置文件

以下代码展示了如何创建一个新的配置文件,该配置文件只读取长度在 5 到 10 之间的 CODE128 条形码:

final _scanwedgePlugin = await Scanwedge.initialize();

// 创建一个新的名为 TestProfile 的配置文件,只读取长度在 5 到 10 之间的 CODE128 条形码
_scanwedgePlugin.createProfile(ProfileModel(
  profileName: 'TestProfile',
  enabledBarcodes: [
    BarcodeTypes.code128.create(minLength: 5, maxLength: 10)
  ]
));
ProfileModel

ProfileModel 类用于设置扫描配置文件:

ProfileModel({
  required String profileName,                      // 配置文件的名称
  List<BarcodeConfig>? enabledBarcodes,            // 将在配置文件中启用的条形码列表
  bool keepDefaults = true,                        // 如果为 true,则保留硬件默认启用的条形码(与 enabledBarcodes 一起)
});
ZebraProfileModel

ZebraProfileModelProfileModel 的扩展版本,针对 Zebra 设备提供了更多配置选项:

  • aimType:扫描器的瞄准类型,默认为 AimType.trigger
  • enableKeyStroke:是否将扫描结果发送到键盘缓冲区,默认为 false
SupportedDevice 枚举

SupportedDevice 枚举用于表示设备是否受支持及设备类型:

enum SupportedDevice { zebra, honeywell, invalid }
BarcodeConfig

BarcodeConfig 类用于设置与条形码扫描相关的配置:

BarcodeConfig({
  required BarcodeTypes barcodeType,  // 条形码类型
  int? minLength,                     // 条形码的最小长度,如果为 null 则忽略
  int? maxLength,                     // 条形码的最大长度,如果为 null 则忽略
});
监听扫描事件

要接收扫描事件,可以监听 Stream:

final _scanwedgePlugin = ScanwedgeChannel();

[@override](/user/override)
Widget build(BuildContext context) {
  return Card(
    child: Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const Text('Last scan:'),
        StreamBuilder(
          stream: _scanwedgePlugin.stream,
          builder: (context, snapshot) {
            return Text(
              snapshot.hasData
                  ? snapshot.data.toString()
                  : snapshot.hasError
                      ? snapshot.error.toString()
                      : 'Scan something',
              style: Theme.of(context).textTheme.titleMedium,
            );
          },
        ),
      ],
    ),
  );
}
AimTypes 枚举

AimTypes 枚举用于设置 Zebra 设备上的扫描器瞄准类型:

enum AimType {
  trigger,
  timedHold,
  timedRelease,
  pressAndRelease,
  presentation,
  continuousRead,
  pressAndSustain,
  pressAndContinue,
  timedContinuous
}
BarcodeTypes 枚举

BarcodeTypes 枚举用于表示支持的条形码类型:

enum BarcodeTypes {
  aztec,
  codabar,
  code128,
  code39,
  code93,
  datamatrix,
  ean128,
  ean13,
  ean8,
  gs1DataBar,
  gs1DataBarExpanded,
  i2of5,
  mailmark,
  maxicode,
  pdf417,
  qrCode,
  upca,
  upce0,
  manual,     // 用于标记手动输入的条形码
  unknown     // 当接收到未知条形码时,检查 [ScanResult.hardwareBarcodeType] 获取实际条形码类型
}

完整示例 Demo

以下是一个完整的示例应用,展示了如何使用 Scanwedge 插件进行条形码扫描:

import 'dart:developer';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:scanwedge/scanwedge.dart';

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

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Scanwedge? _scanwedgePlugin;
  String? _deviceInfo;
  final notifierDisableKeystroke = ValueNotifier(true);
  final notifierAimType = ValueNotifier(AimType.trigger);

  [@override](/user/override)
  void initState() {
    super.initState();
    try {
      // 初始化 Scanwedge 插件
      Scanwedge.initialize().then((scanwedge) {
        _scanwedgePlugin = scanwedge;
        setState(() {});
        // 获取设备信息
        scanwedge.getDeviceInfo().then((devInfo) => setState(() {
              _deviceInfo = devInfo;
            }));
      });
    } catch (e) {
      log('initState Exception: $e');
    }
  }

  // 创建配置文件
  _createProfile() async {
    try {
      log('_createProfile()-${await _scanwedgePlugin?.createScanProfile(_scanwedgePlugin?.manufacturer == 'ZEBRA' ? ZebraProfileModel(
        profileName: 'DemoProfile',
        enabledBarcodes: [
          BarcodeConfig(barcodeType: BarcodeTypes.code39),
          BarcodeConfig(barcodeType: BarcodeTypes.code128),
          BarcodeConfig(barcodeType: BarcodeTypes.ean8),
          BarcodeConfig(barcodeType: BarcodeTypes.ean13),
          BarcodeConfig(barcodeType: BarcodeTypes.i2of5),
        ],
        enableKeyStroke: !notifierDisableKeystroke.value,
        aimType: notifierAimType.value
      ) : ProfileModel(
        profileName: 'DemoProfile',
        enabledBarcodes: [
          BarcodeTypes.code39.create(),
          BarcodeTypes.code128.create(minLength: 10, maxLength: 15),
          BarcodeTypes.qrCode.create(),
        ],
        keepDefaults: false
      ))}');
    } catch (e) {
      log('_createProfile Exception: $e');
    }
  }

  // 触发扫描
  _triggerScan() async {
    try {
      log('_triggerScan()-${await _scanwedgePlugin?.toggleScanning()}');
    } catch (e) {
      log('_triggerScan Exception: $e');
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
          actions: [
            PopupMenuButton(
              itemBuilder: (context) => [
                const PopupMenuItem(
                  value: 'trigger',
                  child: Text('触发扫描'),
                ),
                const PopupMenuItem(
                  value: 'enable',
                  child: Text('启用扫描仪'),
                ),
                const PopupMenuItem(
                  value: 'disable',
                  child: Text('禁用扫描仪'),
                ),
                const PopupMenuItem(
                  value: 'exit',
                  child: Text('退出应用'),
                ),
              ],
              onSelected: (value) {
                switch (value) {
                  case 'trigger':
                    _triggerScan();
                    break;
                  case 'enable':
                    _scanwedgePlugin?.enableScanner();
                    break;
                  case 'disable':
                    _scanwedgePlugin?.disableScanner();
                    break;
                  case 'exit':
                    exit(0);
                    break;
                }
              },
            ),
          ],
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text(_deviceInfo ?? '无设备信息', style: Theme.of(context).textTheme.labelSmall),
            Card(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Flexible(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Row(
                            mainAxisSize: MainAxisSize.min,
                            children: [
                              const Text('禁用键盘输入'),
                              const SizedBox(width: 5),
                              ValueListenableBuilder(
                                valueListenable: notifierDisableKeystroke,
                                builder: (context, disableKeyboard, _) => Switch(
                                  value: disableKeyboard,
                                  onChanged: (value) => notifierDisableKeystroke.value = value,
                                ),
                              ),
                            ],
                          ),
                          ValueListenableBuilder(
                            valueListenable: notifierAimType,
                            builder: (context, aimType, _) => PopupMenuButton(
                              elevation: 4,
                              padding: const EdgeInsets.all(5),
                              itemBuilder: (context) => AimType.values
                                  .map((e) => PopupMenuItem(
                                        value: e,
                                        child: Text(e.toString().split('.').last),
                                      ))
                                  .toList(),
                              child: Container(
                                padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
                                decoration: BoxDecoration(
                                  color: Colors.blue,
                                  borderRadius: BorderRadius.circular(5),
                                  boxShadow: const [BoxShadow(offset: Offset(2, 2), blurRadius: 1, color: Colors.black54)],
                                ),
                                child: Column(
                                  mainAxisSize: MainAxisSize.min,
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text('AimType:', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.white)),
                                    Padding(
                                      padding: const EdgeInsets.only(left: 6.0),
                                      child: Text(aimType.toString().split('.').last, style: Theme.of(context).textTheme.titleLarge?.copyWith(color: Colors.white)),
                                    ),
                                  ],
                                ),
                              ),
                              onSelected: (newAimType) => notifierAimType.value = newAimType,
                            ),
                          ),
                        ],
                      ),
                    ),
                    ElevatedButton(onPressed: _createProfile, child: const Text('创建配置文件')),
                  ],
                ),
              ),
            ),
            TextFormField(
              decoration: const InputDecoration(hintText: '自动插入(如果启用了键盘输入且处于焦点状态)', contentPadding: EdgeInsets.symmetric(horizontal: 6)),
            ),
            const Expanded(child: SizedBox()),
            Card(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: _scanwedgePlugin != null
                    ? Column(
                        mainAxisSize: MainAxisSize.min,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          const Text('最后扫描:'),
                          StreamBuilder(
                            stream: _scanwedgePlugin!.stream,
                            builder: (context, snapshot) {
                              return Text(
                                snapshot.hasData
                                    ? snapshot.data.toString()
                                    : snapshot.hasError
                                        ? snapshot.error.toString()
                                        : '请扫描条形码',
                                style: Theme.of(context).textTheme.titleMedium,
                              );
                            },
                          ),
                        ],
                      )
                    : const Center(child: CircularProgressIndicator()),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter扫码插件scanwedge的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter扫码插件scanwedge的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用scanwedge插件来实现扫码功能的示例代码。scanwedge插件通常用于集成硬件设备(如条码扫描器)进行扫码操作。以下是一个基本的示例,展示了如何在Flutter应用中设置和使用scanwedge插件。

首先,确保你的Flutter项目中已经添加了scanwedge插件。如果还没有添加,可以在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  scanwedge: ^最新版本号 # 请替换为实际的最新版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter应用中,你可以按照以下步骤使用scanwedge插件:

  1. 导入插件

在你的Dart文件中(例如main.dart),导入scanwedge插件:

import 'package:scanwedge/scanwedge.dart';
  1. 初始化插件

在你的应用启动时,初始化ScanWedge插件,并设置扫码结果回调:

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

  // 初始化ScanWedge插件
  ScanWedge.instance.init().then((_) {
    // 设置扫码结果回调
    ScanWedge.instance.addListener((ScanWedgeResult result) {
      // 处理扫码结果
      print("扫码结果: ${result.data}");
      // 你可以在这里更新UI或执行其他操作
    });
  });
}
  1. 创建Flutter应用

创建一个简单的Flutter应用,展示扫码功能:

import 'package:flutter/material.dart';
import 'package:scanwedge/scanwedge.dart';

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

  // 初始化ScanWedge插件的代码(如上所示)
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter ScanWedge Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String scanResult = "";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter ScanWedge Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '扫码结果:',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 10),
            Text(
              scanResult,
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }

  // 在这里添加初始化ScanWedge插件的代码(如上面main函数中的代码)
}

注意:由于ScanWedge插件的具体实现和API可能会随着版本更新而变化,所以请务必参考最新的官方文档和示例代码。如果ScanWedge插件提供了更多配置选项或事件处理,你可能需要根据实际需求进行调整。

此外,由于ScanWedge通常用于集成硬件设备,因此确保你的设备和Flutter应用正确配置了所需的权限和硬件接口。如果遇到硬件集成问题,请查阅相关硬件设备的文档以获取更多帮助。

回到顶部