Flutter条码扫描插件honeywell_scanner的使用

Flutter条码扫描插件honeywell_scanner的使用

关于Honeywell SDK

这个插件使用了Honeywell设备在技术支持下载门户上提供的原生Android SDK。您需要创建一个账户才能下载任何Honeywell软件。 从那里您可以下载包含Honeywell_MobilitySDK_Android_vx.xx.zip文件,该文件包含Android Data Collection SDK,这是该插件所使用的SDK。

  • Mobility SDK版本: 1.00.00.0135
  • 数据收集SDK版本: 1.97.00.0026

注意: 您不需要从上述描述中做任何事情就可以使用此插件,这只是为那些需要知道事实来源的人提供的指南。

描述

支持的设备:

CN51
CK75
CN75
CN75e
CN80
CN85
Dolphin 75e
Dolphin CT40/CT40XP
Dolphin CT50
Dolphin CT60
EDA50
EDA50K
EDA70
Thor VM1A
VM3A
RT10A
CK65
CN80G
CT60XP

如果您的设备不在上面的列表中,也可以尝试一下。

迁移说明

如果您是从低于^4.0.0+14的版本迁移过来,必须进行以下操作:

  • 将所有提到的ScannerCallBack更改为ScannerCallback
  • setScannerCallBack函数在HoneywellScanner中不再可用,如果需要在构造函数之后设置扫描回调,可以使用scannerCallback设置属性。
  • 更改onDecode函数的覆盖实现以接收ScannedData对象而不是String
  • ScannedData对象包含了扫描的代码和其他与扫描代码相关的详细信息。

如何使用

第一步

运行以下命令:

flutter pub add honeywell_scanner

这将在pubspec.yaml依赖项中添加honeywell_scanner,例如:

honeywell_scanner: ^latest_version

然后运行flutter pub get以将库源下载到您的pub-cache中。

第二步

复制位于.../.pub-cache/hosted/pub.dartlang.org/honeywell_scanner-x.x.x+x/example/android/honeywell下的honeywell文件夹到您的Android项目模块中。这一步是必要的,因为Honeywell Data Collection Android库是一个捆绑的.aar文件,需要作为项目库引用。

第三步

在您的Android项目的settings.gradle中添加include ':honeywell'以允许插件定位honeywell.aar库。

第四步

AndroidManifest.xml中的application标签下添加tools:replace="android:label"。这是必需的,因为honeywell.aar库定义了一个android:label="@string/app_name",这会与您的项目的标签冲突,导致Manifest merger failed错误。

如果仍然出现错误,检查是否缺少xmlns:tools="http://schemas.android.com/tools"

第五步

要使用honeywell_scanner插件,只需执行以下步骤:

  1. 实例化:
HoneywellScanner honeywellScanner = HoneywellScanner();

您也可以在构造函数中设置onDecodeonError回调,例如:

HoneywellScanner honeywellScanner = HoneywellScanner(scannerCallback: this);

或者使用函数回调:

HoneywellScanner honeywellScanner = HoneywellScanner(
  onScannerDecodeCallback: (scannedData) {
    // 在这里执行一些操作
  },
  onScannerErrorCallback: (error) {
    // 在这里执行一些操作
  }
);
  1. 检查设备是否受支持。请注意,该插件支持的是一系列Honeywell设备,但并非全部,因此此函数确保兼容性。
isDeviceSupported = await honeywellScanner.isSupported();
  1. 可以在构造函数之后设置扫描回调监听器:
honeywellScanner.setScannerCallBack(this);

或者

honeywellScanner.onScannerDecodeCallback = (scannedData) {
  // 在这里执行一些操作
};
honeywellScanner.onScannerErrorCallback = (error) {
  // 在这里执行一些操作
};
  1. 覆盖ScannerCallback方法:
[@override](/user/override)
void onDecoded(ScannedData? scannedData) {
  setState(() {
    this.scannedData = scannedData;
  });
}

