Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FFI plugin docs #7111

Merged
merged 5 commits into from
May 11, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions src/development/packages-and-plugins/developing-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ Packages can contain more than one kind of content:
see the Medium article by Harry Terkelsen,
[How to Write a Flutter Web Plugin, Part 1][].

**FFI Plugin packages**
: A specialized Dart package that contains an API written in
Dart code combined with one or more platform-specific
implementations that use [Dart FFI][FFI].

## Developing Dart packages {#dart}

The following instructions explain how to write a Flutter
Expand Down Expand Up @@ -472,6 +477,100 @@ functionality does not regress as you make changes to your code. For more
information, see [Testing your plugin][], a section in [Supporting the new
Android plugins APIs][].

## Developing FFI plugin packages {#plugin-ffi}

If you want to develop a package that calls into native APIs using
[Dart's FFI][FFI], you need to develop a FFI plugin package.

### Step 1: Create the package

To create a starter FFI plugin package,
use the `--template=plugin_ffi` flag with `flutter create`:

```terminal
$ flutter create --template=plugin_ffi hello
```

This creates a FFI plugin project in the `hello`
folder with the following specialized content:

**lib**: The Dart code that defines the API of the plugin, and which
calls into the native code using `dart:ffi`.

**src**: The native source code, and a `CmakeFile.txt` file for building
that source code into a dynamic library.

**platform folders** (`android`, `ios`, `windows`, etc.): The build files
for building and bundling the native code library with the platform application.

### Step 2: Buidling and bundling native code

The `pubspec.yaml` specifies FFI plugins as follows:

```yaml
plugin:
platforms:
some_platform:
ffiPlugin: true
```

This configuration invokes the native build for the various target platforms
and bundles the binaries in Flutter applications using these FFI plugins.

This can be combined with `dartPluginClass`, such as when FFI is used for the
implementation of one platform in a federated plugin:

```yaml
plugin:
implements: some_other_plugin
platforms:
some_platform:
dartPluginClass: SomeClass
ffiPlugin: true
```

A plugin can have both FFI and method channels:

```yaml
plugin:
platforms:
some_platform:
pluginClass: SomeName
ffiPlugin: true
```

The native build systems that are invoked by FFI (and method channels) plugins are:

* For Android: Gradle, which invokes the Android NDK for native builds.
* See the documentation in `android/build.gradle`.
* For iOS and MacOS: Xcode, via CocoaPods.
* See the documentation in `ios/hello.podspec`.
* See the documentation in `macos/hello.podspec`.
* For Linux and Windows: CMake.
* See the documentation in `linux/CMakeLists.txt`.
* See the documentation in `windows/CMakeLists.txt`.

### Step 3: Binding to native code

To use the native code, bindings in Dart are needed.

To avoid writing these by hand, they are generated from the header file
(`src/hello.h`) by [`package:ffigen`][].
Regenerate the bindings by running:

```terminal
$ flutter pub run ffigen --config ffigen.yaml
```

### Step 4: Invoking native code

Very short-running native functions can be directly invoked from any isolate.
For an example, see `sum` in `lib/hello.dart`.

Longer-running functions should be invoked on a [helper isolate][] to avoid
dropping frames in Flutter applications.
For an example, see `sumAsync` in `lib/hello.dart`.

## Adding documentation

It is recommended practice to add the following documentation
Expand Down Expand Up @@ -715,11 +814,13 @@ PENDING
[Flutter Favorites]: {{site.pub}}/flutter/favorites
[Flutter Favorites program]: {{site.url}}/development/packages-and-plugins/favorites
[Gradle Documentation]: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
[helper isolate]: {{site.dart-site}}/guides/language/concurrency#background-workers
[How to Write a Flutter Web Plugin, Part 1]: {{site.flutter-medium}}/how-to-write-a-flutter-web-plugin-5e26c689ea1
[How To Write a Flutter Web Plugin, Part 2]: {{site.flutter-medium}}/how-to-write-a-flutter-web-plugin-part-2-afdddb69ece6
[issue #33302]: {{site.repo.flutter}}/issues/33302
[`LICENSE`]: #adding-licenses-to-the-license-file
[`path`]: {{site.pub}}/packages/path
[`package:ffigen`]: {{site.pub}}/packages/ffigen
[platform channel]: {{site.url}}/development/platform-integration/platform-channels
[pub.dev]: {{site.pub}}
[publishing docs]: {{site.dart-site}}/tools/pub/publishing
Expand Down