Flutter文档扫描与识别插件credio_reader的使用

Flutter 文档扫描与识别插件 credio_reader 的使用

简介

Credio Reader 插件是一个专门为 Flutter 设计的包,旨在简化将 Credio 支付终端集成到你的移动应用中的过程。它提供了一个可自定义的按钮来管理与 Credio 读卡器的连接并发起支付交易。

安装

在你的 pubspec.yaml 文件中添加以下依赖项:

dependencies:
  credio_reader: ^latest_version

然后,在终端中运行以下命令以安装该包:

flutter pub get

配置

Credio Reader 插件使用 CredioConfig 类进行配置。以下是设置方法的示例:

final GetIt locator = GetIt.instance;

void setupLocator() {
  locator.registerLazySingleton(() => NavigationService());
}

final apiKey = 'your_api_key'; // 示例:tracker_cred_8f3X9pLm2qRt7vYw4hNk6bJc
final webHookUrl = 'your_webHook_url';

final CredioConfig config = CredioConfig(
  apiKey,
  '2070FLRX',
  webHookUrl,
  locator<NavigationService>().navigatorKey,
  initializerButton: Text("Custom Initializer Button"),
  buttonConfiguration: ButtonConfiguration(
    buttonStyle: ElevatedButton.styleFrom(
      backgroundColor: Colors.green,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.all(Radius.circular(15.0)),
      ),
    ),
  ),
  amount: 100, // 预定义金额
  amountInputDecoration: InputDecoration(
    labelText: 'Enter withdrawal amount',
    prefixIcon: Icon(Icons.attach_money),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(10),
    ),
  ),
  accountTypes: [
    SelectionData(selection: 0, title: "个人账户"),
    SelectionData(selection: 1, title: "企业账户"),
  ],
  customSelectionSheet: (BuildContext context, List<SelectionData> data, Function(SelectionData) onSelect) {
    // 自定义账户类型选择实现
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('选择账户类型'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: data
                .map(
                  (item) => ElevatedButton(
                    child: Text(item.title!),
                    onPressed: () {
                      onSelect(item);
                      Navigator.of(context).pop();
                    },
                  ),
                )
                .toList(),
          ),
        );
      },
    );
  },
  customPinEntry: (BuildContext context, Function(String) onCompleted) {
    // 自定义 PIN 输入实现
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 48.0),
      child: TextFormField(
        autofocus: true,
        obscureText: true,
        keyboardType: TextInputType.number,
        maxLength: 4,
        decoration: InputDecoration(
          labelText: '输入 PIN',
          border: OutlineInputBorder(),
        ),
        onChanged: (value) {
          if (value.length == 4) {
            onCompleted(value);
          }
        },
      ),
    );
  },
  customLoader: <T>({
    required BuildContext context,
    required Future<T> future,
    required String prompt,
    required String errorMessage,
    String? successMessage,
    VoidCallback? action,
    required Function(String) onError,
  }) async {
    try {
      showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                CircularProgressIndicator(),
                SizedBox(height: 20),
                Text(prompt),
              ],
            ),
          );
        },
      );

      final result = await future;

      Navigator.of(context).pop();

      if (successMessage != null) {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Text('成功'),
              content: Text(successMessage),
              actions: <Widget>[
                TextButton(
                  child: Text('确定'),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            );
          },
        );
      }

      return result;
    } catch (error) {
      Navigator.of(context).pop();

      // 调用 onError 处理错误
      onError(errorMessage);

      return null;
    }
  },
);

注意:对于这些新定制选项的详细使用,请参阅包存储库中的示例应用。

权限

在应用中使用 ReaderButton 之前,确保已经请求并获得必要的权限。Credio Reader 插件需要以下权限:

  • 蓝牙
  • 互联网
  • 位置(仅限 Android)

平台特定设置

为了确保应用可以请求这些权限,请在应用的配置文件中添加以下内容:

Android

AndroidManifest.xml 中添加以下内容:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 对于 Android 12 及以上版本 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

iOS

Info.plist 中添加以下内容:

<key>NSBluetoothPeripheralUsageDescription</key>
<string>我们需要访问蓝牙以连接到 Credio 读卡器,并为您提供 POS 支付功能。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Credio 希望访问您的位置,以向您提供相关且个性化的服务。您的位置信息仅在您使用应用时才会被使用。</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Credio 需要蓝牙访问权限,以便安全地连接到 Credio 读卡器,并促进支付处理和设备配置的无缝通信。</string>

你应该在初始化 ReaderButton 之前请求这些权限。以下是一个简单的示例:

import 'package:permission_handler/permission_handler.dart';

Future<bool> requestCredioPermissions() async {
  Map<Permission, PermissionStatus> statuses = await [
    Permission.bluetooth,
    Permission.location,
  ].request();

  return statuses[Permission.bluetooth]!.isGranted && 
         statuses[Permission.location]!.isGranted;
}