[@override](/user/override)
void onError(Exception error) {
  setState(() {
    errorMessage = error.toString();
  });
}
  1. 设置属性。默认情况下,honeywell_scanner设置了支持所有代码格式的属性,还将触发控制属性设置为autoControl,并且禁用浏览器启动扫描URL。然而,如果您需要特定的行为,可以通过使用honeywellScanner.setProperties(properties)来设置任何所需的属性。
List<CodeFormat> codeFormats = CodeFormatUtils.ALL_1D_FORMATS;
Map<String, dynamic> properties = {
  ...CodeFormatUtils.getAsPropertiesComplement(codeFormats), // 将CodeFormat枚举列表转换为其相应的属性表示
  'DEC_CODABAR_START_STOP_TRANSMIT': true, // 这是Codabar开始/停止数字特定属性
  'DEC_EAN13_CHECK_DIGIT_TRANSMIT': true, // 这是EAN13校验位特定属性
};
honeywellScanner.setProperties(properties);

重要提示: 若要了解和理解所有支持的属性,请查看Honeywell SDK文档(获取SDK文档,请参阅README开头的关于Honeywell SDK部分)。您还可以在插件的doc文件夹中查看快速文档,在BarcodeReader.html中找到有关条形码阅读器的所有信息,包括属性,以及在BarcodeReaderProperties.java中找到所有可以设置的属性值。

  1. 启动扫描监听器,此时应用程序将开始监听任何扫描代码,当按下物理PDA按钮或应用内按钮时。
honeywellScanner.startScanner();
  1. 停止扫描监听器,这将释放并关闭扫描器连接。
honeywellScanner.stopScanner();
  1. 检查扫描器是否已启动:
honeywellScanner.isStarted;
  1. 您也可以调用scanner.pauseScanner()scanner.resumeScanner(),具体取决于您的应用生命周期状态。

  2. 开始扫描,此功能激活扫描传感器以扫描代码。这与按下PDA物理按钮相同。

honeywellScanner.startScanning();
  1. 停止扫描,它取消扫描。
honeywellScanner.stopScanning();

注意事项:

  • startScaning()stopScanning()都使用softwareTrigger(bool state)函数,其中state = true表示扫描,state = false表示不扫描。
  • 建议查看示例代码以更好地了解如何使用此插件。

其他可能感兴趣的插件

示例代码

