-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Closed
flutter/packages
#8566Closed
Copy link
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listc: proposalA detailed proposal for a change to FlutterA detailed proposal for a change to Flutterp: pigeonrelated to pigeon messaging codegen toolrelated to pigeon messaging codegen toolpackageflutter/packages repository. See also p: labels.flutter/packages repository. See also p: labels.r: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer versionteam-ecosystemOwned by Ecosystem teamOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem teamTriaged by Ecosystem team
Description
Use case
In my project, I organize interface definitions across multiple files. I want to define EventChannelApi in multiple files using the @EventChannelApi() annotation.
However, this results in the generation of duplicate classes (e.g., PigeonEventChannelWrapper and PigeonEventSink in Swift), which causes build errors.
Code Example
Input files
a.dart
import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(PigeonOptions(
dartOut: 'lib/src/a.g.dart',
dartOptions: DartOptions(),
kotlinOut: 'android/app/src/main/kotlin/dev/flutter/pigeon_sample/A.g.kt',
kotlinOptions: KotlinOptions(),
swiftOut: 'ios/Runner/A.g.swift',
swiftOptions: SwiftOptions(),
))
@EventChannelApi()
abstract class EventA {
int streamA();
}b.dart
import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(PigeonOptions(
dartOut: 'lib/src/b.g.dart',
dartOptions: DartOptions(),
kotlinOut: 'android/app/src/main/kotlin/dev/flutter/pigeon_sample/B.g.kt',
kotlinOptions: KotlinOptions(includeErrorClass: false),
swiftOut: 'ios/Runner/B.g.swift',
swiftOptions: SwiftOptions(includeErrorClass: false),
))
@EventChannelApi()
abstract class EventB {
int streamB();
}Output files
A.g.swift
// Autogenerated from Pigeon (v22.7.2), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#else
#error("Unsupported platform.")
#endif
/// Error class for passing custom error details to Dart side.
final class PigeonError: Error {
let code: String
let message: String?
let details: Any?
init(code: String, message: String?, details: Any?) {
self.code = code
self.message = message
self.details = details
}
var localizedDescription: String {
return
"PigeonError(code: \(code), message: \(message ?? "<nil>"), details: \(details ?? "<nil>")"
}
}
private func isNullish(_ value: Any?) -> Bool {
return value is NSNull || value == nil
}
private func nilOrValue<T>(_ value: Any?) -> T? {
if value is NSNull { return nil }
return value as! T?
}
private class APigeonCodecReader: FlutterStandardReader {
}
private class APigeonCodecWriter: FlutterStandardWriter {
}
private class APigeonCodecReaderWriter: FlutterStandardReaderWriter {
override func reader(with data: Data) -> FlutterStandardReader {
return APigeonCodecReader(data: data)
}
override func writer(with data: NSMutableData) -> FlutterStandardWriter {
return APigeonCodecWriter(data: data)
}
}
class APigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable {
static let shared = APigeonCodec(readerWriter: APigeonCodecReaderWriter())
}
var aPigeonMethodCodec = FlutterStandardMethodCodec(readerWriter: APigeonCodecReaderWriter());
private class PigeonStreamHandler<ReturnType>: NSObject, FlutterStreamHandler {
private let wrapper: PigeonEventChannelWrapper<ReturnType>
private var pigeonSink: PigeonEventSink<ReturnType>? = nil
init(wrapper: PigeonEventChannelWrapper<ReturnType>) {
self.wrapper = wrapper
}
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink)
-> FlutterError?
{
pigeonSink = PigeonEventSink<ReturnType>(events)
wrapper.onListen(withArguments: arguments, sink: pigeonSink!)
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
pigeonSink = nil
wrapper.onCancel(withArguments: arguments)
return nil
}
}
class PigeonEventChannelWrapper<ReturnType> {
func onListen(withArguments arguments: Any?, sink: PigeonEventSink<ReturnType>) {}
func onCancel(withArguments arguments: Any?) {}
}
class PigeonEventSink<ReturnType> {
private let sink: FlutterEventSink
init(_ sink: @escaping FlutterEventSink) {
self.sink = sink
}
func success(_ value: ReturnType) {
sink(value)
}
func error(code: String, message: String?, details: Any?) {
sink(FlutterError(code: code, message: message, details: details))
}
func endOfStream() {
sink(FlutterEndOfEventStream)
}
}
class StreamAStreamHandler: PigeonEventChannelWrapper<Int64> {
static func register(with messenger: FlutterBinaryMessenger,
instanceName: String = "",
streamHandler: StreamAStreamHandler) {
var channelName = "dev.flutter.pigeon.pigeon_sample.EventA.streamA"
if !instanceName.isEmpty {
channelName += ".\(instanceName)"
}
let internalStreamHandler = PigeonStreamHandler<Int64>(wrapper: streamHandler)
let channel = FlutterEventChannel(name: channelName, binaryMessenger: messenger, codec: aPigeonMethodCodec)
channel.setStreamHandler(internalStreamHandler)
}
}
B.g.swift
// Autogenerated from Pigeon (v22.7.2), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#else
#error("Unsupported platform.")
#endif
private func isNullish(_ value: Any?) -> Bool {
return value is NSNull || value == nil
}
private func nilOrValue<T>(_ value: Any?) -> T? {
if value is NSNull { return nil }
return value as! T?
}
private class BPigeonCodecReader: FlutterStandardReader {
}
private class BPigeonCodecWriter: FlutterStandardWriter {
}
private class BPigeonCodecReaderWriter: FlutterStandardReaderWriter {
override func reader(with data: Data) -> FlutterStandardReader {
return BPigeonCodecReader(data: data)
}
override func writer(with data: NSMutableData) -> FlutterStandardWriter {
return BPigeonCodecWriter(data: data)
}
}
class BPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable {
static let shared = BPigeonCodec(readerWriter: BPigeonCodecReaderWriter())
}
var bPigeonMethodCodec = FlutterStandardMethodCodec(readerWriter: BPigeonCodecReaderWriter());
private class PigeonStreamHandler<ReturnType>: NSObject, FlutterStreamHandler {
private let wrapper: PigeonEventChannelWrapper<ReturnType>
private var pigeonSink: PigeonEventSink<ReturnType>? = nil
init(wrapper: PigeonEventChannelWrapper<ReturnType>) {
self.wrapper = wrapper
}
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink)
-> FlutterError?
{
pigeonSink = PigeonEventSink<ReturnType>(events)
wrapper.onListen(withArguments: arguments, sink: pigeonSink!)
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
pigeonSink = nil
wrapper.onCancel(withArguments: arguments)
return nil
}
}
class PigeonEventChannelWrapper<ReturnType> {
func onListen(withArguments arguments: Any?, sink: PigeonEventSink<ReturnType>) {}
func onCancel(withArguments arguments: Any?) {}
}
class PigeonEventSink<ReturnType> {
private let sink: FlutterEventSink
init(_ sink: @escaping FlutterEventSink) {
self.sink = sink
}
func success(_ value: ReturnType) {
sink(value)
}
func error(code: String, message: String?, details: Any?) {
sink(FlutterError(code: code, message: message, details: details))
}
func endOfStream() {
sink(FlutterEndOfEventStream)
}
}
class StreamBStreamHandler: PigeonEventChannelWrapper<Int64> {
static func register(with messenger: FlutterBinaryMessenger,
instanceName: String = "",
streamHandler: StreamBStreamHandler) {
var channelName = "dev.flutter.pigeon.pigeon_sample.EventB.streamB"
if !instanceName.isEmpty {
channelName += ".\(instanceName)"
}
let internalStreamHandler = PigeonStreamHandler<Int64>(wrapper: streamHandler)
let channel = FlutterEventChannel(name: channelName, binaryMessenger: messenger, codec: bPigeonMethodCodec)
channel.setStreamHandler(internalStreamHandler)
}
}
Proposal
I propose introducing a new configuration option in SwiftOptions and KotlinOptions to control the generation of shared utility classes (e.g., PigeonEventChannelWrapper and PigeonEventSink) similar to the includeErrorClass option.
yuukiw00w and satorbs
Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listc: proposalA detailed proposal for a change to FlutterA detailed proposal for a change to Flutterp: pigeonrelated to pigeon messaging codegen toolrelated to pigeon messaging codegen toolpackageflutter/packages repository. See also p: labels.flutter/packages repository. See also p: labels.r: fixedIssue is closed as already fixed in a newer versionIssue is closed as already fixed in a newer versionteam-ecosystemOwned by Ecosystem teamOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem teamTriaged by Ecosystem team