본문 바로가기

Flutter

플러터(Flutter) - QR Code Scan

반응형

 

QR Code Scan을 이용하기 위해 

qr_code_scanner Package를 설치해야 합니다.

https://pub.dev/packages/qr_code_scanner

 

qr_code_scanner | Flutter Package

QR code scanner that can be embedded inside flutter. It uses zxing in Android and MTBBarcode scanner in iOS.

pub.dev

pubspec.yaml 에서 추가해 줍니다.

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.

  qr_code_scanner: ^0.6.1

 

Android > app > build.gradle 에서 최소 minSdkVersion은 20번입니다.

 

AndroidManifest.xml 

<uses-permission android:name="android.permission.CAMERA"/>

AndroidManifest에 카메라 권한을 설정해 줍니다.

 

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

  @override
  State<QrScan> createState() => _QrScanState();
}

class _QrScanState extends State<QrScan> {
  final qrKey = GlobalKey(debugLabel: 'QR');

  Barcode? barcode;
  QRViewController? controller;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        alignment: Alignment.center,
        children: [
          buildQrView(context),
          Positioned(bottom: 10, child: buildResult()),
          Positioned(top: 30, right: 30, child: buildControlResult()),
          Positioned(
            top: Get.mediaQuery.padding.top + 8,
            left: 10,
            child: Text(
                  'QR Code Scan',
                  style: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                    color: Colors.cyan.withOpacity(0.7),
                  ),
                ),
      
          ),
        ],
      ),
    );
  }

  Widget buildResult() {
    if (barcode != null) {
      controller?.pauseCamera();

      Future.microtask(() {
        Navigator.push(context, MaterialPageRoute(builder: (context) => 
        	사용자Web(uri: barcode!.code.toString())));
        controller?.resumeCamera();
      });
    }
    return Column(
      children: [
        Text(
          barcode != null ? 'Result : ${barcode!.code}' : 'Scan a code!',
          maxLines: 3,
          style: const TextStyle(color: grayColor),
        ),
        const Text(
          'Qr 코드 용지를 사각 안에 맞혀 스캔해 주세요',
          style: TextStyle(color: grayColor),
        ),
      ],
    );
  }

  Widget buildQrView(BuildContext context) => QRView(
        key: qrKey,
        onQRViewCreated: onQRViewCreated,
        overlay: QrScannerOverlayShape(
            borderColor: Colors.cyanAccent,
            borderRadius: 10,
            borderLength: 20,
            borderWidth: 10,
            cutOutSize: MediaQuery.of(context).size.width * 0.8),
      );

  void onQRViewCreated(QRViewController _controller) {
    controller = _controller;

    controller!.scannedDataStream.listen((scanData) async {
      setState(() {
        barcode = scanData;
      });
    });
  }
}

 

  final qrKey = GlobalKey(debugLabel: 'QR');

  Barcode? barcode;
  QRViewController? controller;

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

Scanner를 실행하기 위한 기본 설정 값입니다.

controller에서 모든 작동이 이루어집니다.

카메라 플래시 설정도 controller에 들어 있으니 링크된 qr_code_scanner 페이지에서 확인해 보시기 바랍니다.

앱이 종료될 때 dispose()에서 controller를 닫아 주시면 됩니다.

 

  Widget buildQrView(BuildContext context) => QRView(
        key: qrKey,
        onQRViewCreated: onQRViewCreated,
        overlay: QrScannerOverlayShape(
            borderColor: Colors.cyanAccent,
            borderRadius: 10,
            borderLength: 20,
            borderWidth: 10,
            cutOutSize: MediaQuery.of(context).size.width * 0.8),
      );

  void onQRViewCreated(QRViewController _controller) {
    controller = _controller;

    controller!.scannedDataStream.listen((scanData) async {
      setState(() {
        barcode = scanData;
      });
    });
  }

QrScannerOverlayShape => 아래 실행된 모습을 보시면 화면 중앙의 사각형 스캔 영약을 설정해 줍니다.

onQRViewCreated => 화면에 QR용지를 촬영하면 barcode에 스캔된 데이터가 저장됩니다.

setState() => barcode에 값이 들어오면 buildResult 위젯에서 들어온 값을 처리하게 됩니다. (아래 코드)

 

  Widget buildResult() {
    if (barcode != null) {
      controller?.pauseCamera();

      Future.microtask(() {
        Navigator.push(context, MaterialPageRoute(builder: (context) => 
        	LottoWeb(uri: barcode!.code.toString())));
        controller?.resumeCamera();
      });
    }
    return Column(
      children: [
        Text(
          barcode != null ? 'Result : ${barcode!.code}' : 'Scan a code!',
          maxLines: 3,
          style: const TextStyle(color: grayColor),
        ),
        const Text(
          'Qr 코드 용지를 사각 안에 맞혀 스캔해 주세요',
          style: TextStyle(color: grayColor),
        ),
      ],
    );
  }

 

controller?.pauseCamera() => barcode에 값이 들어왔다면 카메라를 잠시 멈추게 합니다. 만약 이렇게 하지 않으면 계속 같은 값이 연속으로 들어와 buildResult가 들어온 값만큼 실행되어 Navigator.push가 그 값만큼 실행됩니다.

원하지 않는 결과를 초래하게 됩니다.

      Future.microtask(() {
        Navigator.push(context, MaterialPageRoute(builder: (context) => 
        	사용자Web(uri: barcode!.code.toString())));
        controller?.resumeCamera();
      });

Future.microtask의 역할은 barcode.code의 값이 완벽하게 넘어올 때까지 기다렸다 안의 내용을 실행시켜 줍니다.

위 코드 없이 실행되면 Navigator가 작동은 하지만 디버그 콘솔에서 넘어갈 때 오류를 확인할 수 있습니다.

같은 조건의 대기 코드로

Future.delayed(Duration.zero, () {
   // 이동
));

두 개 중 하나를 사용하시면 됩니다.

% 사용자 Web(uri: barcode!.code.toString()) => 사용자가 직접 만든 웹뷰가 있다면  barcode데이터를 넘겨 결과를 확인하는 곳입니다. %

만약 그냥 결과 값만 확인을 원하시면 Column에서 처리되니 Navigator 코드는 주석처리하시면 됩니다.

 

controller?. resumeCamera() => 카메라를 다시 활성화시켜 줍니다.

 

 

실행된 모습

반응형