Skip to content

Add Native interop documentation section (Pigeon, FFIgen, JNIgen, dart:ffi) - #13995

Draft
lamek wants to merge 9 commits into
flutter:mainfrom
lamek:native-interop-eap
Draft

lamek wants to merge 9 commits into
flutter:mainfrom
lamek:native-interop-eap

Conversation

@lamek

@lamek lamek commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Description of what this PR is changing or adding, and why:

Adds the new top-level Native interop documentation section (/interop) for the upcoming Flutter 3.50 / Native Interop GA release:

  • Overview (/interop): Decision tree (Mermaid flowchart and step-by-step walkthrough), packaging options, tool comparison matrix, and 3-layer interop architecture.
  • Pigeon (/interop/pigeon): Covers Pigeon with native interop (direct FFI on iOS/macOS and JNI on Android) and Pigeon with platform channels, developer workflow, examples, and constraints.
  • FFIgen (/interop/ffigen): Covers generating C, Objective-C, and Swift bindings with tool/ffigen.dart, developer workflow, examples, and platform/runtime considerations.
  • JNIgen (/interop/jnigen): Covers generating Java and Kotlin bindings on Android with tool/jnigen.dart, developer workflow, examples, and threading/reference lifecycle considerations.
  • dart:ffi (/interop/dart-ffi): Covers native memory allocation, data conversion (package:ffi), and isolate concurrency (Isolate.run).
  • Bind to native code (/interop/bind-native-code): Moved from /platform-integration/bind-native-code with a 301 redirect in firebase.json.
  • Platform channels (/platform-integration/platform-channels): Updated to link to the new Native interop overview and dedicated Pigeon guide.
  • Sidenav (sites/docs/src/data/sidenav/default.yml): Adds the top-level Native interop section above Platform integration.

Issues fixed by this PR (if any):

PRs or commits this PR depends on (if any):

N/A (Draft for early review and staging preview before Flutter 3.50 release)

Presubmit checklist

  • If you are unwilling, or unable, to sign the CLA, even for a tiny, one-word PR, please file an issue instead of a PR.
  • If this PR is not meant to land until a future stable release, mark it as draft with an explanation.
  • This PR follows the Google Developer Documentation Style Guidelines—for example, it doesn't use i.e. or e.g., and it avoids I and we (first-person pronouns).
  • This PR uses semantic line breaks
    of 80 characters or fewer.

- Add Native interop landing page with decision tree and layers guide
- Add Pigeon guide covering platform channels and native bindings modes
- Add FFIgen guide covering Apple frameworks, C-ABI, and developer flow
- Add dart:ffi guide for native memory allocation and concurrency
- Move bind-native-code into platform-integration/interop/
- Add JNIgen guide for Java/Kotlin and Android bindings
- Update platform-channels to focus on manual message passing
- Update sidenav default.yml with new Native interop section
- Update firebase.json with 301 redirect for bind-native-code

TAG=agy
CONV=a76ca369-bcbf-4f8a-822b-b2d6bdd86f54
- Restore exact text, structure, and headings from the Google Doc
- Remove extraneous code examples from developer flow sections

TAG=agy
CONV=a76ca369-bcbf-4f8a-822b-b2d6bdd86f54
@flutter-website-bot

Copy link
Copy Markdown
Collaborator

Staged preview of the updated docs.flutter.dev site (updated for commit fb5205b):

https://flutter-docs-prod--docs-pr13995-native-interop-eap-ihm0amds.web.app

@parlough

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive "Native interop" documentation section, adding new guides for dart:ffi, FFIgen, JNIgen, and Pigeon, along with an overview page to help developers choose the right interop solution. It also updates existing platform integration docs, sidebar navigation, and redirects to point to these new pages. A review comment points out an incorrect API reference in the JNIgen guide, suggesting the use of PlatformDispatcher.instance.scheduleOnPlatformThread instead of runOnPlatformThread.

Watch out for two common scenarios:

