How can I specify a type in Pigeon to be a Map (e.g. Map<String, String>
), and preferably a Map with dynamic value types (Map<String, dynamic>
. I can't know for sure what type the data
values are until the push message is sent.
I've tried to define a class using:
class RemoteMessage {
Notification? notification;
Map<String, dynamic>? data;
}
Unfortunately, I get an error message:
Error: pigeons/push.dart:6: Generic type arguments must be nullable in field "data" in class "RemoteMessage".
Error: pigeons/push.dart:6: Generic type arguments must be nullable in field "data" in class "RemoteMessage".
I also tried making dynamic
optional as well:
class RemoteMessage {
Notification? notification;
Map<String, dynamic?>? data;
}
In that case, I get only 1 instance of the error:
Error: pigeons/push.dart:6: Generic type arguments must be nullable in field "data" in class "RemoteMessage".
If I make the key type optional, i.e. Map<String?, dynamic>? data;
, I get the error:
Unhandled exception:
FileSystemException: Cannot open file, path = './android/app/src/main/java/dev/flutter/pigeon/Pigeon.java' (OS Error: No such file or directory, errno = 2)
#0 _File.open.<anonymous closure> (dart:io/file_impl.dart:356:9)
<asynchronous suspension>
pub finished with exit code 255
It looks like Pigeon doesn't support Map
or dynamic
, although it should already support generics: https://github.com/flutter/flutter/issues/63468.
After a couple of issues on Flutter (1 and 2), where Stuart Morgan (a developer from Google probably working on Dart / Pigeon) gave me some help, I realized that my class should look like:
class RemoteMessage {
Notification? notification;
Map<String?, Object?>? data;
}
Key takeaways:
Object
instead of dynamic
, because Pigeon otherwise generates broken code in Java, Objective-C and Dart. This is a bug I reported in Pigeon: using dynamic generates code...:
dynamic.decode()
@property(nonatomic, strong, nullable) NSDictionary<NSString *, dynamic *> * data;
public void setData(Map<String, dynamic> setterArg) { this.data = setterArg; }
?
for all types, including using String?
as the type for Map key instead of String
: Map<String?, Object?>
.