Вызов библиотеки C из FlutterDesktop MacOS

Как вызвать библиотеку c из FlutterDesktop (MacOS)? Хм….

Все в одном ресурсе Flutter: https://flatteredwithflutter.com/flutterdesktop-and-c/

Начинать…

Уровень: средний

Предварительные требования: Установить пакет FFI

В этой статье предполагается, что читатель знает о FFI. Если нет, отметьте это.

Мы кратко расскажем о

  1. Создание библиотеки C
  2. Интегрируйте библиотеку C в Flutter MacOS
  3. Звонок из 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.

Необходимые шаги описаны в этой ссылке, следуйте вместе со статьей или видео выше.

  1. Откройте yourapp/macos/Runner.xcworkspace в Xcode
  2. Перетащите предварительно скомпилированную библиотеку (libyourlibrary.dylib) в Runner/Frameworks.
  3. Щелкните 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, здесь:







Исходный код для настольного приложения Flutter.