Flutter二维码生成与扫描插件qris的使用

Flutter二维码生成与扫描插件qris的使用

qris 是一个用于解析QR Indonesian Standard (QRIS) 代码的Flutter插件。它能够将读取到的QRIS码分解成有用的信息,如商户名称、交易金额等。

功能

  • 解析QRIS码为各种有用信息,包括QRIS类型、商户名称、交易金额和各类商户信息。

使用示例

从字符串解析QRIS数据

假设你已经通过某种QR阅读工具获取了一个QRIS码,并将其存储在变量 qrisData 中:

final qris = QRIS(qrisData);

debugPrint(qris.merchantName); // 输出: Baznas

qris.merchants.forEach((merchant) {
  debugPrint("${merchant.globallyUniqueIdentifier} | ${merchant.merchantCriteria.toString()}");
});
// 输出: ID.CO.SHOPEE.WWW | QRISMerchantCriteria.large

debugPrint(qris.pointOfInitiation?.toString());
// 输出: QRISInitiationPoint.staticCode

从图片文件或相册中读取QRIS数据

推荐使用 barcode_finder 插件来实现从图片文件或相册中读取QRIS数据。以下是一个修改后的示例(该示例使用了 file_picker 来选择文件,你可以替换为 image_picker):

import 'package:barcode_finder/barcode_finder.dart' as bf;
import 'package:image_picker/image_picker.dart';

Future<QRIS?> scanFile() async {
  final pickedFile = await FilePicker.platform.pickFiles();
  if (pickedFile != null) {
    final filePath = pickedFile.files.single.path;
    if (filePath != null) {
      final scannedData = await bf.BarcodeFinder.scanFile(
        path: filePath,
        formats: [bf.BarcodeFormat.QR_CODE],
      );
      if (scannedData != null) {
        return QRIS(scannedData);
      }
    }
  }
  return null;
}

完整示例Demo

以下是一个完整的Flutter应用程序示例,展示了如何使用 qris 插件进行二维码的扫描和解析:

// ignore_for_file: avoid_print, use_key_in_widget_constructors

import 'package:barcode_finder/barcode_finder.dart' as bf;
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:qris/qris.dart';

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

class QRISDemoApp extends StatelessWidget {
  const QRISDemoApp();

  @override
  Widget build(BuildContext context) {
    const defaultBorder = OutlineInputBorder();

    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        elevatedButtonTheme: const ElevatedButtonThemeData(
          style: ButtonStyle(
            iconColor: MaterialStatePropertyAll(Colors.white),
          ),
        ),
        inputDecorationTheme: const InputDecorationTheme(
          border: defaultBorder,
          focusedBorder: defaultBorder,
          enabledBorder: defaultBorder,
          errorBorder: defaultBorder,
          focusedErrorBorder: defaultBorder,
          isDense: true,
          contentPadding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
        ),
        floatingActionButtonTheme: const FloatingActionButtonThemeData(
          foregroundColor: Colors.white,
        ),
        listTileTheme: ListTileThemeData(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16.0),
            side: const BorderSide(color: Colors.black12),
          ),
        ),
      ),
      home: const QRISDemoPage(),
    );
  }
}

class QRISDemoPage extends StatefulWidget {
  const QRISDemoPage();

  @override
  State<QRISDemoPage> createState() => _QRISDemoPageState();
}

class _QRISDemoPageState extends State<QRISDemoPage> {
  QRIS? _qris;

  late final resultController = TextEditingController();

