Skip to content

Commit

Permalink
Main README update and typos
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrinneal committed Jun 16, 2023
1 parent 6a51bef commit 2bd57cd
Show file tree
Hide file tree
Showing 21 changed files with 1,579 additions and 386 deletions.
295 changes: 80 additions & 215 deletions packages/pigeon/README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,101 @@
# Pigeon
<?code-excerpt path-base="excerpts/packages/pigeon_example"?>

Pigeon is a code generator tool to make communication between Flutter and the
host platform type-safe, easier and faster.
host platform type-safe, easier, and faster.

## Supported Platforms
Pigeon removes the necessity to manage platform channel names as strings across multiple platforms and languages.
It it also improves efficiency over standard data encoding across platform channels.
Most importantly though, it removes the need to write custom platform channel code and codecs,
since Pigeon generates all of that code for you.

For examples on usage, see the [Example README](./example/README.md).

## Features

### Supported Platforms

Currently Pigeon supports generating:
* Kotlin and Java code for Android,
* Swift and Objective-C code for iOS
* Swift code for macOS
* C++ code for Windows

## Runtime Requirements
### Supported Datatypes

Pigeon uses the `StandardMessageCodec` so it supports any datatype Platform
Channels supports
[[documentation](https://flutter.dev/docs/development/platform-integration/platform-channels#codec)].

Custom Classes and Nested datatypes are also supported.

### Enums

Pigeon supports enum generation in class fields only. [Example.](./example/README.md#Enums)

Pigeon generates all the code that is needed to communicate between Flutter and
the host platform, there is no extra runtime requirement. A plugin author
doesn't need to worry about conflicting versions of Pigeon.
### Synchronous and Asynchronous methods

While all calls across platform channel apis (such as Pigeon methods) are asynchronous,
standard Pigeon methods can be treated as synchronous when handling returns and error.

If asynchronous methods are needed, the `@async` annotation can be used. This will require
results or errors to be returned via a provided callback. [Example.](./example/README.md#Async)

### Error Handling

#### Kotlin, Java and Swift

All Host API exceptions are translated into Flutter `PlatformException`.
* For synchronous methods, thrown exceptions will be caught and translated.
* For asynchronous methods, there is no default exception handling; errors should be returned via the provided callback.

To pass custom details into `PlatformException` for error handling, use `FlutterError` in your Host API. [Example.](./example/README.md#Error-Handling)

#### Objective-C and C++

Likewise, Host API errors can be sent using the provided `FlutterError` class (translated into `PlatformException`).

For synchronous methods:
* Objective-C - Assign the `error` argument to a `FlutterError` reference.
* C++ - Return a `FlutterError` directly (for void methods) or within an `ErrorOr` instance.

For async methods:
* Return a `FlutterError` through the provided callback.


### Task Queue

When targeting a Flutter version that supports the
[TaskQueue API](https://docs.flutter.dev/development/platform-integration/platform-channels?tab=type-mappings-kotlin-tab#channels-and-platform-threading)
the threading model for handling HostApi methods can be selected with the
`TaskQueue` annotation. [Example.](./example/README.md#Task-Queue)

## 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 `flutter pub run pigeon`
with suitable arguments (see [example](./example)).
1) Run Pigeon on your ".dart" file to generate the required Dart and
host-language code: `flutter pub get` then `flutter pub run Pigeon`
with suitable arguments. [Example.](./example/README.md#Invocation).
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

1) The file should contain no method or function definitions, only declarations.
1) Custom classes used by APIs are defined as classes with fields of the
supported datatypes (see the supported Datatypes section).
1) APIs should be defined as an `abstract class` with either `@HostApi()` or
`@FlutterApi()` as metadata. `@HostApi()` being for procedures that are defined
on the host platform and the `@FlutterApi()` for procedures that are defined in Dart.
1) Method declarations on the API classes should have arguments and a return
value whose types are defined in the file, are supported datatypes, or are
`void`.
1) Generics are supported, but can currently only be used with nullable types
(example: `List<int?>`).

### Flutter calling into iOS steps

1) Add the generated Objective-C or Swift code to your Xcode project for compilation
Expand Down Expand Up @@ -61,212 +128,10 @@ doesn't need to worry about conflicting versions of Pigeon.

Flutter also supports calling in the opposite direction. The steps are similar
but reversed. For more information look at the annotation `@FlutterApi()` which
denotes APIs that live in Flutter but are invoked from the host platform.

### Rules for defining your communication interface

1) The file should contain no method or function definitions, only declarations.
1) Custom classes used by APIs are defined as classes with fields of the
supported datatypes (see the supported Datatypes section).
1) APIs should be defined as an `abstract class` with either `HostApi()` or
`FlutterApi()` as metadata. The former being for procedures that are defined
on the host platform and the latter for procedures that are defined in Dart.
1) Method declarations on the API classes should have arguments and a return
value whose types are defined in the file, are supported datatypes, or are
`void`.
1) Generics are supported, but can currently only be used with nullable types
(example: `List<int?>`).