以下是完整的示例代码:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:honeywell_scanner/honeywell_scanner.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_) => runApp(const MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

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

class _MyAppState extends State<MyApp>
    with WidgetsBindingObserver
    implements ScannerCallback {
  HoneywellScanner honeywellScanner = HoneywellScanner();
  ScannedData? scannedData;
  String? errorMessage;
  bool scannerEnabled = false;
  bool scan1DFormats = true;
  bool scan2DFormats = true;
  bool isDeviceSupported = false;

  static const BTN_START_SCANNER = 0,
      BTN_STOP_SCANNER = 1,
      BTN_START_SCANNING = 2,
      BTN_STOP_SCANNING = 3;

  [@override](/user/override)
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    honeywellScanner.scannerCallback = this;
    // honeywellScanner.onScannerDecodeCallback = onDecoded;
    // honeywellScanner.onScannerErrorCallback = onError;
    init();
  }

  Future<void> init() async {
    updateScanProperties();
    isDeviceSupported = await honeywellScanner.isSupported();
    if (mounted) setState(() {});
  }

  void updateScanProperties() {
    List<CodeFormat> codeFormats = [];
    if (scan1DFormats) codeFormats.addAll(CodeFormatUtils.ALL_1D_FORMATS);
    if (scan2DFormats) codeFormats.addAll(CodeFormatUtils.ALL_2D_FORMATS);

    Map<String, dynamic> properties = {
      ...CodeFormatUtils.getAsPropertiesComplement(codeFormats),
      'DEC_CODABAR_START_STOP_TRANSMIT': true,
      'DEC_EAN13_CHECK_DIGIT_TRANSMIT': true,
    };
    honeywellScanner.setProperties(properties);
  }

  [@override](/user/override)
  void onDecoded(ScannedData? scannedData) {
    setState(() {
      this.scannedData = scannedData;
    });
  }

  [@override](/user/override)
  void onError(Exception error) {
    setState(() {
      errorMessage = error.toString();
    });
  }

  Widget get scannedDataView => RichText(
        textAlign: TextAlign.center,
        text: TextSpan(
            style: TextStyle(
                color: Theme.of(context).textTheme.bodyLarge?.color,
                height: 0.8),
            children: [
              const TextSpan(text: 'Scanned code: '),
              TextSpan(
                  text: '${scannedData?.code}\n\n',
                  style: const TextStyle(fontWeight: FontWeight.bold)),
              const TextSpan(text: 'Scanned codeId symbol: '),
              TextSpan(
                  text: '${scannedData?.codeId}\n\n',
                  style: const TextStyle(fontWeight: FontWeight.bold)),
              const TextSpan(text: 'Scanned code type: '),
              TextSpan(
                  text: '${scannedData?.codeType}\n\n',
                  style: const TextStyle(fontWeight: FontWeight.bold)),
              const TextSpan(text: 'Scanned aimId: '),
              TextSpan(
                  text: '${scannedData?.aimId}\n\n',
                  style: const TextStyle(fontWeight: FontWeight.bold)),
              const TextSpan(text: 'Scanned charset: '),
              TextSpan(
                  text: '${scannedData?.charset}\n\n',
                  style: const TextStyle(fontWeight: FontWeight.bold)),
            ]),
      );

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Honeywell scanner example'),
        ),
        body: Center(
          child: Scrollbar(
            child: SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'Device supported: $isDeviceSupported',
                    style: TextStyle(
                        color: isDeviceSupported ? Colors.green : Colors.red,
                        fontSize: 18,
                        fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    'Scanner: ${scannerEnabled ? "Started" : "Stopped"}',
                    style: TextStyle(
                        color: scannerEnabled ? Colors.blue : Colors.orange),
                  ),
                  const SizedBox(height: 8),
                  if (scannedData != null && errorMessage == null)
                    scannedDataView,
                  const SizedBox(height: 8),
                  if (errorMessage != null) ...[
                    Text(
                      'Error: $errorMessage',
                      textAlign: TextAlign.center,
                      style: const TextStyle(
                          color: Colors.red, fontWeight: FontWeight.bold),
                    ),
                    const SizedBox(height: 8),
                  ],
                  SwitchListTile(
                    title: const Text("Scan 1D Codes"),
                    subtitle:
                        const Text("like Code-128, Code-39, Code-93, etc"),
                    value: scan1DFormats,
                    onChanged: (value) {
                      scan1DFormats = value;
                      updateScanProperties();
                      setState(() {});
                    },
                  ),
                  SwitchListTile(
                    title: const Text("Scan 2D Codes"),
                    subtitle: const Text("like QR, Data Matrix, Aztec, etc"),
                    value: scan2DFormats,
                    onChanged: (value) {
                      scan2DFormats = value;
                      updateScanProperties();
                      setState(() {});
                    },
                  ),
                  const SizedBox(height: 16),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      ElevatedButton(
                        child: const Text("Start Scanner"),
                        style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.blue)),
                        onPressed: () => onClick(BTN_START_SCANNER),
                      ),
                      ElevatedButton(
                        child: const Text("Stop Scanner"),
                        style: ButtonStyle(
                            backgroundColor: MaterialStateProperty.all(
                                Colors.blue.shade700)),
                        onPressed: () => onClick(BTN_STOP_SCANNER),
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      ElevatedButton(
                        child: const Text("Start Scanning"),
                        style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.green)),
                        onPressed: () => onClick(BTN_START_SCANNING),
                      ),
                      ElevatedButton(
                        child: const Text("Stop Scanning"),
                        style: ButtonStyle(
                            backgroundColor: MaterialStateProperty.all(
                                Colors.green.shade700)),
                        onPressed: () => onClick(BTN_STOP_SCANNING),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  [@override](/user/override)
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    switch (state) {
      case AppLifecycleState.resumed:
        honeywellScanner.resumeScanner();
        break;
      case AppLifecycleState.inactive:
        honeywellScanner.pauseScanner();
        break;
      case AppLifecycleState
            .paused: //AppLifecycleState.paused is used as stopped state because deactivate() works more as a pause for lifecycle
        honeywellScanner.pauseScanner();
        break;
      case AppLifecycleState.detached:
        honeywellScanner.pauseScanner();
        break;
      default:
        break;
    }
  }

  Future<void> onClick(int id) async {
    try {
      errorMessage = null;
      switch (id) {
        case BTN_START_SCANNER:
          if (await honeywellScanner.startScanner()) {
            setState(() {
              scannerEnabled = true;
            });
          }
          break;
        case BTN_STOP_SCANNER:
          if (await honeywellScanner.stopScanner()) {
            setState(() {
              scannerEnabled = false;
            });
          }
          break;
        case BTN_START_SCANNING:
          await honeywellScanner.startScanning();
          break;
        case BTN_STOP_SCANNING:
          await honeywellScanner.stopScanning();
          break;
      }
    } catch (e) {
      print(e);
      setState(() {
        errorMessage = e.toString();
      });
    }
  }

  [@override](/user/override)
  void dispose() {
    honeywellScanner.stopScanner();
    super.dispose();
  }
}

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