  @override
  void dispose() {
    resultController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('QRIS Scanner Demo')),
      body: Padding(
        padding: const EdgeInsets.all(24.0),
        child: Column(
          children: [
            TextField(
              decoration: InputDecoration(
                labelText: 'Reading Result (Raw)',
                suffixIcon: IconButton(
                  icon: const Icon(Icons.copy),
                  onPressed: () {
                    final result = resultController.text.trim();
                    if (result.isEmpty) return;
                    Clipboard.setData(ClipboardData(text: result));
                  },
                ),
              ),
              controller: resultController,
              readOnly: true,
              maxLines: 5,
            ),
            const SizedBox(height: 24.0),
            Expanded(
              child: Builder(
                builder: (_) {
                  final qris = _qris;
                  if (qris == null) {
                    return const Center(
                      child: Text(
                        'See scan results here',
                        textAlign: TextAlign.center,
                      ),
                    );
                  }
                  final map = qris.toEncodable().entries;
                  return ListView.separated(
                    separatorBuilder: (_, __) => const SizedBox(height: 12.0),
                    itemCount: map.length,
                    itemBuilder: (_, idx) {
                      final entry = map.elementAt(idx);
                      final value = '${entry.value}';
                      return ListTile(
                        leading: Text(
                          '[${entry.key}]',
                          style: const TextStyle(
                            fontWeight: FontWeight.bold,
                            color: Colors.blue,
                          ),
                        ),
                        title: Text(value),
                        trailing: IconButton(
                          onPressed: () {
                            if (value.isEmpty) return;
                            Clipboard.setData(ClipboardData(text: value));
                          },
                          icon: const Icon(Icons.copy),
                        ),
                      );
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Permission.camera.request().then((permission) {
            if (!permission.isGranted) {
              if (permission.isPermanentlyDenied) openAppSettings();
              return;
            }
            Navigator.of(context).push(
              MaterialPageRoute(builder: (_) => const QRISScannerPage()),
            ).then((result) {
              if (result is QRIS) {
                resultController.text = result.toString();
                setState(() {
                  _qris = result;
                });
              }
            });
          });
        },
        child: const Icon(Icons.qr_code_2),
      ),
    );
  }
}

class QRISScannerPage extends StatefulWidget {
  const QRISScannerPage();

  @override
  State<QRISScannerPage> createState() => _QRISScannerPageState();
}

class _QRISScannerPageState extends State<QRISScannerPage> with WidgetsBindingObserver {
  late final MobileScannerController controller = MobileScannerController(
    formats: [BarcodeFormat.qrCode],
  );

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        controller.start();
        break;
      case AppLifecycleState.inactive:
        controller.stop();
        break;
      case AppLifecycleState.paused:
        controller.stop();
        break;
      case AppLifecycleState.detached:
        break;
    }
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  void onDetect(BarcodeCapture barcodes) {
    for (var barcode in barcodes.barcodes) {
      final rawValue = barcode.rawValue;
      if (rawValue != null) {
        try {
          final qris = QRIS(rawValue);
          Navigator.of(context).pop(qris);
          break;
        } catch (_) {
          print(_);
        }
      }
    }
  }

  void toggleFlash() {
    if (controller.hasTorch) {
      controller.toggleTorch();
    }
  }

  Future<void> readFromImage() async {
    final storagePermission = await Permission.storage.request();
    if (!storagePermission.isGranted) {
      if (storagePermission.isPermanentlyDenied) openAppSettings();
      return;
    }
    final xFile = await ImagePicker().pickImage(source: ImageSource.gallery);
    final filePath = xFile?.path;
    if (filePath != null) {
      final data = await bf.BarcodeFinder.scanFile(
        path: filePath,
        formats: [bf.BarcodeFormat.QR_CODE],
      );
      if (data != null) {
        Navigator.of(context).pop(QRIS(data));
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('QR Scanner')),
      body: Stack(
        children: [
          Center(child: MobileScanner(controller: controller, onDetect: onDetect)),
          Padding(
            padding: const EdgeInsets.only(bottom: 64.0),
            child: Align(
              alignment: Alignment.bottomCenter,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  ValueListenableBuilder(
                    valueListenable: controller.torchState,
                    builder: (context, state, _) {
                      late final Widget icon;
                      switch (state) {
                        case TorchState.off:
                          icon = const Icon(Icons.flash_on);
                          break;
                        case TorchState.on:
                          icon = const Icon(Icons.flash_off);
                          break;
                      }
                      return ElevatedButton(onPressed: toggleFlash, child: icon);
                    },
                  ),
                  ElevatedButton(onPressed: readFromImage, child: const Icon(Icons.image)),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

以上代码提供了一个完整的Flutter应用示例,展示了如何使用 qris 插件进行二维码的扫描和解析。你可以根据需要进一步修改和完善这个示例。


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

1 回复

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


当然,下面是一个关于如何在Flutter项目中使用qr_code_scannerqr_flutter插件来生成与扫描二维码的示例代码。需要注意的是,尽管qr_code_scannerqr_flutter是两个流行的插件,但直接名为qris的插件可能并不明确指向某个具体的二维码处理库。因此,我将基于这两个广泛使用的插件来演示。

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  qr_code_scanner: ^3.0.1  # 请检查最新版本
  qr_flutter: ^4.0.0       # 请检查最新版本

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

2. 生成二维码

使用qr_flutter插件生成二维码:

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

class QRCodeGenerator extends StatelessWidget {
  final String qrCodeData;

  QRCodeGenerator({required this.qrCodeData});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('二维码生成'),
      ),
      body: Center(
        child: QrImage(
          data: qrCodeData,
          size: 200,
        ),
      ),
    );
  }
}

你可以在你的应用中导航到这个页面并传递你想要编码的数据。

3. 扫描二维码

使用qr_code_scanner插件扫描二维码:

首先,在你的AndroidManifest.xml中添加相机权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />

然后,在你的ios/Runner/Info.plist中添加相机使用描述:

<key>NSCameraUsageDescription</key>
<string>需要访问相机来扫描二维码</string>

接下来,创建一个扫描页面:

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

class QRCodeScannerPage extends StatefulWidget {
  @override
  _QRCodeScannerPageState createState() => _QRCodeScannerPageState();
}

class _QRCodeScannerPageState extends State<QRCodeScannerPage> {
  final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
  QRViewController? controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('二维码扫描'),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 4,
            child: QRView(
              key: qrKey,
              onQRViewCreated: _onQRViewCreated,
            ),
          ),
          Expanded(
            flex: 1,
            child: FittedBox(
              child: ControllerWidget(),
            ),
          ),
        ],
      ),
    );
  }

  void _onQRViewCreated(QRViewController qrViewController) {
    this.controller = qrViewController;
    this.controller!.scannedDataStream.listen((scanData) {
      setState(() {
        print('二维码数据: ${scanData}');
        // 在这里处理扫描到的数据
      });
    });
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }
}

class ControllerWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: () async {
            final BarcodeScannerResult? result = await BarcodeScanner.scan();
            if (result != null) {
              print('扫描结果: ${result.rawContent}');
            }
          },
          child: Text('使用系统相机扫描'),
        ),
      ],
    );
  }
}

请注意,BarcodeScanner.scan()方法是一个平台通道调用,它可能会打开设备的原生相机应用进行扫描,而不是使用qr_code_scanner插件的自定义相机视图。根据你的需求选择使用哪种方式。

4. 导航页面

最后,在你的主应用或任何需要的地方添加导航逻辑:

import 'package:flutter/material.dart';
import 'qr_code_generator.dart';
import 'qr_code_scanner_page.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('二维码示例'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => QRCodeGenerator(qrCodeData: "https://www.example.com")),
                  );
                },
                child: Text('生成二维码'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => QRCodeScannerPage()),
                  );
                },
                child: Text('扫描二维码'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

以上代码展示了如何在Flutter应用中集成二维码生成与扫描功能。请根据你的实际需求调整代码。

回到顶部