Calling Native Libraries in Flutter with Dart FFI

In this tutorial, you’ll learn how to use Dart FFI to access native libraries that support C-interoperability. By Nick Fisher.

5 (6) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Receiving a Struct in Dart

Receiving a struct data type means you need to create a Dart class that mimics the layout and naming of this struct, allowing Dart FFI to easily bridge between the native C type and the Dart type.

In ffi_bridge.dart, locate // TODO: Add ThreeDayForecast here and replace it with:

class ThreeDayForecast extends Struct {
  // 1
  @Double()
  external double get today;
  external set today(double value);

  @Double()
  external double get tomorrow;
  external set tomorrow(double value);

  @Double()
  external double get day_after;
  external set day_after(double value);

  // 2
  @override
  String toString() {
    return 'Today : ${today.toStringAsFixed(1)}\n'
        'Tomorrow : ${tomorrow.toStringAsFixed(1)}\n'
        'Day After ${day_after.toStringAsFixed(1)}';
  }
}

// 3
typedef ThreeDayForecastFunction = ThreeDayForecast Function(Uint8 useCelsius);
typedef ThreeDayForecastFunctionDart = ThreeDayForecast Function(
    int useCelsius);

Here:

  1. The Double() annotation indicates the native type of each field to Dart FFI.
  2. You return the forecast listed to one decimal point.
  3. The typedef indicates the method will have a return type of this class and expects a single int (Dart) / Uint8 C argument. There’s no matching FFI Boolean type, so you use an unsigned 8-bit integer instead.
Note: It’s important to note that get_three_day_forecast returns the ThreeDayForecast struct by value, not by reference. To review the difference between pass-by-value and pass-by-reference, check out this article.

You created a Dart class that can receive the values in the C ThreeDayForecast struct. Now, you can add the code needed to invoke the get_three_day_forecast function.

Binding the Native Struct to a Dart Class

The last feature you’ll add is getting the three-day forecast.

Still in ffi_bridge.dart, locate and replace // TODO: Add _getThreeDayForecast here with:

ThreeDayForecastFunctionDart _getThreeDayForecast;

Here you added a _getThreeDayForecast property to your FFIBridge class, representing the Dart function that will bridge to a C function.

Find // TODO: Assign value to _getThreeDayForecast here and replace it with:

_getThreeDayForecast = dl.lookupFunction<ThreeDayForecastFunction,
        ThreeDayForecastFunctionDart>('get_three_day_forecast');

This uses DynamicLibrary to look up the C function by name get_three_day_forecast with the arguments and return type specified by the ThreeDayForecastFunction typedef.

Fially, you need to return the three-day forecast. You guessed it, replace // TODO: Add getThreeDayForecast() here with:

ThreeDayForecast getThreeDayForecast(bool useCelsius) {
    return _getThreeDayForecast(useCelsius ? 1 : 0);
}

In this code, you added a getThreeDayForecast method to call this function and return an instance of the Dart class ThreeDayForecast that contains the result.

Finally, in main.dart change // TODO: Add code to invoke newly created 3-day forecast (Fahrenheit) method and the throw to call this method when the user presses the relevant button:

_show(_ffiBridge.getThreeDayForecast(false));

Do the same for // TODO: Add code to invoke newly created 3-day forecast (Celsius) and throw:

_show(_ffiBridge.getThreeDayForecast(true));

This last update removed the last error shown on the Dart Analysis tab. :]

Build and run. Tap 3-day forecast (Fahrenheit):

Screen shot of successful 3-day forecast (Fahrenheit) data retrieved.

Tap anywhere on the barrier to dismiss the dialog. Then tap 3-day forecast (Celsius):

Screen shot of successful 3-day forecast (Celsius) data retrieved.

Looking good! You passed a bool argument to, and returned a struct from, your native function.

With that, WeatherFFI is complete! It looks like you’ll need some lotion and sunglasses for the next few days.

Happy sun wearing sunglasses.

Admittedly, the forecast will never change, so don’t rely on it if you’re deciding whether to take an umbrella tomorrow.

But in terms of learning how to call native code directly from Dart, it’s a resounding success. You now know how to compile, declare, locate and invoke a native function from within a Flutter app on both iOS and Android.

Now that you understand how to use Dart FFI to invoke native code, take a look at when you might want to use FFI and when you might want to use platform channels.

Platform Channels vs Dart FFI

You’ve already seen a few use cases for platform channels compared with FFI.

In general, use platform channels for device or OS-specific functionality like cameras, notifications and integrations with other apps. Android, iOS, desktop and web apps all expose different APIs for taking advantage of that functionality.

Use FFI if you’re writing a Flutter app that needs third-party, platform-agnostic libraries. Examples include machine learning libraries, rendering engines, cryptography and signal processing.

While it’s technically possible to use FFI for your own standalone native code, it’s more likely you’ll need FFI to integrate libraries like OpenCV, Tensorflow or PyTorch into your Flutter app.

Note: Dart FFI currently isn’t available for Flutter Web apps. It isn’t marked as stable for Flutter Windows apps yet.

Where to Go From Here?

Download the completed project files by clicking Download Materials at the top or bottom of the tutorial.

To avoid tedious boilerplate typedef code, check out the official ffigen repository, or browse some more FFI samples at the official Dart ffi repository. If you’re interested in understanding FFI in a bit more detail, read the official Flutter documentation on implementing Dart FFI.

If you want to use FFI to bind to a game engine, check out How to Create a 2D Snake Game in Flutter for some ideas about where to draw the line between your Flutter code and your native library.

FFI can be tricky, so please join the forum discussion below if you have any questions or run into any issues. In the meantime, you also might want to check the actual weather report for your area to minimize the risk of wearing Hawaiian shirts when it’s sub-zero and snowing!