Skip to content

[pigeon] Allow multi instance support with message channel name suffix #6224

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

Merged
merged 2 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 18.0.0

* Adds message channel suffix option to all APIs.
* **Breaking Change** [dart] Changes `FlutterApi` `setup` to `setUp`.

## 17.3.0

* [swift] Adds `@SwiftClass` annotation to allow choice between `struct` and `class` for data classes.
Expand Down
5 changes: 5 additions & 0 deletions packages/pigeon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ When targeting a Flutter version that supports the
the threading model for handling HostApi methods can be selected with the
`TaskQueue` annotation.

### Multi-Instance Support

Host and Flutter APIs now support the ability to provide a unique message channel suffix string
to the api to allow for multiple instances to be created and operate in parallel.

## Usage

1) Add pigeon as a `dev_dependency`.
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class _ExampleFlutterApi implements MessageFlutterApi {
}
}
// ···
MessageFlutterApi.setup(_ExampleFlutterApi());
MessageFlutterApi.setUp(_ExampleFlutterApi());
```

### Swift
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,20 @@ public interface ExampleHostApi {
}
/** Sets up an instance of `ExampleHostApi` to handle messages through the `binaryMessenger`. */
static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable ExampleHostApi api) {
setUp(binaryMessenger, "", api);
}

static void setUp(
@NonNull BinaryMessenger binaryMessenger,
@NonNull String messageChannelSuffix,
@Nullable ExampleHostApi api) {
messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage",
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
Expand All @@ -295,7 +304,8 @@ static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable ExampleHos
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add",
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
Expand Down Expand Up @@ -324,7 +334,8 @@ static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable ExampleHos
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage",
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
Expand Down Expand Up @@ -356,9 +367,16 @@ public void error(Throwable error) {
/** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
public static class MessageFlutterApi {
private final @NonNull BinaryMessenger binaryMessenger;
private final String messageChannelSuffix;

public MessageFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
this(argBinaryMessenger, "");
}

public MessageFlutterApi(
@NonNull BinaryMessenger argBinaryMessenger, @NonNull String messageChannelSuffix) {
this.binaryMessenger = argBinaryMessenger;
this.messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;
}

/** Public interface for sending reply. */
Expand All @@ -369,7 +387,8 @@ public MessageFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {

public void flutterMethod(@Nullable String aStringArg, @NonNull Result<String> result) {
final String channelName =
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod";
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod"
+ messageChannelSuffix;
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(binaryMessenger, channelName, getCodec());
channel.send(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,18 @@ interface ExampleHostApi {
val codec: MessageCodec<Any?> by lazy { ExampleHostApiCodec }
/** Sets up an instance of `ExampleHostApi` to handle messages through the `binaryMessenger`. */
@Suppress("UNCHECKED_CAST")
fun setUp(binaryMessenger: BinaryMessenger, api: ExampleHostApi?) {
fun setUp(
binaryMessenger: BinaryMessenger,
api: ExampleHostApi?,
messageChannelSuffix: String = ""
) {
val separatedMessageChannelSuffix =
if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage",
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage$separatedMessageChannelSuffix",
codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
Expand All @@ -144,7 +150,7 @@ interface ExampleHostApi {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add",
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add$separatedMessageChannelSuffix",
codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
Expand All @@ -167,7 +173,7 @@ interface ExampleHostApi {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage",
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage$separatedMessageChannelSuffix",
codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
Expand All @@ -192,14 +198,20 @@ interface ExampleHostApi {
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
@Suppress("UNCHECKED_CAST")
class MessageFlutterApi(private val binaryMessenger: BinaryMessenger) {
class MessageFlutterApi(
private val binaryMessenger: BinaryMessenger,
private val messageChannelSuffix: String = ""
) {
companion object {
/** The codec used by MessageFlutterApi. */
val codec: MessageCodec<Any?> by lazy { StandardMessageCodec() }
}

fun flutterMethod(aStringArg: String?, callback: (Result<String>) -> Unit) {
val channelName = "dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod"
val separatedMessageChannelSuffix =
if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName =
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(aStringArg)) {
if (it is List<*>) {
Expand Down
18 changes: 12 additions & 6 deletions packages/pigeon/example/app/ios/Runner/Messages.g.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,13 @@ class ExampleHostApiSetup {
/// The codec used by ExampleHostApi.
static var codec: FlutterStandardMessageCodec { ExampleHostApiCodec.shared }
/// Sets up an instance of `ExampleHostApi` to handle messages through the `binaryMessenger`.
static func setUp(binaryMessenger: FlutterBinaryMessenger, api: ExampleHostApi?) {
static func setUp(
binaryMessenger: FlutterBinaryMessenger, api: ExampleHostApi?, messageChannelSuffix: String = ""
) {
let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : ""
let getHostLanguageChannel = FlutterBasicMessageChannel(
name: "dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage",
name:
"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
getHostLanguageChannel.setMessageHandler { _, reply in
Expand All @@ -148,7 +152,7 @@ class ExampleHostApiSetup {
getHostLanguageChannel.setMessageHandler(nil)
}
let addChannel = FlutterBasicMessageChannel(
name: "dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add",
name: "dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
addChannel.setMessageHandler { message, reply in
Expand All @@ -166,7 +170,7 @@ class ExampleHostApiSetup {
addChannel.setMessageHandler(nil)
}
let sendMessageChannel = FlutterBasicMessageChannel(
name: "dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage",
name: "dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
sendMessageChannel.setMessageHandler { message, reply in
Expand All @@ -193,14 +197,16 @@ protocol MessageFlutterApiProtocol {
}
class MessageFlutterApi: MessageFlutterApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger) {
private let messageChannelSuffix: String
init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") {
self.binaryMessenger = binaryMessenger
self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : ""
}
func flutterMethod(
aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void
) {
let channelName: String =
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod"
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod\(messageChannelSuffix)"
let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger)
channel.sendMessage([aStringArg] as [Any?]) { response in
guard let listResponse = response as? [Any?] else {
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/example/app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class _ExampleFlutterApi implements MessageFlutterApi {

void main() {
// #docregion main-dart-flutter
MessageFlutterApi.setup(_ExampleFlutterApi());
MessageFlutterApi.setUp(_ExampleFlutterApi());
// #enddocregion main-dart-flutter
runApp(const MyApp());
}
Expand Down
32 changes: 21 additions & 11 deletions packages/pigeon/example/app/lib/src/messages.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,21 @@ class ExampleHostApi {
/// Constructor for [ExampleHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
ExampleHostApi({BinaryMessenger? binaryMessenger})
: __pigeon_binaryMessenger = binaryMessenger;
ExampleHostApi(
{BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: __pigeon_binaryMessenger = binaryMessenger,
__pigeon_messageChannelSuffix =
messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
final BinaryMessenger? __pigeon_binaryMessenger;

static const MessageCodec<Object?> pigeonChannelCodec =
_ExampleHostApiCodec();

final String __pigeon_messageChannelSuffix;

Future<String> getHostLanguage() async {
const String __pigeon_channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage';
final String __pigeon_channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage$__pigeon_messageChannelSuffix';
final BasicMessageChannel<Object?> __pigeon_channel =
BasicMessageChannel<Object?>(
__pigeon_channelName,
Expand Down Expand Up @@ -134,8 +139,8 @@ class ExampleHostApi {
}

Future<int> add(int a, int b) async {
const String __pigeon_channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add';
final String __pigeon_channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add$__pigeon_messageChannelSuffix';
final BasicMessageChannel<Object?> __pigeon_channel =
BasicMessageChannel<Object?>(
__pigeon_channelName,
Expand Down Expand Up @@ -163,8 +168,8 @@ class ExampleHostApi {
}

Future<bool> sendMessage(MessageData message) async {
const String __pigeon_channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage';
final String __pigeon_channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage$__pigeon_messageChannelSuffix';
final BasicMessageChannel<Object?> __pigeon_channel =
BasicMessageChannel<Object?>(
__pigeon_channelName,
Expand Down Expand Up @@ -198,12 +203,17 @@ abstract class MessageFlutterApi {

String flutterMethod(String? aString);

static void setup(MessageFlutterApi? api,
{BinaryMessenger? binaryMessenger}) {
static void setUp(
MessageFlutterApi? api, {
BinaryMessenger? binaryMessenger,
String messageChannelSuffix = '',
}) {
messageChannelSuffix =
messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
{
final BasicMessageChannel<Object?> __pigeon_channel = BasicMessageChannel<
Object?>(
'dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod',
'dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod$messageChannelSuffix',
pigeonChannelCodec,
binaryMessenger: binaryMessenger);
if (api == null) {
Expand Down
6 changes: 6 additions & 0 deletions packages/pigeon/example/app/macos/Runner/messages.g.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,17 @@ NSObject<FlutterMessageCodec> *PGNExampleHostApiGetCodec(void);
extern void SetUpPGNExampleHostApi(id<FlutterBinaryMessenger> binaryMessenger,
NSObject<PGNExampleHostApi> *_Nullable api);

extern void SetUpPGNExampleHostApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,
NSObject<PGNExampleHostApi> *_Nullable api,
NSString *messageChannelSuffix);

/// The codec used by PGNMessageFlutterApi.
NSObject<FlutterMessageCodec> *PGNMessageFlutterApiGetCodec(void);

@interface PGNMessageFlutterApi : NSObject
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
messageChannelSuffix:(nullable NSString *)messageChannelSuffix;
- (void)flutterMethodAString:(nullable NSString *)aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion;
@end
Expand Down
41 changes: 35 additions & 6 deletions packages/pigeon/example/app/macos/Runner/messages.g.m
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,21 @@ - (FlutterStandardReader *)readerWithData:(NSData *)data {

void SetUpPGNExampleHostApi(id<FlutterBinaryMessenger> binaryMessenger,
NSObject<PGNExampleHostApi> *api) {
SetUpPGNExampleHostApiWithSuffix(binaryMessenger, api, @"");
}

void SetUpPGNExampleHostApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,
NSObject<PGNExampleHostApi> *api,
NSString *messageChannelSuffix) {
messageChannelSuffix = messageChannelSuffix.length > 0
? [NSString stringWithFormat:@".%@", messageChannelSuffix]
: @"";
{
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
initWithName:@"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage"
initWithName:[NSString stringWithFormat:@"%@%@",
@"dev.flutter.pigeon.pigeon_example_package."
@"ExampleHostApi.getHostLanguage",
messageChannelSuffix]
binaryMessenger:binaryMessenger
codec:PGNExampleHostApiGetCodec()];
if (api) {
Expand All @@ -159,7 +171,11 @@ void SetUpPGNExampleHostApi(id<FlutterBinaryMessenger> binaryMessenger,
}
{
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
initWithName:@"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add"
initWithName:
[NSString
stringWithFormat:@"%@%@",
@"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add",
messageChannelSuffix]
binaryMessenger:binaryMessenger
codec:PGNExampleHostApiGetCodec()];
if (api) {
Expand All @@ -181,7 +197,10 @@ void SetUpPGNExampleHostApi(id<FlutterBinaryMessenger> binaryMessenger,
}
{
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
initWithName:@"dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage"
initWithName:[NSString stringWithFormat:@"%@%@",
@"dev.flutter.pigeon.pigeon_example_package."
@"ExampleHostApi.sendMessage",
messageChannelSuffix]
binaryMessenger:binaryMessenger
codec:PGNExampleHostApiGetCodec()];
if (api) {
Expand Down Expand Up @@ -210,21 +229,31 @@ void SetUpPGNExampleHostApi(id<FlutterBinaryMessenger> binaryMessenger,

@interface PGNMessageFlutterApi ()
@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
@property(nonatomic, strong) NSString *messageChannelSuffix;
@end

@implementation PGNMessageFlutterApi

- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
self = [super init];
return [self initWithBinaryMessenger:binaryMessenger messageChannelSuffix:@""];
}
- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger
messageChannelSuffix:(nullable NSString *)messageChannelSuffix {
self = [self init];
if (self) {
_binaryMessenger = binaryMessenger;
_messageChannelSuffix = [messageChannelSuffix length] == 0
? @""
: [NSString stringWithFormat:@".%@", messageChannelSuffix];
}
return self;
}
- (void)flutterMethodAString:(nullable NSString *)arg_aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion {
NSString *channelName =
@"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod";
NSString *channelName = [NSString
stringWithFormat:@"%@%@",
@"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod",
_messageChannelSuffix];
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel messageChannelWithName:channelName
binaryMessenger:self.binaryMessenger
Expand Down
Loading