- Calling platform APIs that must run on the platform thread.
Use `runOnPlatformThread` from `dart:ui`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In Flutter, there is no top-level function or direct class named runOnPlatformThread in the dart:ui library. To run a task on the platform thread, you should use PlatformDispatcher.instance.scheduleOnPlatformThread (introduced in newer Flutter versions) or coordinate with platform channels / native bindings. Please update this reference to the correct API to avoid confusing developers.

Suggested change
Use `runOnPlatformThread` from `dart:ui`.
Use `PlatformDispatcher.instance.scheduleOnPlatformThread` from `dart:ui`.
References
  1. Ensure correct instructions, commands, API names, or expected results are documented. (link)

@sfshaza2 sfshaza2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some quibbles but, overall, a great addition to the site! I like the decision graph and would be hesitant to clobber it. I also like the table comparing the approaches.

For desktop-specific guidance on calling system APIs—including wrapper
packages like [`package:win32`]({{site.pub-pkg}}/win32) and
[Canonical's Linux packages]({{site.pub}}/publishers/canonical.com/packages)—see
[Canonical's Linux packages]({{site.pub}}/publishers/canonical.com/packages)—refer to

@sfshaza2 sfshaza2 Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true that we used to use the HTML "—" extensively, but these days you can just paste the character itself into the text.

The `dart:ffi` (Foreign Function Interface) library is a core Dart SDK library
that provides the low-level APIs to call C-ABI functions from Dart.

Rather than a code generation tool like [Pigeon](/interop/pigeon),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Rather than a code generation tool like [Pigeon](/interop/pigeon),
Rather than code generation tools like [Pigeon](/interop/pigeon),

This is listing multiple tools, right? If not, the sentence should be rephrased.

Comment on lines +29 to +30
for native arguments, and you must manually free that memory when done.
This helps avoid memory leaks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for native arguments, and you must manually free that memory when done.
This helps avoid memory leaks.
for native arguments, and you must manually free that memory when done
to prevent memory leaks.

The text "That helps to avoid..." is a bit vague. It makes me wonder what else I've done to introduce a memory leak.


## Concurrency in Flutter

FFI calls are synchronous and run on the thread they are called on.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FFI calls are synchronous and run on the thread they are called on.
FFI calls are synchronous and run on the thread on which they are called.

I don't usually complain about dangling participles, but this one bothered me.

Comment on lines +16 to +18
:::note
Direct Swift interop is in experimental support.
:::

@sfshaza2 sfshaza2 Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an idea of how likely it is to change or how soon? I'd say just a tad more here. Such as "... and is likely to change."


## Developer flow

The developer experience with Pigeon follows a structured cycle:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this text active, please!

and produces the necessary code for both Dart and your target native platform.

:::note
If you're using the Pigeon with native interop communication option,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you're using the Pigeon with native interop communication option,
If you're using Pigeon with the native interop communication option,

"...the Pigeon.."??

refer to the [native interop guide][pigeon-native-guide].
:::

After the code is generated, you implement the generated native interfaces

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
After the code is generated, you implement the generated native interfaces
After the code is generated, implement the generated native interfaces

I notice that the text often uses "...you ...". Most of the time, the "you" just isn't necessary.

in the platform-specific directories of your Flutter project
(such as `android/`, `ios/`, or `macos/`)
and register them with the Flutter engine.
Finally, you call the generated Dart classes from your Flutter app,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Finally, you call the generated Dart classes from your Flutter app,
Finally, call the generated Dart classes from your Flutter app,

For example...


### Inheritance

Pigeon does not support complex inheritance.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Pigeon does not support complex inheritance.
Pigeon doesn't support complex inheritance.

You know, this insistence on avoiding contractions just isn't necessary. Studies show that, in verbal communication, avoiding contractions can be clearer, but not so much in written communication. This is really an old school idea that hasn't proven out.

@sfshaza2 sfshaza2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, once my feedback is incorporated. I'll go ahead and approve, but I'd like approval from a SME. thx! Overall, this looks great!

@tarrinneal tarrinneal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple little clarifications

Comment on lines +111 to +114
### (Pigeon with platform channels only) Async errors

For `@async` methods, native code must return errors through the provided
callback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Pigeon 28.0.0, @async generates suspend functions in Kotlin and async throws methods in Swift even when using platform channels (where native code throws FlutterError or PigeonError directly rather than using a callback). Completion callbacks are now only generated for @asyncCallback methods (for platform channels) or in the Java, Objective-C, C++, and GObject generators.

Comment on lines +141 to +153
| Target language | Direct interop | Pigeon |
| --- | --- | --- |
| **C** | [FFIgen](/interop/ffigen) | Not recommended. Supported with platform channels, but not maintained by the Flutter team. |
| **C++ with `extern "C"`** | [FFIgen](/interop/ffigen) | (Refer to C) |
| **C++ without `extern "C"`** | FFIgen (not yet supported) | Supported with platform channels, but not maintained by the Flutter team. |
| **Rust with `extern "C"`** | [FFIgen](/interop/ffigen) | (Refer to C) |
| **Rust without `extern "C"`** | [Flutter Rust Bridge][frb] | Not supported |
| **Go with `extern "C"`** | [FFIgen](/interop/ffigen) | (Refer to C) |
| **Go without `extern "C"`** | Not supported | Not supported |
| **Java** | [JNIgen](/interop/jnigen) | Supported through Kotlin |
| **Kotlin** | [JNIgen](/interop/jnigen) | Supported (recommended) |
| **Objective-C** | [FFIgen](/interop/ffigen) | Supported through Swift |
| **Swift without Obj-C compatibility annotations** | [`package:swiftgen`][swiftgen-pub] (experimental) | Supported (recommended) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two clarifications on the Pigeon column here:

  1. Pigeon's C (GObject on Linux) and C++ (Windows) platform-channel generators in flutter/packages are maintained by the Flutter team for desktop plugins, though they only support platform-channels.
  2. For Java and Objective-C, "Supported through Kotlin" / "Supported through Swift" applies to Pigeon with native interop, whereas Pigeon with platform channels also includes direct Java (JavaOptions) and Objective-C (ObjcOptions) generators.

Comment on lines +66 to +80
:::note
If you're using the Pigeon with native interop communication option,
set `appDirectory`, `swiftOptions: SwiftOptions(useFfi: true)`, and
`kotlinOptions: KotlinOptions(useJni: true)` in the `@ConfigurePigeon`
section of your Pigeon definition file.
For complete prerequisites and build configuration,
refer to the [native interop guide][pigeon-native-guide].
:::

After the code is generated, you implement the generated native interfaces
in the platform-specific directories of your Flutter project
(such as `android/`, `ios/`, or `macos/`)
and register them with the Flutter engine.
Finally, you call the generated Dart classes from your Flutter app,
or invoke the generated native APIs to call back into your Dart code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few helpful details from native_interop_guide.md that could save readers from common setup errors when using Pigeon with native interop:

  1. In @ConfigurePigeon, SwiftOptions also takes ffiModuleName (for example, SwiftOptions(useFfi: true, ffiModuleName: 'Runner')).
  2. On the Dart side, callers must instantiate the generated host API using <MyApi>.createWithNativeInteropApi() (since the default <MyApi>() constructor uses platform channels).
  3. Under Constraints and limitations, we could note that @ProxyApi, and @TaskQueue are only supported with platform channels, but it's probably not worth mentioning.

between Dart and host platforms.
To learn how to use Pigeon, define API contracts, and choose between
native interop and platform channels,
refer to the dedicated [Pigeon guide](/interop/pigeon).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Note regarding lines 1426–1430 of sites/docs/src/content/platform-integration/platform-channels.md)

Since the [Pigeon][] reference in the #pigeon section was replaced with [Pigeon guide](/interop/pigeon), the [Pigeon]: {{site.pub-pkg}}/pigeon link definition on line 1428 is now unused and can be removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants