Flutter Barcode 플러그인: Windows 데스크톱용 C++ 코드 작성

38398 단어 flutterwindowsbarcode
지난 주에 저는 Dynamsoft Barcode Reader로 Flutter 바코드 SDK 플러그인을 빌드하는 방법을 공유하는 step-by-step tutorial 글을 썼습니다. Android의 플랫폼별 코드가 완료되었습니다. 이번 주에는 Windows 데스크톱에 집중하겠습니다. Flutter 데스크톱 플러그인 개발은 아직 초기 단계이므로 사용 가능한 학습 리소스가 그리 많지 않습니다. C++를 사용하여 데스크톱 플러그인 구현을 탐색하는 것은 흥미롭고 어려울 것입니다.



알아야 할 사항



  • 학습 자료



    다음 리소스는 Flutter Windows 플러그인 개발에 영감을 줍니다.
  • https://flutter.dev/desktop
  • https://github.com/google/flutter-desktop-embedding
  • https://github.com/flutter/samples/tree/master/experimental/desktop_photo_search

  • Flutter Windows 플러그인에 C++ Barcode SDK 통합


    windows plugin 폴더 구조를 살펴보겠습니다.

    bin
      /DynamsoftBarcodeReaderx64.dll
    
    include
    
      /flutter_barcode_sdk
    
        /flutter_barcode_sdk_plugin.h
    
      /barcode_manager.h
    
      /DynamsoftBarcodeReader.h
    
      /DynamsoftCommon.h
    
    lib
      /DBRx64.lib
    
    CMakeLists.txt
    
    flutter_barcode_sdk_plugin.cpp
    


  • CMakeLists.txt는 cmake의 빌드 구성 파일입니다.
  • flutter_barcode_sdk_plugin.cpp에서 Dynamsoft Barcode SDK를 호출하는 C++ 코드를 작성합니다.
  • DynamsoftBarcodeReaderx64.dll , DBRx64.lib , DynamsoftBarcodeReader.hDynamsoftCommon.h 파일이 바코드 SDK 설치 프로그램에서 추출됩니다.
  • flutter_barcode_sdk_plugin.cpp 외에도 일부 바코드 디코딩 논리가 barcode_manager.h에 구현되어 있습니다.

  • HandleMethodCall() 메서드 시작하기


    HandleMethodCall() 메서드는 DartC++ 사이의 연결점입니다. 이 함수에서 Dart 메서드와 해당 인수를 구문 분석할 수 있습니다.

    void FlutterBarcodeSdkPlugin::HandleMethodCall(
          const flutter::MethodCall<flutter::EncodableValue> &method_call,
          std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result)
      {
        const auto *arguments = std::get_if<EncodableMap>(method_call.arguments());
    
        if (method_call.method_name().compare("getPlatformVersion") == 0)
        {
    
        }
        else if (method_call.method_name().compare("setLicense") == 0)
        {
    
        }
        else if (method_call.method_name().compare("decodeFile") == 0)
        {
    
        }
        else if (method_call.method_name().compare("decodeFileBytes") == 0)
        {
    
        }
        else if (method_call.method_name().compare("decodeImageBuffer") == 0)
        {
    
        }
        else
        {
          result->NotImplemented();
        }
      }
    
    } 
    


    여기에 필요한 C++ 데이터 유형에는 string , intvector<unsigned char> 가 포함됩니다. Dart 데이터 유형을 C++ 데이터 유형으로 변환하기 위해 다음을 사용합니다.

    std::string filename;
    auto filename_it = arguments->find(EncodableValue("filename"));
    if (filename_it != arguments->end())
    {
      filename = std::get<std::string>(filename_it->second);
    }
    
    
    std::vector<unsigned char> bytes;
    auto bytes_it = arguments->find(EncodableValue("bytes"));
    if (bytes_it != arguments->end())
    {
      bytes = std::get<vector<unsigned char>>(bytes_it->second);
    }
    
    int width = 0;
    auto width_it = arguments->find(EncodableValue("width"));
    if (width_it != arguments->end())
    {
      width = std::get<int>(width_it->second);
    }
    


    반환 값의 유형은 Flutter 데이터 유형이어야 합니다.

    EncodableList results;
    result->Success(results);
    


    따라서 다음 섹션에서는 바코드를 디코딩하고 결과를 Flutter C++ 데이터 유형으로 캡슐화하는 방법에 대해 설명합니다.

    barcode_manager.h에서 BarcodeManager 클래스 만들기



    다음과 같이 세 가지 바코드 디코딩 방법을 정의합니다.

    EncodableList DecodeFile(const char * filename) 
    {
        EncodableList out;   
        int ret = reader->DecodeFile(filename, "");
    
        if (ret == DBRERR_FILE_NOT_FOUND)
        {
            printf("Error code %d. %s\n", ret, CBarcodeReader::GetErrorString(ret));
            return out;
        }
    
        return WrapResults();
    }
    
    EncodableList DecodeFileBytes(const unsigned char * bytes, int size) 
    {
        reader->DecodeFileInMemory(bytes, size, "");
        return WrapResults();
    }
    
    EncodableList DecodeImageBuffer(const unsigned char * buffer, int width, int height, int stride, int format) 
    {
        ImagePixelFormat pixelFormat = IPF_BGR_888;
        switch(format) {
            case 0:
                pixelFormat = IPF_GRAYSCALED;
                break;
            case 1:
                pixelFormat = IPF_ARGB_8888;
                break;
        }
    
        reader->DecodeBuffer(buffer, width, height, stride, pixelFormat, "");
    
        return WrapResults();
    }
    


    어떤 것을 호출하든 데이터를 캡슐화하는 방법은 동일합니다.

    EncodableList WrapResults() 
    {
        EncodableList out;
        TextResultArray *results = NULL;
        reader->GetAllTextResults(&results);
    
        if (results->resultsCount == 0)
        {
            printf("No barcode found.\n");
            CBarcodeReader::FreeTextResults(&results);
        }
    
        for (int index = 0; index < results->resultsCount; index++)
        {
            EncodableMap map;
            map[EncodableValue("format")] = results->results[index]->barcodeFormatString;
            map[EncodableValue("text")] = results->results[index]->barcodeText;
            map[EncodableValue("x1")] = results->results[index]->localizationResult->x1;
            map[EncodableValue("y1")] = results->results[index]->localizationResult->y1;
            map[EncodableValue("x2")] = results->results[index]->localizationResult->x2;
            map[EncodableValue("y2")] = results->results[index]->localizationResult->y2;
            map[EncodableValue("x3")] = results->results[index]->localizationResult->x3;
            map[EncodableValue("y3")] = results->results[index]->localizationResult->y3;
            map[EncodableValue("x4")] = results->results[index]->localizationResult->x4;
            map[EncodableValue("y4")] = results->results[index]->localizationResult->y4;
            out.push_back(map);
        }
    
        CBarcodeReader::FreeTextResults(&results);
        return out;
    }
    


  • EncodableMap는 모든 바코드 반환 값을 저장하는 데 사용됩니다.
  • EncodableList는 모든 EncodableMap를 저장하는 데 사용됩니다.

  • Flutter Windows 플러그인용 CMake 구성



    CMake 빌드를 통과하려면 타사 동적 라이브러리를 연결하고 번들하는 방법을 파악해야 합니다.
  • 링크 Dynamsoft 바코드 판독기:

  •   link_directories("${PROJECT_SOURCE_DIR}/lib/") 
      target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin "DBRx64")
    


  • 번들 Dynamsoft 바코드 판독기:

  •   set(flutter_barcode_sdk_bundled_libraries
        "${PROJECT_SOURCE_DIR}/bin/"
        PARENT_SCOPE
      )
    


    Windows용 Flutter 데스크탑 바코드 리더기



    지금까지 Flutter Windows 플러그인을 구현했습니다. 간단한 Windows 데스크톱 바코드 판독 응용 프로그램을 구축할 때입니다.

    첫 번째 단계는 새 Flutter 프로젝트를 만들고 pubspec.yaml에 종속성을 추가하는 것입니다.

    dependencies:
      flutter:
        sdk: flutter
    
      flutter_barcode_sdk:
    


    그런 다음 Barcode Reader 개체를 초기화합니다.

    class _DesktopState extends State<Desktop> {
      String _platformVersion = 'Unknown';
      final _controller = TextEditingController();
      String _barcodeResults = '';
      FlutterBarcodeSdk _barcodeReader;
      bool _isValid = false;
      String _file = '';
    
      @override
      void initState() {
        super.initState();
        initPlatformState();
        initBarcodeSDK();
      }
    
      Future<void> initBarcodeSDK() async {
        _barcodeReader = FlutterBarcodeSdk();
        // Get 30-day FREEE trial license from https://www.dynamsoft.com/customer/license/trialLicense?product=dbr
        await _barcodeReader.setLicense('LICENSE-KEY');
      }
    }
    


    UI 측면에서 TextField , Image , MaterialButtonText 를 포함한 다양한 위젯을 결합합니다.
  • TextFiedl: 이미지 경로를 입력합니다.
  • 이미지: 바코드 이미지를 표시합니다.
  • MaterialButton: 바코드 디코딩을 트리거합니다.
  • 텍스트: 바코드 결과를 표시합니다.

  • 다음은 UI 코드 스니펫입니다.

    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: const Text('Dynamsoft Barcode Reader'),
            ),
            body: Column(children: [
              Container(
                height: 100,
                child: Row(children: <Widget>[
                  Text(
                    _platformVersion,
                    style: TextStyle(fontSize: 14, color: Colors.black),
                  )
                ]),
              ),
              TextField(
                controller: _controller,
                decoration: InputDecoration(
                  labelText: 'Input an image path',
                  errorText: _isValid ? null : 'File not exists',
                ),
              ),
              Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    children: [
                      getDefaultImage(),
                      Text(
                        _barcodeResults,
                        style: TextStyle(fontSize: 14, color: Colors.black),
                      ),
                    ],
                  ),
                ),
              ),
              Container(
                height: 100,
                child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      MaterialButton(
                          child: Text('Decode Barcode'),
                          textColor: Colors.white,
                          color: Colors.blue,
                          onPressed: () async {
                            if (_controller.text.isEmpty) {
                              setState(() {
                                _isValid = false;
                                _barcodeResults = '';
                                _file = '';
                              });
                              return;
                            }
                            File file = File(_controller.text);
                            if (!file.existsSync()) {
                              setState(() {
                                _isValid = false;
                                _barcodeResults = '';
                                _file = '';
                              });
                              return;
                            } else {
                              setState(() {
                                _isValid = true;
                                _file = _controller.text;
                              });
                            }
                            Uint8List bytes = await file.readAsBytes();
                            List<BarcodeResult> results =
                                await _barcodeReader.decodeFileBytes(bytes);
                            setState(() {
                              _barcodeResults = getBarcodeResults(results);
                            });
                          }),
                    ]),
              ),
            ])),
      );
    }
    


    지정된 이미지 파일이 없으면 자산에서 기본 이미지를 로드합니다.

    Widget getDefaultImage() {
      if (_controller.text.isEmpty || !_isValid) {
        return Image.asset('images/default.png');
      } else {
        return Image.file(File(_file));
      }
    }
    


    그동안 pubspec.yaml에 자산 구성을 추가하는 것을 잊지 마십시오.

    flutter:
      assets:
        - images/default.png
    


    마지막으로 다음을 사용하여 Windows 바코드 판독기 응용 프로그램을 실행할 수 있습니다.

    flutter run -d windows
    




    할 것



    iOS, 웹

    소스 코드



    https://github.com/yushulx/flutter_barcode_sdk

    좋은 웹페이지 즐겨찾기