我的Flutter一维码,二维码插件已经支持Android,Windows和Web。这篇文章继续添加新的平台:Linux。
Flutter插件下载
https://pub.dev/packages/flutter_barcode_sdk
学习资源
- https://flutter.dev/desktop
- https://github.com/google/flutter-desktop-embedding
- https://github.com/flutter/samples/tree/master/experimental/desktop_photo_search
使用Dart和C++开发Flutter Linux插件
要开发Linux插件,需要把开发平台切换到Linux。我使用统信UOS。
在当前的插件项目中添加Linux插件的模板:
flutter create --template=plugin --platforms=linux .
命令执行之后会生成如下的目录结构:
- include/
- CMakeLists.txt
- flutter_barcode_sdk_plugin.cc
接下来创建一个lib
目录。把下载的Dynamsoft Barcode Reader C++ 压缩包里的*.so
库文件拷贝到目录中。然后在CMakeLists.txt
中配置link_directories
, target_link_libraries
和flutter_barcode_sdk_bundled_libraries
:
cmake_minimum_required(VERSION 3.10)
set(PROJECT_NAME "flutter_barcode_sdk")
project(${PROJECT_NAME} LANGUAGES CXX)
# This value is used when generating builds using this plugin, so it must
# not be changed
set(PLUGIN_NAME "flutter_barcode_sdk_plugin")
link_directories("${PROJECT_SOURCE_DIR}/bin/")
add_library(${PLUGIN_NAME} SHARED
"flutter_barcode_sdk_plugin.cc"
)
apply_standard_settings(${PLUGIN_NAME})
set_target_properties(${PLUGIN_NAME} PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
target_include_directories(${PLUGIN_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter "DynamsoftBarcodeReader")
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
# List of absolute paths to libraries that should be bundled with the plugin
set(flutter_barcode_sdk_bundled_libraries
"${PROJECT_SOURCE_DIR}/lib/"
PARENT_SCOPE
)
到此,动态链接库的编译链接已经没有问题了,开始写C++代码。打开flutter_barcode_sdk_plugin.cc
找到flutter_barcode_sdk_plugin_handle_method_call()
函数。这里是Dart通向C++的入口。我们先构造基本的接口名判断代码:
static void flutter_barcode_sdk_plugin_handle_method_call(
FlutterBarcodeSdkPlugin* self,
FlMethodCall* method_call) {
g_autoptr(FlMethodResponse) response = nullptr;
const gchar* method = fl_method_call_get_name(method_call);
FlValue* args = fl_method_call_get_args(method_call);
if (strcmp(method, "getPlatformVersion") == 0) {
struct utsname uname_data = {};
uname(&uname_data);
g_autofree gchar *version = g_strdup_printf("Linux %s. Dynamsoft Barcode Reader version: %s", uname_data.version, self->manager->GetVersion());
g_autoptr(FlValue) result = fl_value_new_string(version);
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
else if (strcmp(method, "setLicense") == 0) {
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
else if (strcmp(method, "decodeFile") == 0) {
response = FL_METHOD_RESPONSE(fl_method_success_response_new(results));
}
else if (strcmp(method, "decodeFileBytes") == 0) {
response = FL_METHOD_RESPONSE(fl_method_success_response_new(results));
}
else if (strcmp(method, "decodeImageBuffer") == 0) {
response = FL_METHOD_RESPONSE(fl_method_success_response_new(results));
}
else if (strcmp(method, "setBarcodeFormats") == 0) {
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
} else {
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
}
fl_method_call_respond(method_call, response, nullptr);
}
然后要解决数据类型转换及封装。Linux的头文件和Windows上的完全不同,不能直接使用。可以参考example/linux/flutter/ephemeral/flutter_linux/fl_value.h
里的定义。
以下是Dart传入参数到C++的类型转换:
String转换
FlValue* value = fl_value_lookup_string(args, "license");
const char* license = fl_value_get_string(value);
Int转换
value = fl_value_lookup_string(args, "width");
int width = fl_value_get_int(value);
Bytes转换
FlValue* value = fl_value_lookup_string(args, "bytes");
unsigned char* bytes = (unsigned char*)fl_value_get_uint8_list(value);
和Windows一样,所有的解码实现都封装在barcode_manager.h
中。不同的是返回类型:
FlValue* WrapResults()
{
FlValue* out = fl_value_new_list();
TextResultArray *results = NULL;
reader->GetAllTextResults(&results);
if (results == NULL || results->resultsCount == 0)
{
printf("No barcode found.\n");
}
else
{
for (int index = 0; index < results->resultsCount; index++)
{
FlValue* map = fl_value_new_map ();
fl_value_set_string_take (map, "format", fl_value_new_string(results->results[index]->barcodeFormatString));
fl_value_set_string_take (map, "text", fl_value_new_string(results->results[index]->barcodeText));
fl_value_set_string_take (map, "x1", fl_value_new_int(results->results[index]->localizationResult->x1));
fl_value_set_string_take (map, "y1", fl_value_new_int(results->results[index]->localizationResult->y1));
fl_value_set_string_take (map, "x2", fl_value_new_int(results->results[index]->localizationResult->x2));
fl_value_set_string_take (map, "y2", fl_value_new_int(results->results[index]->localizationResult->y2));
fl_value_set_string_take (map, "x3", fl_value_new_int(results->results[index]->localizationResult->x3));
fl_value_set_string_take (map, "y3", fl_value_new_int(results->results[index]->localizationResult->y3));
fl_value_set_string_take (map, "x4", fl_value_new_int(results->results[index]->localizationResult->x4));
fl_value_set_string_take (map, "y4", fl_value_new_int(results->results[index]->localizationResult->y4));
fl_value_set_string_take (map, "angle", fl_value_new_int(results->results[index]->localizationResult->angle));
fl_value_append_take (out, map);
}
}
CBarcodeReader::FreeTextResults(&results);
return out;
}
FlValue* DecodeFile(const char * filename)
{
FlValue* out = fl_value_new_list();
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();
}
FlValue* DecodeFileBytes(const unsigned char * bytes, int size)
{
reader->DecodeFileInMemory(bytes, size, "");
return WrapResults();
}
FlValue* 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();
}
全部搞定。由于Dart的代码是和Windows共用的,所以不需要修改上层代码。现在运行Linux桌面读码程序:
flutter run -d linux
视频
<iframe allowfullscreen="true" data-mediaembed="bilibili" id="FjLjJLXC-1621931869941" src="https://player.bilibili.com/player.html?aid=290386360"></iframe>Flutter开发统信UOS桌面读码App
源码
https://github.com/yushulx/flutter_barcode_sdk