// 在应用中使用
void initializeCredioReader() async {
  if (await requestCredioPermissions()) {
    // 权限已授予,现在可以使用 ReaderButton
    // 例如:
    // ReaderButton(_config)
  } else {
    // 处理权限未授予的情况
    // 你可能想要显示一个对话框解释为什么需要这些权限
  }
}

使用

按照上述配置部分创建 CredioConfig 实例后,你可以通过在应用的 UI 中添加 ReaderButton 小部件来使用 Credio Reader

ReaderButton(config)

交易处理

当用户按下自定义的 Credio 按钮时,交易过程将被启动。插件会管理与 Credio 读卡器的交互并在后台处理交易。完成后,回调函数会被触发,提供交易的结果。

  • 成功的交易:回调函数将返回一个包含交易详情的成功消息,如金额、时间戳和响应码。如果响应码为“00”,则认为交易成功。
  • 失败的交易:如果发生错误或失败,回调函数将包含错误详情,允许应用通知用户并采取适当的措施。

错误处理

错误处理对于提供无缝的用户体验至关重要。插件提供了内置的错误消息,但开发者也可以在回调函数中自定义错误处理方式。常见的错误包括:

  • 无效的 terminalIdapiKey
  • Credio 读卡器的连接问题
  • 用户取消交易

部署

确保在部署应用之前正确设置了所有必需的配置(如 terminalIdapiKey)。credio_reader 插件应在测试环境中进行彻底测试,以确保其与 Credio 读卡器正确交互并按预期处理交易。

示例代码

import 'package:credio_reader/components/app_selection_sheet.dart';
import 'package:credio_reader/configuration/button_configuration.dart';
import 'package:credio_reader/configuration/configuration.dart';
import 'package:credio_reader/credio_reader.dart';
import 'package:credio_reader_example/nav.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';

final GetIt locator = GetIt.instance;

void setupLocator() {
  locator.registerLazySingleton(() => NavigationService());
}

void main() async {
  setupLocator();

  runApp(const MyApp());
}

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

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

class _MyAppState extends State<MyApp> {
  late final CredioConfig _config;
  final apiKey = 'your_api_key'; // 示例:tracker_cred_8f3X9pLm2qRt7vYw4hNk6bJc
  final webHookUrl = 'your_webHook_url';

  [@override](/user/override)
  void initState() {
    super.initState();
    _config = CredioConfig(
      apiKey,
      '2070FLRX',
      webHookUrl,
      locator<NavigationService>().navigatorKey,
      initializerButton: Text("I can use a single Text"),
      buttonConfiguration: ButtonConfiguration(
        buttonStyle: ElevatedButton.styleFrom(
          backgroundColor: Colors.green,
          shape: const RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(15.0),
            ),
          ),
        ),
      ),
      amount: 100,
      amountInputDecoration: InputDecoration(
        labelText: 'Enter withdrawal amount',
        prefixIcon: const Icon(Icons.attach_money),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
        ),
      ),
      accountTypes: [
        SelectionData(selection: 0, title: "个人账户"),
        SelectionData(selection: 1, title: "企业账户"),
      ],
      customSelectionSheet: (BuildContext context, List<SelectionData> data, Function(SelectionData) onSelect) {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Text('选择账户类型'),
              content: Column(
                mainAxisSize: MainAxisSize.min,
                children: data
                    .map(
                      (item) => ElevatedButton(
                        child: Text(item.title!),
                        onPressed: () {
                          onSelect(item);
                          Navigator.of(context).pop();
                        },
                      ),
                    )
                    .toList(),
              ),
            );
          },
        );
      },
      customPinEntry: (BuildContext context, Function(String) onCompleted) {
        return Padding(
          padding: const EdgeInsets.symmetric(horizontal: 48.0),
          child: TextFormField(
            autofocus: true,
            obscureText: true,
            keyboardType: TextInputType.number,
            maxLength: 4,
            decoration: InputDecoration(
              labelText: '输入 PIN',
              border: OutlineInputBorder(),
            ),
            onChanged: (value) {
              if (value.length == 4) {
                onCompleted(value);
              }
            },
          ),
        );
      },
      customLoader: <T>({
        required BuildContext context,
        required Future<T> future,
        required String prompt,
        required String errorMessage,
        String? successMessage,
        VoidCallback? action,
        required Function(String) onError,
      }) async {
        try {
          showDialog(
            context: context,
            barrierDismissible: false,
            builder: (BuildContext context) {
              return AlertDialog(
                content: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    CircularProgressIndicator(),
                    SizedBox(height: 20),
                    Text(prompt),
                  ],
                ),
              );
            },
          );

          final result = await future;

          Navigator.of(context).pop();

          if (successMessage != null) {
            showDialog(
              context: context,
              builder: (BuildContext context) {
                return AlertDialog(
                  title: Text('成功'),
                  content: Text(successMessage),
                  actions: <Widget>[
                    TextButton(
                      child: Text('确定'),
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                    ),
                  ],
                );
              },
            );
          }

          return result;
        } catch (error) {
          Navigator.of(context).pop();

          // 调用 onError 处理错误
          onError(errorMessage);

          return null;
        }
      },
    );
    if (mounted) {
      setState(() {});
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.purple),
      navigatorKey: locator<NavigationService>().navigatorKey,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Credio Reader 示例应用'),
        ),
        body: Center(
          child: Builder(
            builder: (context) {
              return ReaderButton(_config);
            },
          ),
        ),
      ),
    );
  }
}

