어떻게 처음부터 전진 QR코드 스캐너 플러그인을 실현합니까

만약 당신이 떨림 카메라 프로그램을 만들고 싶다면, 빠른 방법은 공식 소프트웨어 Camera plugin 를 설치하는 것이다.그러나 이 플러그인은 아직 개발 중이며 사용 가능한 vision API가 없습니다.본고는 QR코드 스캔을 지원하는 안드로이드 원생 카메라 보기를 포장하여 맞춤형 떨림 카메라 보기의 작은 위젯을 만드는 방법을 보여 드리겠습니다.

장치


  • Dynamsoft Camera Enhancer :
    allprojects {
        repositories {
            google()
            jcenter()
            maven {
                url "https://download.dynamsoft.com/maven/dce/aar"
            }
        }
    }
    dependencies {
        implementation 'com.dynamsoft:dynamsoftcameraenhancer:2.0.0@aar'
    }
    

  • Dynamsoft Barcode Reader :
    allprojects {
        repositories {
            google()
            jcenter()
            maven {
                url "https://download2.dynamsoft.com/maven/dbr/aar"
            }
        }
    }
    
    dependencies {
        implementation 'com.dynamsoft:dynamsoftbarcodereader:8.8.0@aar'
    }
    

  • Android TextView에서 간단한 떨림 위젯 만들기


    이 절에서, 우리는 Flutter's tutorial Flatter 소부품TextView에 안드로이드PlatformView를 위탁 관리할 것이다.

  • 새 바이브레이션 플러그인 항목을 만들려면 다음과 같이 하십시오.
    flutter create --org com.dynamsoft --template=plugin --platforms=android -a java flutter_qrcode_scanner
    

  • Dart의 경우 lib/flutter_qrcode_scanner.dart에서 다음 코드를 확인할 수 있습니다.
    
    import 'dart:async';
    
    import 'package:flutter/services.dart';
    
    class FlutterQrcodeScanner {
      static const MethodChannel _channel = MethodChannel('flutter_qrcode_scanner');
    
      static Future<String?> get platformVersion async {
        final String? version = await _channel.invokeMethod('getPlatformVersion');
        return version;
      }
    }
    
    
    위의 코드 세그먼트를 삭제하고 다음과 같이 상태가 있는 작은 위젯을 정의합니다.
    class ScannerView extends StatefulWidget {
      const ScannerView({Key? key}) : super(key: key);
      @override
      State<StatefulWidget> createState() => _ScannerViewState();
    }
    
    class _ScannerViewState extends State<ScannerView> {
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        const String viewType = 'com.dynamsoft.flutter_qrcode_scanner/nativeview';
        final Map<String, dynamic> creationParams = <String, dynamic>{};
    
        return AndroidView(
          viewType: viewType,
          creationParams: creationParams,
          creationParamsCodec: const StandardMessageCodec(),
        );
      }
    }    
    

  • 플랫폼 쪽에서 NativeView 클래스를 만들었는데 이 클래스는 io.flutter.plugin.platform.PlatformView를 확장하여 TextView에 대한 인용을 제공합니다.
    import android.content.Context;
    import android.graphics.Color;
    import android.view.View;
    import android.widget.TextView;
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import io.flutter.plugin.platform.PlatformView;
    import java.util.Map;
    
    class NativeView implements PlatformView {
        @NonNull private final TextView textView;
    
         NativeView(@NonNull Context context, int id, @Nullable Map<String, Object> creationParams) {
             textView = new TextView(context);
             textView.setTextSize(72);
             textView.setBackgroundColor(Color.rgb(255, 255, 255));
             textView.setText("Rendered on a native Android view (id: " + id + ")");
         }
    
         @NonNull
         @Override
         public View getView() {
             return textView;
         }
    
         @Override
         public void dispose() {}
    }
    
    그리고 NativeViewFactory 클래스를 만들어서 초기화NativeView:
    import android.content.Context;
    import android.view.View;
    import androidx.annotation.Nullable;
    import androidx.annotation.NonNull;
    import io.flutter.plugin.common.BinaryMessenger;
    import io.flutter.plugin.common.StandardMessageCodec;
    import io.flutter.plugin.platform.PlatformView;
    import io.flutter.plugin.platform.PlatformViewFactory;
    import java.util.Map;
    
    class NativeViewFactory extends PlatformViewFactory {
      @NonNull private final BinaryMessenger messenger;
    
      NativeViewFactory(@NonNull BinaryMessenger messenger) {
        super(StandardMessageCodec.INSTANCE);
        this.messenger = messenger;
      }
    
      @NonNull
      @Override
      public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
        final Map<String, Object> creationParams = (Map<String, Object>) args;
        return new NativeView(context, id, creationParams);
      }
    }
    
    FlutterQrcodeScannerPlugin.java 파일에factory 클래스가 등록되어 있습니다.
    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
      channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_qrcode_scanner");
      channel.setMethodCallHandler(this);
      flutterPluginBinding.getPlatformViewRegistry().registerViewFactory(
          "com.dynamsoft.flutter_qrcode_scanner/nativeview",
          new NativeViewFactory(flutterPluginBinding.getBinaryMessenger()));
    }
    
  • 이제 이 플러그인을 사용할 수 있습니다.우리는 코드example/lib/main.dart를 정상적으로 작동하도록 변경했습니다.
    import 'package:flutter/material.dart';
    import 'dart:async';
    
    import 'package:flutter/services.dart';
    import 'package:flutter_qrcode_scanner/flutter_qrcode_scanner.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      String _platformVersion = 'Unknown';
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Plugin example app'),
            ),
            body: Center(
              child: ScannerView(),
            ),
          ),
        );
      }
    }
    
    다음 예제를 실행합니다.
    flutter run
    

    Android Camera View에서 바이브레이션 카메라 위젯 구현


    만약 위의 코드가 당신에게 유효하다면, 다음 단계는 텍스트 보기를 카메라 보기로 바꾸는 것입니다.여기서 우리는 다이나믹 소프트 카메라 증강기를 예로 들 수 있다.

  • 구성android/build.gradle:
    rootProject.allprojects {
        repositories {
            google()
            mavenCentral()
            maven {
                url "https://download.dynamsoft.com/maven/dce/aar"
            }
        }
    }
    
    android {
        compileSdkVersion 30
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    
        defaultConfig {
            minSdkVersion 21
        }
    }
    
    dependencies {
        implementation 'com.dynamsoft:dynamsoftcameraenhancer:2.0.0@aar'
    }
    
    최소 Android SDK 버전을 21 이상으로 변경해야 합니다.
  • NativeView.java에서 카메라 패키지를 가져오려면 다음과 같이 하십시오.
    import com.dynamsoft.dce.*;
    
    TextViewDCECameraView로 변경합니다.CameraEnhancer를 사용하여 카메라 미리보기를 시작하고 중지할 수 있습니다.
    private final DCECameraView cameraView;
    private CameraEnhancer cameraEnhancer;
    
    NativeView(BinaryMessenger messenger, @NonNull Activity context, int id,
            @Nullable Map<String, Object> creationParams) {
        this.context = context;
    
        cameraEnhancer = new CameraEnhancer(context);
        cameraView = new DCECameraView(context);
        cameraEnhancer.setCameraView(cameraView);
        try {
            cameraEnhancer.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    캠페인 수명 주기 동안 카메라 상태를 전환하기 위해 구현Application.ActivityLifecycleCallbacks:
    class NativeView implements PlatformView, Application.ActivityLifecycleCallbacks {
        @Override
        public void onActivityResumed(Activity activity) {
            try {
                cameraEnhancer.open();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void onActivityPaused(Activity activity) {
            try {
                cameraEnhancer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  • Activity 클래스에서 Context 가 아닌 NativeView 클래스를 사용하고 있음을 알 수 있습니다.따라서 NativeViewFactory 클래스도 변경해야 합니다.
    class NativeViewFactory extends PlatformViewFactory {
      @NonNull private final BinaryMessenger messenger;
      @NonNull private Activity activity;
    
      NativeViewFactory(@NonNull BinaryMessenger messenger, Activity activity) {
        super(StandardMessageCodec.INSTANCE);
        this.messenger = messenger;
        this.activity = activity;
      }
    
      @NonNull
      @Override
      public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
        final Map<String, Object> creationParams = (Map<String, Object>) args;
        return new NativeView(messenger, activity, id, creationParams);
      }
    }
    

  • 마지막으로 FlutterQrcodeScannerPlugin클래스에서 우리는 활동 상태를 감시하고 활동 인용을 NativeViewFactory 실례에 전달한다.
    public class FlutterQrcodeScannerPlugin implements FlutterPlugin, ActivityAware {
        private Activity activity;
        private FlutterPluginBinding flutterPluginBinding;
    
        @Override
        public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
          this.flutterPluginBinding = flutterPluginBinding;
        }
    
        @Override
        public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
          this.flutterPluginBinding = null;
        }
    
        @Override
        public void onAttachedToActivity(ActivityPluginBinding activityPluginBinding) {
          bind(activityPluginBinding);
        }
    
        @Override
        public void onReattachedToActivityForConfigChanges(ActivityPluginBinding activityPluginBinding) {
          bind(activityPluginBinding);
        }
    
        @Override
        public void onDetachedFromActivityForConfigChanges() {
          activity = null;
        }
    
        @Override
        public void onDetachedFromActivity() {
          activity = null;
        }
    
        private void bind(ActivityPluginBinding activityPluginBinding) {
          activity = activityPluginBinding.getActivity();
          flutterPluginBinding.getPlatformViewRegistry().registerViewFactory(
              "com.dynamsoft.flutter_qrcode_scanner/nativeview",
              new NativeViewFactory(flutterPluginBinding.getBinaryMessenger(), activity));
        }
    }
    
  • 떨림 카메라 보기의 작은 부품을 완성했다.그러나 이 예제를 실행하기 전에 최소 SDK 버전을 21인치example/android/build.gradle로 변경해야 합니다.

    떨림 카메라 플러그인을 떨림 QR코드 스캐너로 바꾸다


    일반적으로 우리는 미리 보기 리셋 함수에서 카메라 프레임을 가져와 진일보한 이미지 처리를 할 수 있다.개발자의 시간을 절약하기 위해서는 좋은 카메라 소부품이 시각 기능을 제공해야 한다.다음 단락에서 Dynamsoft 바코드 리더 SDK를 현재 Flatter cameraview 작은 위젯에 집적하는 방법을 보실 수 있습니다.

  • camera SDK를 사용하는 것과 마찬가지로 바코드 패키지를 build.gradle에 추가합니다.
    rootProject.allprojects {
        repositories {
            google()
            mavenCentral()
            maven {
                url "https://download.dynamsoft.com/maven/dce/aar"
            }
            maven {
                url "https://download.dynamsoft.com/maven/dbr/aar"
            }
        }
    }
    
    android {
        compileSdkVersion 30
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    
        defaultConfig {
            minSdkVersion 21
        }
    }
    
    dependencies {
        implementation 'com.dynamsoft:dynamsoftcameraenhancer:2.0.0@aar'
        implementation 'com.dynamsoft:dynamsoftbarcodereader:8.8.0@aar'
    }
    

  • Dynamsoft 카메라 증강기와 Dynamsoft 바코드 리더 SDK는 협동하여 일을 잘 할 수 있다.실시간 QR코드 검색을 위해 QRCodeScanner.java 파일에 넣습니다.
    public class QRCodeScanner {
        private CameraEnhancer mCameraEnhancer;
        private BarcodeReader reader;
        private Activity context;
        private DCECameraView cameraView;
        private DetectionHandler handler;
    
        public interface DetectionHandler {
            public void onDetected(List<Map<String, Object>> data);
        }
    
        public QRCodeScanner(Activity context, DCECameraView cameraView) {
            this.context = context;
            this.cameraView = cameraView;
            mCameraEnhancer = new CameraEnhancer(context);
            mCameraEnhancer.setCameraView(cameraView);
            cameraView.setOverlayVisible(true);
    
            DCESettingParameters dceSettingParameters = new DCESettingParameters();
            dceSettingParameters.cameraInstance = mCameraEnhancer;
            dceSettingParameters.textResultCallback = mTextResultCallback;
    
            try {
                // mCameraEnhancer.open();
                reader = new BarcodeReader();
                reader.SetCameraEnhancerParam(dceSettingParameters);
                PublicRuntimeSettings settings = reader.getRuntimeSettings();
                settings.barcodeFormatIds = EnumBarcodeFormat.BF_QR_CODE;
                reader.updateRuntimeSettings(settings);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    
        TextResultCallback mTextResultCallback = new TextResultCallback() {
            @Override
            public void textResultCallback(int i, TextResult[] results, Object userData) {
                if (results != null) {
                    final List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
                    for (TextResult result: results) {
                        final Map<String, Object> data = new HashMap<>();
                        data.put("format", result.barcodeFormatString);
                        data.put("text", result.barcodeText);
                        data.put("x1", result.localizationResult.resultPoints[0].x);
                        data.put("y1", result.localizationResult.resultPoints[0].y);
                        data.put("x2", result.localizationResult.resultPoints[1].x);
                        data.put("y2", result.localizationResult.resultPoints[1].y);
                        data.put("x3", result.localizationResult.resultPoints[2].x);
                        data.put("y3", result.localizationResult.resultPoints[2].y);
                        data.put("x4", result.localizationResult.resultPoints[3].x);
                        data.put("y4", result.localizationResult.resultPoints[3].y);
                        data.put("angle", result.localizationResult.angle);
                        ret.add(data);
                    }
    
                    if (handler != null) {
                        handler.onDetected(ret);
                    }
                }
            }
        };
    
        public void setDetectionHandler(DetectionHandler handler) {
            this.handler = handler;
        }
    
        public void startScan() {
            try {
                // mCameraEnhancer.open();
                cameraView.setOverlayVisible(true);
                reader.StartCameraEnhancer();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    
        public void stopScan() {
            try {
                // mCameraEnhancer.close();
                cameraView.setOverlayVisible(false);
                reader.StopCameraEnhancer();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    
        public void setLicense(String license) {
            try {
                reader.initLicense(license);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    
    QR코드 감지 API를 활성화하려면 valid license가 필요합니다.

  • QR코드가 감지되면 Java에서 Dart로 결과를 보내는 방법이 필요합니다.MethodChannel 클래스는Dart와 로컬 코드 사이에서 메시지를 보내고 받는 데 사용됩니다.따라서 다음 코드를 NativeView.java에 추가합니다.
    class NativeView implements PlatformView, MethodCallHandler, Application.ActivityLifecycleCallbacks, QRCodeScanner.DetectionHandler {
        @Override
        public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
            switch (call.method) {
            case "startScanning":
                qrCodeScanner.startScan();
                result.success(null);
                break;
            case "stopScanning":
                qrCodeScanner.stopScan();
                result.success(null);
                break;
            case "setLicense":
                final String license = call.argument("license");
                qrCodeScanner.setLicense(license);
                result.success(null);
                break;
            case "setBarcodeFormats":
                final int formats = call.argument("formats");
                qrCodeScanner.setBarcodeFormats(formats);
                result.success(null);
                break;
            default:
                result.notImplemented();
            }
        }
    }
    
    QR코드가 감지되면 콜백 함수onDetected가 트리거됩니다.함수는 작업 라인에서 호출되고, 방법 채널 통신은 주 라인에서 호출되어야 한다는 것을 알아야 합니다.이를 위해 runOnUiThread를 사용하여 주 스레드에 메시지를 보냅니다.
    @Override
    public void onDetected(List<Map<String, Object>> data) {
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                methodChannel.invokeMethod("onDetected", data);
            }
        });
    }
    

  • Dart의 경우 ScannerViewController에 QR코드 검사 결과를 수신하기 위한 flutter_qrcode_scanner.dart를 정의했습니다.
    class _ScannerViewState extends State<ScannerView> {
      ScannerViewController? _controller;
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        const String viewType = 'com.dynamsoft.flutter_qrcode_scanner/nativeview';
        final Map<String, dynamic> creationParams = <String, dynamic>{};
    
        return AndroidView(
          viewType: viewType,
          onPlatformViewCreated: _onPlatformViewCreated,
          creationParams: creationParams,
          creationParamsCodec: const StandardMessageCodec(),
        );
      }
    
      void _onPlatformViewCreated(int id) {
        _controller = ScannerViewController(id);
        widget.onScannerViewCreated(_controller!);
      }
    }
    
    class ScannerViewController {
      late MethodChannel _channel;
      final StreamController<List<BarcodeResult>> _streamController =
          StreamController<List<BarcodeResult>>();
      Stream<List<BarcodeResult>> get scannedDataStream => _streamController.stream;
    
      ScannerViewController(int id) {
        _channel =
            MethodChannel('com.dynamsoft.flutter_qrcode_scanner/nativeview_$id');
        _channel.setMethodCallHandler((call) async {
          switch (call.method) {
            case 'onDetected':
              if (call.arguments != null) {
                List<BarcodeResult> data = fromPlatformData(call.arguments as List);
                _streamController.sink.add(data);
              }
              break;
          }
        });
      }
    }
    
    이 메서드를 호출하는 함수는 다음과 같습니다.
    Future<void> startScanning() async {
      await _channel.invokeMethod('startScanning');
    }
    
    Future<void> stopScanning() async {
      await _channel.invokeMethod('stopScanning');
    }
    
    /// Apply for a 30-day FREE trial license: https://www.dynamsoft.com/customer/license/trialLicense
    Future<void> setLicense(String license) async {
      await _channel.invokeMethod('setLicense', {'license': license});
    }
    
  • 지금까지 전진 QR코드 스캐너 플러그인은 완전히 완성되었다.다음은 간단한 QR코드 스캐너의 전체 예입니다.
    import 'package:flutter/material.dart';
    import 'dart:async';
    
    import 'package:flutter/services.dart';
    import 'package:flutter_camera_qrcode_scanner/flutter_qrcode_scanner.dart';
    import 'package:flutter_camera_qrcode_scanner/dynamsoft_barcode.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      ScannerViewController? controller;
      String _barcodeResults = '';
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('QR Code Scanner'),
            ),
            body: Stack(children: <Widget>[
              ScannerView(onScannerViewCreated: onScannerViewCreated),
              Column(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Container(
                    height: 100,
                    child: SingleChildScrollView(
                      child: Text(
                        _barcodeResults,
                        style: TextStyle(fontSize: 14, color: Colors.white),
                      ),
                    ),
                  ),
                  Container(
                    height: 100,
                    child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: <Widget>[
                          MaterialButton(
                              child: Text('Start Scan'),
                              textColor: Colors.white,
                              color: Colors.blue,
                              onPressed: () async {
                                controller!.startScanning();
                              }),
                          MaterialButton(
                              child: Text("Stop Scan"),
                              textColor: Colors.white,
                              color: Colors.blue,
                              onPressed: () async {
                                controller!.stopScanning();
                              })
                        ]),
                  ),
                ],
              )
            ]),
          ),
        );
      }
    
      void onScannerViewCreated(ScannerViewController controller) {
        setState(() {
          this.controller = controller;
        });
        controller.setLicense('LICENSE-KEY');
        controller.startScanning(); // auto start scanning
        controller.scannedDataStream.listen((results) {
          setState(() {
            _barcodeResults = getBarcodeResults(results);
          });
        });
      }
    
      String getBarcodeResults(List<BarcodeResult> results) {
        StringBuffer sb = new StringBuffer();
        for (BarcodeResult result in results) {
          sb.write(result.format);
          sb.write("\n");
          sb.write(result.text);
          sb.write("\n\n");
        }
        if (results.isEmpty) sb.write("No QR Code Detected");
        return sb.toString();
      }
    
      @override
      void dispose() {
        controller?.dispose();
        super.dispose();
      }
    }
    

    술집에서 떨림 QR코드 스캐너를 다운로드하다.덕부


    https://pub.dev/packages/flutter_camera_qrcode_scanner

    소스 코드


    https://github.com/yushulx/flutter_qrcode_scanner

    좋은 웹페이지 즐겨찾기