Introduction to the

Pigeon was released in Flutter 1.20. In order to solve the problem that the native code of Flutter is too troublesome and difficult to call, it is necessary to match function names and parameters on the basis of strings. This can be done by using this package. But there is still a difference with their own projects.

  • Securely communicate with native types

  • Reduce the amount of handwritten code through automatic generation

This article describes in detail how to use Pigeon to call a simple getPlatformVersion method implemented in Swift/Kotlin from the Flutter side. Sample projects are available here.

Create a Flutter app


$ flutter create -i swift -a kotlin flutter_pigeon

Copy the code

What does a Pigeon do

The Java/Objective-C interface protocol is automatically generated based on the parameters and return value information defined on the Dart side.

The native implementation is based on these interfaces to enable type-safe communication with the Flutter end.

This is similar to creating type definition files with TypeScript.

The installation


# pubspec.yamlDev_dependencies: pigeon: ^ 1.0.0Copy the code

Dart

First, create a DART file that defines communication with the native. Create a pigeon/schema.dart file in the root directory


// schema.dart
import 'package:pigeon/pigeon.dart';

class Version {

  late String string;

}

@HostApi(a)abstract class Api {

  Version getPlatformVersion();

}

Copy the code

Create a new script file run_pigeon


# run_pigeon.h

$ flutter pub run pigeon \

  --input pigeon/schema.dart \

  --dart_out lib/api_generated.dart  \

  --objc_header_out ios/Runner/Pigeon.h \

  --objc_source_out ios/Runner/Pigeon.m \

  --objc_prefix FLT \

  --java_out android/app/src/main/java/io/flutter/plugins/Pigeon.java \

  --java_package "io.flutter.plugins"

Copy the code

Run the script to automatically generate the corresponding interface file


$ ./run_pigeon.sh

Copy the code

Import and use the Dart file that Pigeon generated where native method functions need to be called

Kotlin

The API interface is written in a Java file that Pigeon generated, so create a class that implements it and pass it to the setup method.


// MainActivity.kt

package com.example.flutter_pigeon

import io.flutter.embedding.android.FlutterActivity

import io.flutter.embedding.engine.FlutterEngine

import io.flutter.plugins.Pigeon


class MainActivity: FlutterActivity() {

    private class MyApi: Pigeon.Api {

        override fun getPlatformVersion(a): Pigeon.Version {

            var result = Pigeon.Version()

            result.string = "Android ${android.os.Build.VERSION.RELEASE}"

            return result

        }

    }


    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {

        super.configureFlutterEngine(flutterEngine)

        // 2. setup()

        Pigeon.Api.setup(flutterEngine.dartExecutor.binaryMessenger, MyApi())

    }
}

Copy the code

Swift

Add import statements to the bridge file ios/RunnerRunner-Bridging- header. h to make Pigeon’s Objective-C file visible to Swift


// ios / Runner / Runner-Bridging-Header.h

#import "Pigeon.h"

Copy the code

Since the API protocol is written in the generated file, create a class MyApi that implements the protocol

Create the swiftPigeonService. swift file to implement the protocol method


// SwiftPigeonService.swift

import Flutter

import UIKit

public class SwiftPigeonService: NSObject.FLTApi {

    public func getPlatformVersionWithError(_ error: AutoreleasingUnsafeMutablePointer<FlutterError? >) -> FLTVersion? {

        let result = FLTVersion.init()

        result.string = "iOS " + UIDevice.current.systemVersion

        return result

    }

}

Copy the code

Instantiate the API in the AppDelegate and pass it to the setup method


// AppDelegate.swift

import UIKit

import Flutter


@UIApplicationMain

@objc class AppDelegate: FlutterAppDelegate {

  override func application(

    _ application: UIApplication.didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?

  ) -> Bool {

   let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

    FLTApiSetup(controller.binaryMessenger, SwiftPigeonService())

    GeneratedPluginRegistrant.register(with: self)

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)

  }

}

Copy the code

conclusion

  • Pigeon automatically generates parts of content associated with using MethodChannel. (Pigeon, technically, used a BasicMessageChannel.)

  • Predefined schemas allow type-safe communication with Native

  • The generated code is Java/Objective-C, but since Kotlin can call Java, Swift can call Objective-C

  • You don’t have to know the Dart side code (just call the automatically generated API)

  • You don’t have to know native code (just implement an automatically generated interface)

  • The video_player is already in use in the official plugin