更多关于Flutter文档扫描与识别插件credio_reader的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文档扫描与识别插件credio_reader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


credio_reader 是一个用于在 Flutter 应用中实现文档扫描和文本识别的插件。它基于 OCR(光学字符识别)技术,能够从图像中提取文本。以下是如何在 Flutter 项目中使用 credio_reader 的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 credio_reader 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  credio_reader: ^1.0.0  # 请检查最新版本

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

2. 导入插件

在你的 Dart 文件中导入 credio_reader 插件:

import 'package:credio_reader/credio_reader.dart';

3. 初始化扫描器

在使用插件之前,通常需要初始化扫描器。你可以使用 CredioReader.initialize() 方法来完成初始化:

void initializeScanner() async {
  bool isInitialized = await CredioReader.initialize();
  if (isInitialized) {
    print("Scanner initialized successfully");
  } else {
    print("Failed to initialize scanner");
  }
}

4. 启动文档扫描

你可以使用 CredioReader.scanDocument() 方法来启动文档扫描。该方法会返回扫描后的图像路径:

void scanDocument() async {
  String? imagePath = await CredioReader.scanDocument();
  if (imagePath != null) {
    print("Document scanned successfully: $imagePath");
    // 你可以在这里处理扫描后的图像,例如显示在UI中或进行OCR识别
  } else {
    print("Document scanning failed or was canceled");
  }
}

5. 执行OCR识别

如果你需要从扫描的图像中提取文本,可以使用 CredioReader.recognizeText() 方法:

void recognizeText(String imagePath) async {
  String? recognizedText = await CredioReader.recognizeText(imagePath);
  if (recognizedText != null) {
    print("Recognized text: $recognizedText");
    // 你可以在这里处理识别出的文本,例如显示在UI中或保存到数据库
  } else {
    print("Text recognition failed");
  }
}

6. 结合使用

你可以将扫描和识别的步骤结合起来,例如在扫描完成后立即进行OCR识别:

void scanAndRecognize() async {
  String? imagePath = await CredioReader.scanDocument();
  if (imagePath != null) {
    print("Document scanned successfully: $imagePath");
    String? recognizedText = await CredioReader.recognizeText(imagePath);
    if (recognizedText != null) {
      print("Recognized text: $recognizedText");
    } else {
      print("Text recognition failed");
    }
  } else {
    print("Document scanning failed or was canceled");
  }
}

7. 处理权限

在使用相机和存储功能时,确保你已经处理了相关的权限请求。你可以在 AndroidManifest.xmlInfo.plist 中添加必要的权限,并在运行时请求用户授权。

8. 错误处理

在实际应用中,建议添加适当的错误处理机制,以应对可能出现的异常情况。

9. 示例代码

以下是一个完整的示例代码,展示了如何使用 credio_reader 插件进行文档扫描和文本识别:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ScannerScreen(),
    );
  }
}

class ScannerScreen extends StatefulWidget {
  [@override](/user/override)
  _ScannerScreenState createState() => _ScannerScreenState();
}

class _ScannerScreenState extends State<ScannerScreen> {
  String? _scannedImagePath;
  String? _recognizedText;

  void initializeScanner() async {
    bool isInitialized = await CredioReader.initialize();
    if (isInitialized) {
      print("Scanner initialized successfully");
    } else {
      print("Failed to initialize scanner");
    }
  }

  void scanAndRecognize() async {
    String? imagePath = await CredioReader.scanDocument();
    if (imagePath != null) {
      setState(() {
        _scannedImagePath = imagePath;
      });
      String? recognizedText = await CredioReader.recognizeText(imagePath);
      if (recognizedText != null) {
        setState(() {
          _recognizedText = recognizedText;
        });
      } else {
        print("Text recognition failed");
      }
    } else {
      print("Document scanning failed or was canceled");
    }
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    initializeScanner();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Document Scanner & OCR"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            if (_scannedImagePath != null)
              Image.file(
                File(_scannedImagePath!),
                height: 200,
              ),
            if (_recognizedText != null)
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(_recognizedText!),
              ),
            ElevatedButton(
              onPressed: scanAndRecognize,
              child: Text("Scan Document"),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部