From 7026261ef3b769a6e59c373bc5ec4e745485dac6 Mon Sep 17 00:00:00 2001 From: Craig Labenz Date: Thu, 14 Nov 2024 14:18:14 -0800 Subject: [PATCH 1/4] adds quick start to readme --- packages/pigeon/README.md | 351 +++++++++++++++++++++++++++++- packages/pigeon/example/README.md | 41 +--- 2 files changed, 349 insertions(+), 43 deletions(-) diff --git a/packages/pigeon/README.md b/packages/pigeon/README.md index cc375f5e2faa..e7f3a1606d3f 100644 --- a/packages/pigeon/README.md +++ b/packages/pigeon/README.md @@ -1,13 +1,354 @@ # Pigeon +// TODO: how to frame this? +// To get started, see the Quickstart Guide in the [Example README](./example/README.md). + Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier, and faster. -Pigeon removes the necessity to manage strings across multiple platforms and languages. -It also improves efficiency over common method channel patterns. Most importantly though, -it removes the need to write custom platform channel code, since pigeon generates it for you. +Pigeon works by reading special files which by convention are placed in a separate +folder, `/pigeons`, alongside your `/lib` folder. You can put all of your definitions +in a single file (e.g., `/pigeons/messages.dart`), or you can divide your methods +and classes into separate files as you wish. After reading these files, Pigeon +generates: + + * New Dart source files within your `/lib` folder at the specific paths you +specify, and + * New native source files with matching code within your native projects at the + specific paths you specify + +Internally, the generated code uses `MethodChannel`s to communicate across Flutter's +UI thread and the Platform thread where your host app initially launched. The value +in Pigeon comes from automatically keeping this unpleasant boilerplate in sync and +efficiently marshalling data between languages. + +The generated code can either flow from Dart to native code, or native code back +to Dart. Generated code on the receiving end uses interfaces or abstract classes, +allowing you to provide implementations in concrete classes. + +Pigeon works in both complete Flutter apps and hybrid apps using the add-to-app paradigm. + +## Quickstart + +### Installation + +Begin by adding Pigeon to your Dart project's `pubspec.yaml` file: + +```sh +$ flutter pub add pigeon --dev +$ flutter pub get +``` + +### Setup + +To specify what code Pigeon should generate, create a `/pigeons` directory and add +a `.dart` configuration file. This guide will place all such configurations within +`/pigeons/messages.dart`, but you are free to choose any file name(s) you like. + +Begin by instantiating a `PigeonOptions` object, wrapped in the `@ConfigurePigeon` +decorator. Later, you will pass named parameters to your `PigeonOptions` object +to specify your desired behavior. + +```dart +// pigeons/messages.dart + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions() +); +``` + +### Define your messages + +The next step to use Pigeon is to define the data structures Dart will exchange +with native code. You do this by writing plain Dart enums or classes in your +`/pigeons` files. These messages should only contain simple constructors and direct +attributes. Methods, factory constructors, constructor bodies, and computed +properties are all not allowed. + +```dart +// pigeons/messages.dart + +enum Code { a, b } + +class MessageData { + MessageData({required this.code, required this.data}); + String? name; + String? description; + Code code; + Map data; +} +``` + +No extra steps are necessary to register these classes - their inclusion +in a `pigeons/*.dart` ensures Pigeon will generate matching Dart and native +implementations. + +### Define which methods to expose + +The point of Pigeon and the `MethodChannel`s it utilizes is to call native functions +living on the Platform thread from Dart, or to call Dart functions living on the UI +thread from native code. Either way, you must declare methods in your `/pigeons/*` +files which tell Pigeon what function signatures its generated code must support. + +#### Call native code from Dart + +To expose a native function to be called from Dart, write an abstract class in +your Pigeon file and mark it with `@HostApi()`. + +```dart +// pigeons/messages.dart + +@HostApi() +abstract class ExampleHostApi { + String getHostLanguage(); + int add(int a, int b); + + @async + void sendMessage(MessageData message); +} +``` + +> Note: For more information on the `@async` decorator, see the [section on +> asynchronous](#Synchronous-and-Asynchronous-methods) methods below. + +Later, the Pigeon generator will produce a matching interface in native code and +you will register a concrete implementation. This concrete version of the class +will be where you either perform the necessary native operations or call out to +other native libraries. + +#### Call Dart code from native + +To expose a Dart function to your app's native code, write an abstract class in +your Pigeon file and mark it with `@FlutterApi()`. + +```dart +// pigeons/messages.dart + +@FlutterApi() +abstract class MessageFlutterApi { + String flutterMethod(String? aString); +} +``` + +Later, you will register a concrete implementation of this Dart abstract class, but +for now this is enough for you to run the generator. The concrete class you supply +will be the bridge to the rest of your application's business logic. + +### Configure your output + +It is time to pass values to the `PigeonOptions` object to configure our desired +behavior. To begin, specify a `dartOut` value where your Dart code should live and, +optionally, a `DartOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/messages.g.dart', + dartOptions: DartOptions(), // Optional + ), +) +``` +Next, add sections for each native platform your app should support. + +> Note: The paths to your native projects can vary depending on whether your +> app is entirely Flutter, or whether you are adding Flutter into an existing +> native app. These code paths will assume your app is entirely Flutter, but +> add-to-app users should see the `Add to app usage` section for specific guidance. + + +#### Add iOS and/or macOS support + +To instruct Pigeon to generate Swift code for your app on iOS, provide a path +for the `swiftOut` parameter and, optionally, a `SwiftOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + ... + swiftOut: 'ios/Runner/Messages.g.swift', + swiftOptions: SwiftOptions(), // Optional + ), +) +``` + +To instruct Pigeon to generate Objective-C code for your app on iOS, provide paths +for the `objcHeaderOut` and `objcSourceOut` parameters and, optionally, an +`ObjcOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + ... + objcHeaderOut: 'ios/Runner/Messages.g.h', + objcSourceOut: 'ios/Runner/Messages.g.m', + // Set this to a unique prefix for your plugin or application, per Objective-C naming conventions. + objcOptions: ObjcOptions(prefix: 'PGN'), + ), +) +``` + +> Note: Pigeon generates code on a per-language basis, not a per-platform basis. +> This is important for Pigeon to support all the platforms Flutter will build +> to in the future, but it does introduce a wrinkle if you want the same definitions +> generated for two different platforms; e.g., Swift code on iOS and macOS. To +> achieve this, you can either symlink your iOS files into your macOS directory, +> or you can use a separate Pigeon file (e.g., `/pigeons/macos_messages.dart`) +> which specifies macOS paths (e.g., `macos/Runner/file_name.g.swift`). + +#### Add Android support + +To instruct Pigeon to generate Kotlin code for your app on Android, provide a path +for the `kotlinOut` parameter and, optionally, a `KotlinOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + ... + kotlinOut: 'android/app/src/main/kotlin/dev/flutter/my_app_name/Messages.g.kt', + kotlinOptions: KotlinOptions(), + ), +) +``` + +To instruct Pigeon to generate Java code for your app on Android, provide a path +for the `javaOut` parameter and, optionally, a `JavaOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + ... + javaOut: 'android/app/src/main/java/io/flutter/plugins/Messages.java', + javaOptions: JavaOptions(), + ), +) +``` + +#### Add Windows support + +To instruct Pigeon to generate C++ code for your app on Windows, provide paths +for the `cppHeaderOut` and `cppSourceOut` parameters and, optionally, a +`CppOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + ... + cppHeaderOut: 'windows/runner/messages.g.h', + cppSourceOut: 'windows/runner/messages.g.cpp', + cppOptions: CppOptions(namespace: 'pigeon_example'), + ), +) +``` + +#### Add Linux support + +To instruct Pigeon to generate GObject code for your app on Linux, provide paths +for the `gobjectHeaderOut` and `gobjectSourceOut` parameters and, optionally, a +`GObjectOptions` instance. + +```dart +@ConfigurePigeon( + PigeonOptions( + ... + gobjectHeaderOut: 'linux/messages.g.h', + gobjectSourceOut: 'linux/messages.g.cc', + gobjectOptions: GObjectOptions(), + ), +) +``` + +#### A note on Web support + +Pigeon does not support the Web because Flutter apps compiled to the Web can +already directly call any JavaScript code without switching threads, as is +currently required in Flutter on mobile or desktop. Pigeon generates code which +performs two roles: + +1. Uses Flutter's `MethodChannel`s concept to jump from the UI thread to the +Platform thread (or in the other direction), and +2. Marshalls data between Dart and the native language. + +Flutter Web apps intrinsically do not encounter the first problem and only +encounter a form of the second problem if you need to interface with a +library's `d.ts` interface. In this case, you may need to author custom Dart +classes which match those TypeScript definitions. Check pub.dev for existing solutions. + +### Run the builder + +Once your Pigeon files define any data classes and functions you wish to invoke, +you can run the builder: + +```sh +$ dart run pigeon --input pigeons/messages.dart +``` + +You must run this command once per Pigeon file, specifying a single `--input` each +time. Pigeon files may only import `package:pigeon/pigeon.dart`, so they cannot +depend on each other. Pigeon files must also all have their own +`@ConfigurePigeon(PigeonOptions())` declaration. + +### Use the generated code + +You should now see matching output files at the locations you specified in your +`PigeonOptions` instance, or in your command line arguments. The two primary +scenarios to explore are calling native code from Dart and calling Dart code from +native. + +#### Calling native code from Dart + +The sample code in this Quickstart defines an example native API named `ExampleHostApi`. +Pigeon will generate a complete Dart implementation and the equivalent of an abstract +class in each native language (for example, a `protocol` in Swift and an `interface` +in Kotlin). + +See the [language-specific guides](example/README.md#HostApi-Example) for help instantiating the native classes +generated by Pigeon. + +In Dart, typical use within a `StatefulWidget` might look like this: + +```dart +@override +void initState() { + final ExampleHostApi _hostApi = ExampleHostApi(); + super.initState(); +} + +Future getHostLanguage() async + => _hostApi.getHostLanguage(); + +Future add(int a, int b) async + => _hostApi.add(a, b); + +Future sendMessage(MessageData message) async + => _hostApi.sendMessage(message); +``` + +#### Calling Dart code from native + +The sample code in this Quickstart defined an example Dart API named `MessageFlutterApi`. +Define a concrete implementation of this abstract class with your real implementation: + +```dart +class _MessageFlutterApi implements MessageFlutterApi { + @override + String flutterMethod(String? aString) => aString ?? ''; +} +``` + +Next, register your implementation with the `MessageChannel` harness that Pigeon +generated. You must complete this call to `setUp` before invoking the +`flutterMethod` method from your native code. + +```dart +MessageFlutterApi.setUp(_MessageFlutterApi()); +``` -For usage examples, see the [Example README](./example/README.md). +Pigeon will have generated a native implementation of `MessageFlutterApi` in your +designated languages and files, and you should now be ready to instantiate that +class and invoke its methods. See the language-specific sections below for help +instantiating the native classes generated by Pigeon. ## Features @@ -87,7 +428,7 @@ to the api to allow for multiple instances to be created and operate in parallel communication interface. 1) Run pigeon on your ".dart" file to generate the required Dart and host-language code: `flutter pub get` then `dart run pigeon` - with suitable arguments. [Example](./example/README.md#Invocation). + with suitable arguments. [Example](./example/README.md#Configure_your_output). 1) Add the generated Dart code to `./lib` for compilation. 1) Implement the host-language code and add it to your build (see below). 1) Call the generated Dart methods. diff --git a/packages/pigeon/example/README.md b/packages/pigeon/example/README.md index bd5e4bd116af..4b37954021b7 100644 --- a/packages/pigeon/example/README.md +++ b/packages/pigeon/example/README.md @@ -1,48 +1,13 @@ # Pigeon Examples +For a quick start guide to Pigeon, see the [QuickStart guide](../README.md#Quickstart). For language-specific guides to instantiate code generated by Pigeon, continue with +this guide. + The examples here will cover basic usage. For a more thorough set of examples, check the [core_tests pigeon file](../pigeons/core_tests.dart) and [platform test folder](../platform_tests/) ([shared_test_plugin_code](../platform_tests/shared_test_plugin_code/) and [alternate_language_test_plugin](../platform_tests/alternate_language_test_plugin/) especially). -## Invocation - -Begin by configuring pigeon at the top of the `.dart` input file. -In actual use, you would include only the languages -needed for your project. - - -```dart -@ConfigurePigeon(PigeonOptions( - dartOut: 'lib/src/messages.g.dart', - dartOptions: DartOptions(), - cppOptions: CppOptions(namespace: 'pigeon_example'), - cppHeaderOut: 'windows/runner/messages.g.h', - cppSourceOut: 'windows/runner/messages.g.cpp', - gobjectHeaderOut: 'linux/messages.g.h', - gobjectSourceOut: 'linux/messages.g.cc', - gobjectOptions: GObjectOptions(), - kotlinOut: - 'android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt', - kotlinOptions: KotlinOptions(), - javaOut: 'android/app/src/main/java/io/flutter/plugins/Messages.java', - javaOptions: JavaOptions(), - swiftOut: 'ios/Runner/Messages.g.swift', - swiftOptions: SwiftOptions(), - objcHeaderOut: 'macos/Runner/messages.g.h', - objcSourceOut: 'macos/Runner/messages.g.m', - // Set this to a unique prefix for your plugin or application, per Objective-C naming conventions. - objcOptions: ObjcOptions(prefix: 'PGN'), - copyrightHeader: 'pigeons/copyright.txt', - dartPackageName: 'pigeon_example_package', -)) -``` -Then make a simple call to run pigeon on the Dart file containing your definitions. - -```sh -dart run pigeon --input path/to/input.dart -``` - ## HostApi Example This example gives an overview of how to use Pigeon to call into the From 3fee1bbda38b03cae6cbfbd22e9cfe8226c2072a Mon Sep 17 00:00:00 2001 From: Craig Labenz Date: Wed, 20 Nov 2024 09:31:27 -0800 Subject: [PATCH 2/4] responses to code review --- packages/pigeon/README.md | 70 +++++++++++++++------------------------ 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/packages/pigeon/README.md b/packages/pigeon/README.md index e7f3a1606d3f..72eb42b8c72e 100644 --- a/packages/pigeon/README.md +++ b/packages/pigeon/README.md @@ -6,19 +6,13 @@ Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier, and faster. -Pigeon works by reading special files which by convention are placed in a separate -folder, `/pigeons`, alongside your `/lib` folder. You can put all of your definitions -in a single file (e.g., `/pigeons/messages.dart`), or you can divide your methods -and classes into separate files as you wish. After reading these files, Pigeon -generates: - - * New Dart source files within your `/lib` folder at the specific paths you -specify, and - * New native source files with matching code within your native projects at the - specific paths you specify - -Internally, the generated code uses `MethodChannel`s to communicate across Flutter's -UI thread and the Platform thread where your host app initially launched. The value +Pigeon works by reading a special file or files, which are placed outside of the +`/lib` directory which hosts all of your application code. You define special +data classes and endpoints, which Pigeon will then consume and use to generate +matching Dart and native code at the paths you specify. + +Internally, the generated code uses `MethodChannel`s to communicate between Flutter's +UI thread and the Platform thread where your host app is initially launched. The value in Pigeon comes from automatically keeping this unpleasant boilerplate in sync and efficiently marshalling data between languages. @@ -41,9 +35,9 @@ $ flutter pub get ### Setup -To specify what code Pigeon should generate, create a `/pigeons` directory and add -a `.dart` configuration file. This guide will place all such configurations within -`/pigeons/messages.dart`, but you are free to choose any file name(s) you like. +To specify what code Pigeon should generate, create your interface definition file. +This guide will place all such definitions at `/pigeons/messages.dart`, but you +are free to choose any file name you like, inside a dedicated folder or not. Begin by instantiating a `PigeonOptions` object, wrapped in the `@ConfigurePigeon` decorator. Later, you will pass named parameters to your `PigeonOptions` object @@ -63,7 +57,7 @@ import 'package:pigeon/pigeon.dart'; The next step to use Pigeon is to define the data structures Dart will exchange with native code. You do this by writing plain Dart enums or classes in your -`/pigeons` files. These messages should only contain simple constructors and direct +definition file. These messages should only contain simple constructors and direct attributes. Methods, factory constructors, constructor bodies, and computed properties are all not allowed. @@ -82,15 +76,15 @@ class MessageData { ``` No extra steps are necessary to register these classes - their inclusion -in a `pigeons/*.dart` ensures Pigeon will generate matching Dart and native +in your definitions file ensures Pigeon will generate matching Dart and native implementations. ### Define which methods to expose The point of Pigeon and the `MethodChannel`s it utilizes is to call native functions living on the Platform thread from Dart, or to call Dart functions living on the UI -thread from native code. Either way, you must declare methods in your `/pigeons/*` -files which tell Pigeon what function signatures its generated code must support. +thread from native code. Either way, you must declare methods in your definitions +file which tell Pigeon what function signatures its generated code must support. #### Call native code from Dart @@ -138,7 +132,7 @@ will be the bridge to the rest of your application's business logic. ### Configure your output -It is time to pass values to the `PigeonOptions` object to configure our desired +It is time to pass values to the `PigeonOptions` object to configure your desired behavior. To begin, specify a `dartOut` value where your Dart code should live and, optionally, a `DartOptions` instance. @@ -155,7 +149,8 @@ Next, add sections for each native platform your app should support. > Note: The paths to your native projects can vary depending on whether your > app is entirely Flutter, or whether you are adding Flutter into an existing > native app. These code paths will assume your app is entirely Flutter, but -> add-to-app users should see the `Add to app usage` section for specific guidance. +> add-to-app users should see the [`Add to app usage`](Add-to-app-usage) +> section for specific guidance. #### Add iOS and/or macOS support @@ -195,7 +190,7 @@ for the `objcHeaderOut` and `objcSourceOut` parameters and, optionally, an > generated for two different platforms; e.g., Swift code on iOS and macOS. To > achieve this, you can either symlink your iOS files into your macOS directory, > or you can use a separate Pigeon file (e.g., `/pigeons/macos_messages.dart`) -> which specifies macOS paths (e.g., `macos/Runner/file_name.g.swift`). +> which specifies macOS paths (e.g., `macos/Runner/Messages.g.swift`). #### Add Android support @@ -207,7 +202,7 @@ for the `kotlinOut` parameter and, optionally, a `KotlinOptions` instance. PigeonOptions( ... kotlinOut: 'android/app/src/main/kotlin/dev/flutter/my_app_name/Messages.g.kt', - kotlinOptions: KotlinOptions(), + kotlinOptions: KotlinOptions(), // Optional ), ) ``` @@ -220,7 +215,7 @@ for the `javaOut` parameter and, optionally, a `JavaOptions` instance. PigeonOptions( ... javaOut: 'android/app/src/main/java/io/flutter/plugins/Messages.java', - javaOptions: JavaOptions(), + javaOptions: JavaOptions(), // Optional ), ) ``` @@ -266,9 +261,9 @@ already directly call any JavaScript code without switching threads, as is currently required in Flutter on mobile or desktop. Pigeon generates code which performs two roles: -1. Uses Flutter's `MethodChannel`s concept to jump from the UI thread to the +1. Using Flutter's `MethodChannel`s concept to jump from the UI thread to the Platform thread (or in the other direction), and -2. Marshalls data between Dart and the native language. +2. Marshalling data between Dart and the native language. Flutter Web apps intrinsically do not encounter the first problem and only encounter a form of the second problem if you need to interface with a @@ -284,11 +279,6 @@ you can run the builder: $ dart run pigeon --input pigeons/messages.dart ``` -You must run this command once per Pigeon file, specifying a single `--input` each -time. Pigeon files may only import `package:pigeon/pigeon.dart`, so they cannot -depend on each other. Pigeon files must also all have their own -`@ConfigurePigeon(PigeonOptions())` declaration. - ### Use the generated code You should now see matching output files at the locations you specified in your @@ -309,9 +299,11 @@ generated by Pigeon. In Dart, typical use within a `StatefulWidget` might look like this: ```dart +late final ExampleHostApi; + @override void initState() { - final ExampleHostApi _hostApi = ExampleHostApi(); + _hostApi = ExampleHostApi(); super.initState(); } @@ -328,7 +320,7 @@ Future sendMessage(MessageData message) async #### Calling Dart code from native The sample code in this Quickstart defined an example Dart API named `MessageFlutterApi`. -Define a concrete implementation of this abstract class with your real implementation: +Define a concrete implementation of this abstract class with your real business logic: ```dart class _MessageFlutterApi implements MessageFlutterApi { @@ -423,16 +415,6 @@ to the api to allow for multiple instances to be created and operate in parallel ## Usage -1) Add pigeon as a `dev_dependency`. -1) Make a ".dart" file outside of your "lib" directory for defining the - communication interface. -1) Run pigeon on your ".dart" file to generate the required Dart and - host-language code: `flutter pub get` then `dart run pigeon` - with suitable arguments. [Example](./example/README.md#Configure_your_output). -1) Add the generated Dart code to `./lib` for compilation. -1) Implement the host-language code and add it to your build (see below). -1) Call the generated Dart methods. - ### Rules for defining your communication interface [Example](./example/README.md#HostApi_Example) From c52f2f10b4fccee4fef832a164d07a1af4fae1ec Mon Sep 17 00:00:00 2001 From: Craig Labenz Date: Wed, 20 Nov 2024 10:34:44 -0800 Subject: [PATCH 3/4] adds dedicated add-to-app guidance --- packages/pigeon/README.md | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/packages/pigeon/README.md b/packages/pigeon/README.md index 72eb42b8c72e..b13d4cd00947 100644 --- a/packages/pigeon/README.md +++ b/packages/pigeon/README.md @@ -474,6 +474,66 @@ but reversed. For more information look at the annotation `@FlutterApi()` which denotes APIs that live in Flutter but are invoked from the host platform. [Example](./example/README.md#FlutterApi_Example). +### Add to app usage + +Apps which are primarily Flutter from the beginning have slightly different structures +from apps which are native from the beginning and then later introduce Flutter. +These differences do not materially change how to use Pigeon, but they do of +course influence the paths you supply to various commands. + +In Flutter-first apps, your structure might look like this: + +``` +android/ + ... +ios/ + Runner/ + Messages.g.swift +lib/ + main.dart + src/ + pigeon_messages.g.dart +pigeon_messages.dart +pubspec.yaml +``` + +This would suggest `PigeonOptions` values like so: + +```dart +PigeonOptions( + dartOut: 'lib/src/pigeon_messages.g.dart', + kotlinOut: 'android/app/src/main/kotlin/dev/flutter/app_name/Messages.g.kt' + swiftOut: 'ios/Runner/Messages.g.swift', +) +``` + +However, in native-first apps, your structure might look like this: + +``` +android_app_name/ + ... +ios_app_name/ + Messages.g.swift +flutter_module/ + .ios/ + .android/ + lib/ + src/ + pigeon_messages.dart + pigeon_messages.dart + pubspec.yaml +``` + +Such an add-to-app setup would suggest `PigeonValues` like so: + +```dart +PigeonOptions( + dartOut: 'lib/src/pigeon_messages.g.dart', + kotlinOut: '../android_app_name/app/src/main/kotlin/dev/flutter/app_name/Messages.g.kt' + swiftOut: '../ios_app_name/Messages.g.swift', +) +``` + ## Feedback File an issue in [flutter/flutter](https://github.com/flutter/flutter) with From 217c883baeae0228466fcb85ec1b1a0d6ad0ad70 Mon Sep 17 00:00:00 2001 From: Craig Labenz Date: Wed, 20 Nov 2024 10:35:36 -0800 Subject: [PATCH 4/4] readme cleanup --- packages/pigeon/README.md | 3 --- packages/pigeon/example/README.md | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/pigeon/README.md b/packages/pigeon/README.md index b13d4cd00947..a5865c156b11 100644 --- a/packages/pigeon/README.md +++ b/packages/pigeon/README.md @@ -1,8 +1,5 @@ # Pigeon -// TODO: how to frame this? -// To get started, see the Quickstart Guide in the [Example README](./example/README.md). - Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier, and faster. diff --git a/packages/pigeon/example/README.md b/packages/pigeon/example/README.md index 4b37954021b7..7f16cca3ca94 100644 --- a/packages/pigeon/example/README.md +++ b/packages/pigeon/example/README.md @@ -1,7 +1,8 @@ # Pigeon Examples -For a quick start guide to Pigeon, see the [QuickStart guide](../README.md#Quickstart). For language-specific guides to instantiate code generated by Pigeon, continue with +For a quick start guide to Pigeon, see the [QuickStart guide](../README.md#Quickstart). +For language-specific guides to instantiate code generated by Pigeon, continue with this guide. The examples here will cover basic usage. For a more thorough set of examples,