1 回复

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


当然,以下是如何在Flutter项目中使用honeywell_scanner插件进行条码扫描的示例代码。honeywell_scanner插件用于与霍尼韦尔(Honeywell)条码扫描器进行集成,以便在Flutter应用中实现条码扫描功能。

首先,确保你的Flutter项目中已经添加了honeywell_scanner依赖。你可以在pubspec.yaml文件中添加以下依赖:

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

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

接下来,你需要配置Android和iOS平台以支持霍尼韦尔扫描器。这通常涉及在AndroidManifest.xmlInfo.plist中添加必要的权限和配置,但具体步骤可能因扫描器型号和Flutter插件版本而异。请参考honeywell_scanner插件的官方文档获取详细的配置指南。

以下是一个简单的Flutter应用示例,展示如何使用honeywell_scanner插件进行条码扫描:

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

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

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

class ScannerScreen extends StatefulWidget {
  @override
  _ScannerScreenState createState() => _ScannerScreenState();
}

class _ScannerScreenState extends State<ScannerScreen> {
  String _scanResult = "";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Honeywell Scanner Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Scan Result:',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            Text(
              _scanResult,
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 40),
            ElevatedButton(
              onPressed: _startScanning,
              child: Text('Start Scanning'),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _startScanning() async {
    try {
      // 初始化扫描器(具体方法可能因插件版本而异)
      // 假设有一个初始化方法 initScanner()
      // await HoneywellScanner.instance.initScanner();

      // 开始扫描并监听扫描结果
      HoneywellScanner.instance.scanStream.listen((scanResult) {
        setState(() {
          _scanResult = scanResult;
        });
      }, onError: (error) {
        print('Scanning error: $error');
      }, onDone: () {
        print('Scanning done');
      });

      // 触发扫描(具体方法可能因插件版本而异)
      // 假设有一个触发扫描的方法 triggerScan()
      // await HoneywellScanner.instance.triggerScan();

      // 注意:实际使用中,扫描的触发和结果监听可能需要更复杂的逻辑处理,
      // 例如处理扫描器的连接状态、扫描结果的解析等。
      // 请参考插件的官方文档和示例代码进行具体实现。

    } catch (e) {
      print('Error starting scanner: $e');
    }
  }
}

注意:上述代码中的initScanner()triggerScan()方法是假设的方法名,实际使用时需要参考honeywell_scanner插件的API文档来调用正确的方法。此外,由于霍尼韦尔扫描器的多样性和插件的更新,具体的初始化和扫描逻辑可能有所不同。

确保你查阅了最新的honeywell_scanner插件文档,并根据你的扫描器型号和Flutter版本进行适当的调整。如果插件提供了示例代码或详细的集成指南,请务必遵循这些指南进行操作。

回到顶部