## Supported Datatypes

Pigeon uses the `StandardMessageCodec` so it supports any datatype Platform
Channels supports
[[documentation](https://flutter.dev/docs/development/platform-integration/platform-channels#codec)].
Nested datatypes are supported, too.

## Features

### Asynchronous Handlers

By default Pigeon will generate synchronous handlers for messages and
asynchronous methods. If you want a handler to be able to respond to a message
asynchronously you can use the @async annotation as of version 0.1.20.

Example:

```dart
class Value {
int? number;
}
@HostApi()
abstract class Api2Host {
@async
Value calculate(Value value);
}
```

Generates:

```objc
// Objective-C
@protocol Api2Host
-(void)calculate:(nullable Value *)input
completion:(void(^)(Value *_Nullable, FlutterError *_Nullable))completion;
@end
```
```swift
// Swift
/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/
protocol Api2Host {
func calculate(value: Value, completion: @escaping (Value) -> Void)
}
```

```java
// Java
public interface Result<T> {
void success(T result);
}

/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/
public interface Api2Host {
void calculate(Value arg, Result<Value> result);
}
```

```kotlin
// Kotlin

/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/
interface Api2Host {
fun calculate(value: Value, callback: (Result<Value>) -> Unit)
}
```

```c++
// C++

/** Generated class from Pigeon that represents a handler of messages from Flutter.*/
class Api2Host {
public:
virtual void calculate(Value value, flutter::MessageReply<Value> result) = 0;
}
```
### Null Safety (NNBD)
Pigeon supports generating null-safe code, but it doesn't yet support:
1) Nullable generics type arguments
1) Nullable enum arguments to methods
### Enums
Pigeon supports enum generation in class fields. For example:
```dart
enum State {
pending,
success,
error,
}
class StateResult {
String? errorMessage;
State? state;
}
@HostApi()
abstract class Api {
StateResult queryState();
}
```

### Primitive Data-types

Prior to version 1.0 all arguments to API methods had to be wrapped in a class, now they can be used directly. For example:

```dart
@HostApi()
abstract class Api {
Map<String?, int?> makeMap(List<String?> keys, List<String?> values);
}
```

### TaskQueues

When targeting a Flutter version that supports the
[TaskQueue API](https://docs.flutter.dev/development/platform-integration/platform-channels?tab=type-mappings-kotlin-tab#channels-and-platform-threading)
the threading model for handling HostApi methods can be selected with the
`TaskQueue` annotation:

```dart
@HostApi()
abstract class Api2Host {
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
int add(int x, int y);
}
```
### Error Handling
#### Kotlin, Java and Swift
All Host API exceptions are translated into Flutter `PlatformException`.
* For synchronous methods, thrown exceptions will be caught and translated.
* For asynchronous methods, there is no default exception handling; errors should be returned via the provided callback.
To pass custom details into `PlatformException` for error handling, use `FlutterError` in your Host API.
For example:
```kotlin
// Kotlin
class MyApi : GeneratedApi {
// For synchronous methods
override fun doSomething() {
throw FlutterError('error_code', 'message', 'details')
}
// For async methods
override fun doSomethingAsync(callback: (Result<Unit>) -> Unit) {
callback(Result.failure(FlutterError('error_code', 'message', 'details'))
}
}
```

#### Objective-C and C++

Likewise, Host API errors can be sent using the provided `FlutterError` class (translated into `PlatformException`).

For synchronous methods:
* Objective-C - Assign the `error` argument to a `FlutterError` reference.
* C++ - Return a `FlutterError` directly (for void methods) or within an `ErrorOr` instance.

For async methods:
* Both - Return a `FlutterError` through the provided callback.

#### Handling the errors

Then you can implement error handling on the Flutter side:

```dart
// Dart
void doSomething() {
try {
myApi.doSomething()
} catch (PlatformException e) {
if (e.code == 'error_code') {
// Perform custom error handling
assert(e.message == 'message')
assert(e.details == 'details')
}
}
}
```
denotes APIs that live in Flutter but are invoked from the host platform.
[Example](./example/README.md#Flutter-Api).

## Feedback

File an issue in [flutter/flutter](https://github.com/flutter/flutter) with the
word "pigeon" in the title.
File an issue in [flutter/flutter](https://github.com/flutter/flutter) with
"[Pigeon]" at the start of the title.
Loading

0 comments on commit 2bd57cd

Please sign in to comment.