Вызов библиотеки C из FlutterDesktop MacOS
Как вызвать библиотеку c из FlutterDesktop (MacOS)? Хм….
Все в одном ресурсе Flutter: https://flatteredwithflutter.com/flutterdesktop-and-c/
Начинать…
Уровень: средний
Предварительные требования: Установить пакет FFI
В этой статье предполагается, что читатель знает о FFI. Если нет, отметьте это.
Мы кратко расскажем о
- Создание библиотеки C
- Интегрируйте библиотеку C в Flutter MacOS
- Звонок из Flutter MacOS
Примечание. Мы не будем подробно рассказывать о Dart FFI, так как ему посвящены хорошие статьи.
Создание библиотеки C
Каждая сложная вещь начинается с простого. Давайте создадим простую библиотеку C (Hello World)
Представляем CMake и makefile
Создание библиотеки c включает в себя множество команд, вы можете использовать их либо CMake.
Согласно документации
CMake - это расширяемая система с открытым исходным кодом, которая управляет процессом сборки в операционной системе независимо от компилятора.
Установите CMake, используя
brew install cmake
CMake использует текстовый файл с именем CMakeLists.txt в домашнем каталоге программного пакета, чтобы указать действия, необходимые для настройки программного обеспечения. Пользователь начинает процесс сборки, перейдя в домашний каталог и набрав
cmake .
CMake выполнит процесс настройки, после чего в домашнем каталоге будет создан традиционный Makefile. Затем программный процесс завершается вводом
make
Создайте файл заголовка C, hello.h, в котором есть 1 объявление функции.
void hello_world();
Давайте импортируем этот файл заголовка в наш hello.c
#include <stdio.h> #include "hello.h" // OUR HEADER FILE int main() { hello_world(); // FUNCTION FROM HEADER FILE return 0; } void hello_world() // IMPLEMENTATION OF FUNCTION { printf("Hello World\n"); }
Наша структура папок выглядит так
Наконец, внутри нашего CMakeLists.txt мы определяем команды как
cmake_minimum_required(VERSION 3.10) project(first_c VERSION 1.0 LANGUAGES C) add_library(first_c SHARED hello.c) add_executable(hello_test hello.c) set_target_properties(first_c PROPERTIES PUBLIC_HEADER hello.h VERSION ${PROJECT_VERSION} SOVERSION 1 OUTPUT_NAME "hello" )
Примечание: Список команд CMake
- cmake_minimum_required: установите минимально необходимую версию CMake для проекта.
- проект: укажите название, версию и включите языки для всего проекта.
Здесь мы используем first_c (имя нашей родительской папки), версию 1.0 и язык как C.
- add_library: добавьте библиотеку в проект, используя указанные исходные файлы.
Наш проект - first_c, и мы указываем общую (динамическую библиотеку), которая будет создана из нашей программы hello.c.
- add_executable: добавьте исполняемый файл в проект, используя указанные исходные файлы.
Это создает исполняемый файл (hello_test) из нашего источника (hello.c), который мы можем протестировать для нашей сгенерированной общей библиотеки.
- set_target_properties: Цели могут иметь свойства, влияющие на их построение.
Здесь наш проект first_c, а свойства записываются как
PROPERTIES prop1 value1
Теперь запустите команды
cmake . make
Теперь вы увидите нашу структуру папок как:
Ура, теперь у нас есть libhello.dylib !!
Интегрируйте библиотеку C в Flutter MacOS
Теперь нам нужно интегрировать библиотеку C в наше приложение Flutter Desktop.
Необходимые шаги описаны в этой ссылке, следуйте вместе со статьей или видео выше.
- Откройте
yourapp/macos/Runner.xcworkspace
в Xcode - Перетащите предварительно скомпилированную библиотеку (
libyourlibrary.dylib
) вRunner/Frameworks
. - Щелкните
Runner
и перейдите на вкладкуBuild Phases
.
- Перетащите
libyourlibrary.dylib
в списокCopy Bundle Resources
. - В разделе
Bundle Framework
отметьтеCode Sign on Copy
. - В разделе
Link Binary With Libraries
установлен статусOptional
.
4. Щелкните Runner
и перейдите на вкладку General
.
- Перетащите
libyourlibrary.dylib
в списокFrameworks, Libararies and Embedded Content
. - Выберите
Embed & Sign
.
Структура вашего проекта Flutter Desktop должна выглядеть так
Звонок из Flutter MacOS
Теперь мы будем вызывать наши динамические библиотеки из Flutter Desktop.
- Импортируйте пакет dart ffi (присутствует внутри Flutter) как
import 'dart:ffi' as ffi
У этого есть класс DynamicLibrary. Мы вызываем метод open и загружаем нашу динамическую библиотеку (libhello.dylib).
- Найдите символ в загруженной динамической библиотеке с помощью lookup или lookupFunction.
- Наконец, вызовите функцию «hello_world» (отображается из файла заголовка .h)
typedef hello_world_func = ffi.Void Function(); void openFromFlutter() { final sysLib = ffi.DynamicLibrary.open('libhello.dylib'); final HelloWorld hello = sysLib .lookup<ffi.NativeFunction<hello_world_func>>('hello_world') .asFunction(); hello(); // Call the function }
БОНУС
Допустим, у нас есть функция в заголовочном файле C, подобная этой
char *sayHello(char *str);
Поскольку он принимает входной параметр и тип возвращаемого значения как указатель символа, нам необходимо преобразовать наши строки Flutter в / из указателя.
- Мы указываем функции SystemCHello и SystemDartHello, которые в основном
typedef SystemCHello = ffi.Pointer<Utf8> Function(ffi.Pointer<Utf8> str); typedef SystemDartHello = ffi.Pointer<Utf8>Function(ffi.Pointer<Utf8> str);
- Преобразуйте нашу Flutter String в Utf8 и передайте ее функции
final sysLib = ffi.DynamicLibrary.open('libfetchtemp.dylib'); final helloFromC = sysLib.lookupFunction<SystemCHello, SystemDartHello>('sayHello'); // Pass input final name = Utf8.toUtf8(input); // Call the function final res = helloFromC(name);
- Поскольку значение, возвращаемое функцией, также является указателем, мы преобразуем его в Flutter String.
// Convert response into string final strRes = Utf8.fromUtf8(res);
Интересные статьи, связанные с Flutter, здесь: