Flutter communicate between with Native Code (Android and iOS).

Introduction

In Flutter development, integrating native platform functionality, like accessing device sensors or native UI elements, often requires a way to communicate seamlessly between Flutter and native code. Pigeon is a tool designed to simplify this by generating type-safe message-based communication channels between Flutter and native Android or iOS code, enabling developers to bridge this gap efficiently.

What is Pigeon?

Pigeon allows Flutter developers to define a shared API in Dart code, which it uses to generate code that facilitates communication between Flutter and the native platforms. It minimizes boilerplate, supports type-safe data exchange, and enables smoother cross-platform functionality in Flutter projects.

Setting Up Pigeon

To start using Pigeon, add it to your dev_dependencies in your pubspec.yaml:

dev_dependencies:
  pigeon: ^4.2.0

Run flutter pub get to install it. Next, define a .dart file to serve as the Pigeon API schema, which specifies the methods and data structures for communication.

Defining the Pigeon Schema

Create a file, pigeon_schema.dart, and define the classes for messages as well as methods to expose to native code. For instance, if you want to retrieve the battery level, define it like this:

import 'package:pigeon/pigeon.dart';

class BatteryRequest {}
class BatteryResponse {
  int? level;
}

@HostApi()
abstract class BatteryApi {
  BatteryResponse getBatteryLevel(BatteryRequest request);
}

Generating Code

Run Pigeon to generate the platform-specific code. Use the following command:

flutter pub run pigeon \
  --input pigeons/pigeon_schema.dart \
  --dart_out lib/pigeon.dart \
  --java_out android/app/src/main/java/com/example/app/Pigeon.java \
  --java_package "com.example.app"

This command will generate Dart and Java files based on the schema. Make sure to specify appropriate paths for your project structure.

Integrating with Native Code

Android

In MainActivity.java, implement the methods defined in the Pigeon-generated file:

import com.example.app.Pigeon;

public class MainActivity extends FlutterActivity {
  @Override
  public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    super.configureFlutterEngine(flutterEngine);
    Pigeon.BatteryApi.setup(flutterEngine.getDartExecutor(), new Pigeon.BatteryApi() {
      @Override
      public Pigeon.BatteryResponse getBatteryLevel(Pigeon.BatteryRequest request) {
        Pigeon.BatteryResponse response = new Pigeon.BatteryResponse();
        response.setLevel(getBatteryLevel()); // Native method
        return response;
      }
    });
  }
}

Best Practices and Considerations

Consistency in Naming: Keep naming consistent between Dart, Java, and Objective-C/Swift files to simplify development.

  1. Error Handling: Implement thorough error handling in both Flutter and native code to avoid crashes.
  2. Schema Updates: Any changes in the Pigeon schema will require regenerating the files and updating the native code.

Conclusion

By leveraging Pigeon, Flutter developers can achieve seamless, type-safe integration with native Android and iOS functionalities, making it easier to implement platform-specific features in cross-platform applications. This approach not only reduces boilerplate code but also maintains the performance and reliability required in production applications.

riduns

© 2025 Aria

Instagram 𝕏 GitHub