Skip to content

Commit

Permalink
[pigeon] Allow multi instance support with message channel name suffix (
Browse files Browse the repository at this point in the history
flutter#6224)

Adds the ability to instantiate any api using a suffix string to allow for unique instances. 

partial flutter/flutter#66710
  • Loading branch information
tarrinneal authored Apr 3, 2024
1 parent 3ff376b commit 0f14d4f
Show file tree
Hide file tree
Showing 60 changed files with 3,843 additions and 1,497 deletions.
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

0 comments on commit 0f14d4f

Please sign in to comment.