添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
In this tutorial, you’ll learn how to use Dart FFI to access native libraries that support C-interoperability. By Nick Fisher. With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more! Create account Already a member of Kodeco? Sign in With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more! Create account Already a member of Kodeco? Sign in

Binding Functions That Return Pointers

The double your C function returns is a stack-allocated primitive that freely passes between C and Dart code without any memory concerns.

What if you want to obtain a Dart String from your C function? The C standard library has no concept of a string, so you can only work with NULL-terminated char array pointers.

Note : If you need a refresher on scope and memory allocation in C, you might want to read these lecture slides.

Proper Scope

You might feel tempted to add the following to weather.c , but don’t:

char* get_forecast() { char* forecast = "sunny"; return forecast;

This code will compile unless you’ve turned on the right compiler warnings, but it isn’t valid C!

Why? Because you created a stack-allocated char array, which is only valid within the scope of this function. Once you return the pointer to your Dart code, this no longer points to a valid char array in memory.

To safely return a char pointer, you must return a pointer to properly allocated memory.

Add the following code to weather.c :

char* get_forecast() { char* forecast = "sunny"; char* forecast_m = malloc(strlen(forecast)); strcpy(forecast_m, forecast); return forecast_m;

This function creates a local char pointer for the string "sunny" , allocates memory for a char pointer memory on the heap of the same size, and copies the contents of the former into the latter.

Then add the following C library include s to the top of weather.c :

#include <string.h> #include <stddef.h> #include <stdbool.h> #include <stdlib.h>

This code includes header files from the C standard library so that you can use strcpy , strlen and a few other functions and types you’ll see later in this tutorial.

In this tutorial, you know exactly what memory you’re copying, so there’s no need to worry. Note : In general, you should avoid strcpy and strlen because you can inadvertently introduce security holes by copying untrusted data.

In this tutorial, you know exactly what memory you’re copying, so there’s no need to worry.

If you’re a seasoned C developer, you already know that returning pointers to locally-scoped variables is a big no-no. At best, it’ll create incorrect return values. At worst, your app will segfault and crash.

If this is your first time working with C, it’s worth reiterating: don’t return pointers to locally-scoped variables!

Next, you need to create a Dart type to represent a function that accepts no arguments with a return value of type Pointer .

Typing Dart Functions That Return Pointers

On the Dart side, create the matching typedefs in ffi_bridge.dart . Locate // TODO: Add new typedef declarations here and replace it with:

typedef ForecastFunction = Pointer<Utf8> Function(); typedef ForecastFunctionDart = Pointer<Utf8> Function();

Dart FFI uses Pointer<Utf8> to represent a char pointer. Keep in mind, the Dart typedef doesn’t return a String because you need to manually free the returned pointer. In contrast, TemperatureFunction directly returns a Dart double .

Add Functions and Their Respective Lookups

Find and replace // TODO: Add _getForecast declaration here with:

ForecastFunctionDart _getForecast;

Here you added a _getForecast of type ForecastFunctionDart to your FFIBridge , which is the Dart function that acts as a bridge to a C function.

Next, replace // TODO: Assign value to _getForecast with:

_getForecast = dl .lookupFunction<ForecastFunction, ForecastFunctionDart>('get_forecast');

This uses DynamicLibrary to locate the C function you’ll bridge to, using the name get_forecast and the typedef ForecastFunction .

Find // TODO: Add getForecast() here and replace it with:

String getForecast() { final ptr = _getForecast(); final forecast = ptr.toDartString(); calloc.free(ptr); return forecast;

In this code, you create a getForecast that invokes the bound Dart function, converts the returned char pointer to a Dart string and frees the memory allocated for the returned pointer.

Return to main.dart and locate // TODO: Add code to invoke newly created forecast method replace it and throw UnimplementedError(); with:

_show(_ffiBridge.getForecast());

This invokes the getForecast() you added in the last step.

Build and run. Then click Today’s forecast .

Voila! Here you:

  • Obtain a native char pointer.
  • Convert the pointer to a UTF8/Dart String .
  • Free the allocated memory.
  • Pass the String back to your Flutter widget.
  • Both the get_temperature and get_forecast returned primitive types, a double , and a char pointer respectively. Neither of these functions accepted any arguments.

    Next, you’ll see how to invoke a C function that accepts some arguments. You’ll also see how to return a more complicated data structure, not just a simple pointer.

    Arguments and Structs

    In this section, you’ll see how to pass arguments from Dart to C by creating a function to return a three-day forecast in either Celsius or Fahrenheit.

    Creating A Three-Day Forecast Structure

    A three-day forecast needs three temperature values, so you obviously can’t return a solitary double . You need to create an appropriate struct .

    Add the following to the bottom of weather.c :

    struct ThreeDayForecast { double today; double tomorrow; double day_after;

    Then add a function that converts between Fahrenheit and Celsius:

    double fahrenheit_to_celsius(double temperature) { return (5.0f / 9.0f) * (temperature - 32);

    In the next section, you’ll write the function to create an instance of the ThreeDayForecast struct. This function will then populate the struct’s values with the temperature forecast in either Celsius or Fahrenheit.

    Accepting Arguments And Returning Structs

    Before your app can provide a three-day forecast in both Fahrenheit and Celsius, you need to create a function that accepts arguments.

    At the bottom of weather.c , add:

    struct ThreeDayForecast get_three_day_forecast(bool useCelsius) { struct ThreeDayForecast forecast; forecast.today = 87.0f; forecast.tomorrow = 88.0f; forecast.day_after = 89.0f; if(useCelsius) { forecast.today = fahrenheit_to_celsius(forecast.today); forecast.tomorrow = fahrenheit_to_celsius(forecast.tomorrow); forecast.day_after = fahrenheit_to_celsius(forecast.day_after); return forecast;

    Going through step-by-step, this function:

  • Accepts a bool indicating whether to return Celsius or Fahrenheit values.
  • Instantiates a struct with some very boring and static values, representing the forecasted temperature over the next three days.
  • Converts these values to Celsius if useCelsius is true.
  • Returns the struct.
  • Since this function returns a struct, you can’t use the same approach as getForecast() and return a Pointer . You need to create a matching class on the Dart side to receive the values in this struct.

    With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more! Create account Already a member of Kodeco? Sign in With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more! Create account Already a member of Kodeco? Sign in This content was released on Jun 22 2021. The official support period is 6-months from this date.

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

    With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more! Create account Already a member of Kodeco? Sign in A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos. Learn more Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalogue of 50+ books and 4,000+ videos. Learn more The largest and most up-to-date collection of courses and books on iOS, Swift, Android, Kotlin, Flutter, Dart, Server-Side Swift, Unity, and more!