





















At Nutrient, we deliver a high-performance PDF SDK that powers PDF viewing, annotation, form filling, digital signatures, and real-time collaboration across multiple platforms. Our Flutter SDK wraps these native implementations, providing Flutter developers with the same powerful PDF capabilities through a unified API. Since our SDK bridges complex native functionality to Flutter, tight, type-safe interoperability is essential. Pigeon enables us to expose native functionality with minimal boilerplate while maintaining strong type safety across all platforms.
This post will explore:
Pigeon(opens in a new tab) is a code generation tool that creates type-safe communication between Flutter and host platforms. Instead of manually writing platform channel code, you define your API once in Dart, and Pigeon generates the corresponding native code for iOS, Android, and Flutter.
Flutter apps often need to access platform-specific functionality that isn’t available in Dart. The traditional approach uses method channels — a message-passing system between Flutter and native code. However, this approach has significant drawbacks:
Map<String, dynamic> objectsWhen we evaluated solutions for our Flutter SDK, Pigeon stood out for several reasons:
Type safety — Pigeon generates strongly typed interfaces, catching errors at compile time rather than runtime. For a complex PDF SDK with hundreds of methods, this was crucial.
Reduced boilerplate — Instead of writing serialization code for each platform, we define our API once and let Pigeon handle the rest. This dramatically reduced our codebase size.
Consistency — All our platform bridges follow the same patterns, making the code easier to understand and maintain across iOS and Android.
Asynchronous support — Pigeon supports both synchronous and asynchronous operations, which is essential for PDF operations that can be time-consuming.
Active development — As a Google-backed project, Pigeon receives regular updates and has strong community support.
Before we started using Pigeon, here’s how we implemented processAnnotations with manual platform channels:
// From `nutrient_flutter_method_channel.dart`.
Future<bool?> processAnnotations(
AnnotationType type,
AnnotationProcessingMode processingMode,
String destinationPath,
) async =>
methodChannel.invokeMethod('processAnnotations', <String, String>{
'type': type.fullName,
'processingMode': processingMode.name,
'destinationPath': destinationPath
});
There were a few problems with this, namely the manual parameter serialization into a <String, String> map, explicit enum-to-string conversion, and string-based method names.
Here’s the same processAnnotations method using Pigeon:
// From `nutrient_flutter_api_impl.dart`.
Future<bool?> processAnnotations(
AnnotationType type,
AnnotationProcessingMode processingMode,
String destinationPath
) {
return _nutrientApi.processAnnotations(
type,
processingMode,
destinationPath
);
}
What changed? Now there’s a direct API call with native parameter types, no manual serialization, and type-safe method invocation.
But the real difference comes from manual map creation and enum conversion vs. direct, type-safe parameter passing.
After using Pigeon in production for our PDF SDK, these are the benefits that matter most to us:
1. Single source of truth — API definitions live in one Dart file. When we change a method signature, the compiler immediately tells us what breaks across iOS, Android, and Flutter, which means no more discovering API mismatches at runtime.
2. Developer velocity — Compare the processAnnotations examples above: Eight lines of manual serialization became three lines of direct method calls. Multiply this across 200+ API methods, and the productivity gain is substantial.
3. Bulletproof type safety — No more as Map<String, dynamic> casting or enum-to-string conversions. Pigeon’s generated code handles type safety automatically, eliminating an entire class of runtime crashes.
4. Consistent patterns — Every API follows the same generated structure. New team members don’t need to learn our custom serialization patterns; they just work with clean, predictable interfaces.
5. Future-proof architecture — As our SDK evolves, Pigeon scales with us. Adding new methods or changing existing ones is now a matter of updating one definition file rather than three platform implementations.
At Nutrient, our Flutter SDK is built on top of our mature native iOS, Android, and Web SDKs. Pigeon serves as the primary bridge between Flutter and our native platforms, handling the vast majority of our API surface. Check out our Flutter customization guide(opens in a new tab) for more details on how we use Pigeon to connect our native SDKs to Flutter.
Explore our Flutter customization guide to see how we use Pigeon to bridge native functionality and build type-safe platform integrations.
Pigeon has significant constraints when it comes to object-oriented programming patterns that are common in native SDKs.
What’s not supported:
What’s partially supported:
TextAnnotation, InkAnnotation, and ShapeAnnotation all inherit from a base Annotation class cannot be directly modeled in Pigeon.In the Google announcement, “Flutter’s path towards seamless interop”(opens in a new tab), the Flutter team highlighted FFIgen and JNIgen as the next generation of native interoperability tools. Unlike Pigeon, which uses method channels, these tools generate direct bindings with better performance characteristics.
Benefits over Pigeon:
Current status (November 2025):
At Nutrient, we’re in the early phases of experimenting with FFIgen and JNIgen to explore a bindings-based approach for our Flutter SDK. While Pigeon continues to serve us well, direct native bindings could offer performance improvements and help us overcome the inheritance limitations we currently work around.
For Nutrient Flutter SDK, Pigeon has been a gamechanger despite its limitations. The benefits — type safety, reduced boilerplate, faster development cycles, and fewer runtime errors — far outweigh the challenges. While we occasionally need manual workarounds for complex inheritance hierarchies, Pigeon handles the vast majority of our platform bridging needs elegantly.
The upcoming FFIgen and JNIgen tools promise even better performance and flexibility, which could help us overcome current limitations. However, Pigeon’s simplicity and battle-tested reliability make it an excellent choice for teams building production Flutter plugins today.
If you’re considering Pigeon for your Flutter plugin:
At Nutrient, Pigeon remains an essential tool in our Flutter SDK development toolkit, enabling us to deliver a consistent, reliable document processing experience across iOS and Android while maintaining our development velocity.
Experience Nutrient Flutter SDK with seamless native interoperability. Add PDF viewing, annotation, and collaboration to your Flutter app.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。