Pre-Requisite: Install package FFI

This article assumes that the reader has knowledge about FFI. In case not, check this.

We will cover briefly about

  1. Creating C Library
  2. Integrate C Library in Flutter MacOS
  3. Call from Flutter MacOS

Note: We won’t be explaining in-depth about Dart FFI as there are good articles dedicated to it.

Creating C Library

Every complicated thing starts with a basic thing. Let’s create a simple C library (Hello World)

Introducing CMake and makefile

Creating a c library involves a bunch of commands, either you can use those or you can utilize CMake.

FlutterDesktop and C | CMake
FlutterDesktop and C | CMake

As per the documentation

CMake is an extensible, open-source system that manages the build process in an operating system and in a compiler-independent manner.

Install CMake using

brew install cmake

CMake uses a text file named CMakeLists.txt, in the home directory of the software package, to specify the actions that are necessary to set up the software. The user begins the build process by moving to the home directory and typing

cmake .

CMake will carry out a configuration process, after which a traditional Makefile will be created in the home directory. The software process is then completed by typing


Create a C header file, hello.h, which has 1 function declaration

void hello_world();

Let’s import this header file in our 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");

Our folder structure looks like this

FlutterDesktop and C | Folder Structure | Before
FlutterDesktop and C | Folder Structure | Before

Finally, inside our CMakeLists.txt we define the commands as

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
    OUTPUT_NAME "hello"

Note: CMake commands list

  • cmake_minimum_required: Set the minimum required version of CMake for a project.
  • project: Set a name, version, and enable languages for the entire project.

Here, we are using first_c (our parent folder name), version 1.0, and language as C.

  • add_library: Add a library to the project using the specified source files.

Our project is first_c and we specify Shared (Dynamic Library) to be created out of our hello.c program

  • add_executable: Add an executable to the project using the specified source files.

This creates an executable(hello_test) from our source (hello.c), which we can test for our generated shared library.

  • set_target_properties: Targets can have properties that affect how they are built.

Here, our project is first_c, and properties are written as 

PROPERTIES prop1 value1

Now run the commands 

cmake .

You will see our folder structure now as:

FlutterDesktop and C | Folder Structure | After
FlutterDesktop and C | Folder Structure | After

Hurray, we have our libhello.dylib now!!

Integrate C Library in Flutter MacOS

Now we need to integrate the C library in our Flutter Desktop application.

The steps needed are documented in this link, follow along with the article or the above video.

  1. Open the yourapp/macos/Runner.xcworkspace in Xcode
  2. Drag your precompiled library (libyourlibrary.dylib) into Runner/Frameworks.
  3. Click Runner and go to the Build Phases tab.
  • Drag libyourlibrary.dylib into the Copy Bundle Resources list.
  • Under Bundle Framework, check Code Sign on Copy.
  • Under, Link Binary With Libraries set status to Optional.

4. Click Runner and go to the General tab.

  • Drag libyourlibrary.dylib into the Frameworks, Libararies and Embedded Content list.
  • Select Embed & Sign.

Your Flutter Desktop project structure should look like this

FlutterDesktop and C | Folder Structure | Flutter
FlutterDesktop and C | Folder Structure | Flutter

Call from Flutter MacOS

We will call our dynamic libraries from Flutter Desktop now.

  • Import the dart ffi package(present inside Flutter) as
import 'dart:ffi' as ffi

This has a class DynamicLibrary. We call the method open and load our dynamic library (libhello.dylib).

  • Lookup for the symbol from the loaded dynamic library using lookup or lookupFunction.
  • Finally, call the function ‘hello_world’ (exposed from header file .h)
typedef hello_world_func = ffi.Void Function();

void openFromFlutter() {
  final sysLib ='libhello.dylib');

  final HelloWorld hello = sysLib
  hello(); // Call the function


Let’s say we have a function in the C header file like this

char *sayHello(char *str);

Since this accepts the input parameter and the return type as char pointer, we need to convert our Flutter Strings to/from Pointer.

  • We specify SystemCHello and SystemDartHello functions, which basically are
typedef SystemCHello = ffi.Pointer<Utf8> Function(ffi.Pointer<Utf8> str);

typedef SystemDartHello = ffi.Pointer<Utf8>Function(ffi.Pointer<Utf8> str);
  • Convert our Flutter String to Utf8 and pass it to the function
final sysLib ='libfetchtemp.dylib');

final helloFromC = sysLib.lookupFunction<SystemCHello, SystemDartHello>('sayHello');

// Pass input
final name = Utf8.toUtf8(input);

// Call the function
final res = helloFromC(name);
  • Since the value returned from the function, is also a pointer, we convert it to Flutter String
// Convert response into string
final strRes = Utf8.fromUtf8(res);

Source code for Flutter Desktop App.

Valuable comments