Tool plugin: Pigeon

The official must-see example: Pigeon_plugin_example

4. Pigeons: ① pigeon/example ② pigeons

Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier and faster. A code generation tool that makes Flutter and its host platform safer, simpler, and faster to communicate.

The Dart entry generates template code that is common to both ends, while the native interface needs to be overridden within the template without managing the implementation of the Method Channel. Parameters can be generated synchronously from templates.

Pigeon currently supports only OC and Java code generation.

1. Create a commandPlugin

$ flutter create --template=plugin --platforms=android,ios -i swift -a kotlin flutter_pigeon_plugin

2,flutterIn the projectpubspec.yamlthedev_dependencies, addpigeonPlug-in dependencies

Dev_dependencies: flutter_test: SDK: flutter_lints: ^1.0.0:Copy the code

3, inFlutterThe projectlibCreate one outside the directorypigeonsFolder, inpigeonsCreate in folderall_types_pigeon.dart

import 'package:pigeon/pigeon.dart'; class Everything { bool? aBool; int? anInt; double? aDouble; String? aString; Uint8List? aByteArray; Int32List? a4ByteArray; Int64List? a8ByteArray; Float64List? aFloatArray; // ignore: always_specify_types List? aList; // ignore: always_specify_types Map? aMap; List<List<bool? >? >? nestedList; Map<String? , String? >? mapWithAnnotations; } /// the native method of Flutter calls @hostapi () abstract class HostEverything {Everything giveMeEverything(); Everything echo(Everything everything); } @flutterAPI () abstract class FlutterEverything {Everything giveMeEverythingFlutter(); Everything echoFlutter(Everything everything); }Copy the code

4. Run the command

First create a folder for the generated files: Under Android/SRC /mian create the Java /com/example/ Flutter_pigeon_plugin/folder where you will get the generated Java files.

Under the project directory ~/flutter_pigeon_plugin, execute the following command: $ flutter pub run pigeon –input pigeons/all_types_pigeon.dart –dart_out lib/all_types_pigeon.dart –objc_header_out ios/Classes/AllTypesPigeon.h –objc_source_out ios/Classes/AllTypesPigeon.m –java_out android/src/main/java/com/example/flutter_pigeon_plugin/AllTypesPigeon.java –java_package “com.example.flutter_pigeon_plugin”

Command disassembly: ①` flutter pub run pigeon`Command to generate code ②` --input pigeons/all_types_pigeon.dart `Specifies the input to generate code`dart`The file 3.`--dart_out lib/all_types_pigeon.dart `Specify output generation`dart`File directory file ④`--objc_header_out ios/Classes/AllTypesPigeon.h `Specifies what to build`iOS`the`.h`File path ⑤`--objc_source_out ios/Classes/AllTypesPigeon.m `Specifies what to build`iOS`the`.m`File path ⑥`--java_out android/src/main/java/com/example/flutter_pigeon_plugin/AllTypesPigeon.java `Specifies what to build`Android`the`.java`File path ⑦`--java_package "com.example.flutter_pigeon_plugin`The specified`Android`Package name, in`android/src/main/`Under the`AndroidManifest.xml`In the`package``--objc_prefix FLT`(Optional) Specify the prefix of the GENERATED OC file as FLT. The prefix is self-defined.Copy the code

/run_pigeon. Sh: run_pigeon. Sh: run_pigeon.

flutter pub run pigeon \
  --input pigeons/all_types_pigeon.dart \
  --dart_out lib/all_types_pigeon.dart \
  --objc_header_out ios/Classes/AllTypesPigeon.h \
  --objc_source_out ios/Classes/AllTypesPigeon.m \
  --objc_prefix FLT \
  --java_out android/src/main/java/com/example/flutter_pigeon_plugin/AllTypesPigeon.java \
  --java_package "com.example.flutter_pigeon_plugin"
Copy the code

When the command is executed, response files are automatically generated in the specified locations.

5,iOSimplementationFlutterCall the native method

A method called HostEverythingSetup is automatically generated in AllTypesPigeon

void HostEverythingSetup(id<FlutterBinaryMessenger> binaryMessenger, NSObject<HostEverything> *api) { { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel messageChannelWithName:@"dev.flutter.pigeon.HostEverything.giveMeEverything" binaryMessenger:binaryMessenger codec:HostEverythingGetCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(giveMeEverythingWithError:)], @"HostEverything api doesn't respond to @selector(giveMeEverythingWithError:)"); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { FlutterError *error;  Everything *output = [api giveMeEverythingWithError:&error]; callback(wrapResult(output, error)); }]; } else { [channel setMessageHandler:nil]; } } { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel messageChannelWithName:@"dev.flutter.pigeon.HostEverything.echo" binaryMessenger:binaryMessenger codec:HostEverythingGetCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(echoEverything:error:)], @"HostEverything api doesn't respond to @selector(echoEverything:error:)"); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message;  Everything *arg_everything = args[0]; FlutterError *error;  Everything *output = [api echoEverything:arg_everything error:&error]; callback(wrapResult(output, error)); }]; } else { [channel setMessageHandler:nil]; }}}Copy the code

(3) in SwiftFlutterPigeonPlugin. Swift registration method, call the setup method to initialize and Settings

    public static func register(with registrar: FlutterPluginRegistrar) {
        let messenger: FlutterBinaryMessenger = registrar.messenger()
        let api: HostEverything & NSObjectProtocol = SwiftFlutterPigeonPlugin.init()
        HostEverythingSetup(messenger, api)
    }
Copy the code

4. Swiftflutterutterthing Plugin complies with the HostEverything protocol, which implements the native method of Flutter

import Flutter
import UIKit

Follow the HostEverything protocol to implement the native method of Flutter
public class SwiftFlutterPigeonPlugin: NSObject.FlutterPlugin.HostEverything {
    public static func register(with registrar: FlutterPluginRegistrar) {
        let messenger: FlutterBinaryMessenger = registrar.messenger()
        let api: HostEverything & NSObjectProtocol = SwiftFlutterPigeonPlugin.init(a)HostEverythingSetup(messenger, api)
    }

    // MARK: HostEverything

    public func giveMeEverythingWithError(_ error: AutoreleasingUnsafeMutablePointer<FlutterError? >) -> Everything? {
        let everyThing = Everything()
        everyThing.aString = "Native string returned to Flutter"
        everyThing.aBool = false
        everyThing.anInt = 11
        return everyThing
    }

    Follow the HostEverything protocol to implement the native method of Flutter
    public func echo(_ everything: Everything.error: AutoreleasingUnsafeMutablePointer<FlutterError? >) -> Everything? {
        everything.aString = "Native exchanged strings for Flutter"
        everything.aBool = false
        everything.anInt = 12
        return everything
    }
}

Copy the code

⑤ To iOS/Classes, create the flutter_pigeon_plugin.h file and import the header file. This file is automatically referenced in the iOS auto-generated

file.

//
//  flutter_pigeon_plugin.h
//  Pods
//
//  Created by yuanzhiying on 2021/9/13.
//

#ifndef flutter_pigeon_plugin_h
#define flutter_pigeon_plugin_h

#import "AllTypesPigeon.h"

#endif /* flutter_pigeon_plugin_h */

Copy the code

6,flutter_pigeon_plugin.dartIn the implementation of plug-in tuning native method

import 'dart:async';

import 'package:flutter_pigeon_plugin/all_types_pigeon.dart';

class FlutterPigeonPlugin {
  static final HostEverything _hostEverything = HostEverything();

  /// Flutter calls native methods
  static Future<Everything> getEverything() async {
    return await _hostEverything.giveMeEverything();
  }

  /// Flutter calls native methods
  static Future<Everything> echoEveryThing(Everything everything) async {
    return await_hostEverything.echo(everything); }}Copy the code

7. Using plug-ins

  Future<void> getHostData() async {
    /// Invoke native methods through plug-ins
    Everything everything = await FlutterPigeonPlugin.getEverything();
    debugPrint('everything.aString: ${everything.aString}');
    debugPrint('everything.aBool: ${everything.aBool}');
    debugPrint('everything. AnInt:${everything.anInt}');
  }

  void echoHostData() async {
    Everything echoEveryThing = Everything();
    echoEveryThing.aString = 'String I want to swap with native';
    echoEveryThing.aBool = true;
    echoEveryThing.anInt = 10;

    /// Invoke native methods through plug-ins
    Everything everything = await FlutterPigeonPlugin.echoEveryThing(echoEveryThing);
    debugPrint('everything.aString: ${everything.aString}');
    debugPrint('everything.aBool: ${everything.aBool}');
    debugPrint('everything. AnInt:${everything.anInt}');
  }
Copy the code

At this point, Flutter calls the native iOS method to complete.

Eight,flutterCall the android native implementation

(1) delete the old version number for the channel code. (2) FlutterPigeonPlugin kt inherit AllTypesPigeon. HostEverything, and implement the corresponding method

  override fun giveMeEverything(a): AllTypesPigeon.Everything {
    var everything: AllTypesPigeon.Everything = AllTypesPigeon.Everything()
    everything.aString = "Native string returned to Flutter"
    everything.aBool = false
    everything.anInt = 11
    return everything
  }

  override fun echo(everything: AllTypesPigeon.Everything?).: AllTypesPigeon.Everything? { everything? .aString ="Native exchanged strings for Flutter"everything? .aBool =falseeverything? .anInt =12
    return everything
  }
Copy the code

3 Use the automatically generated setup method to initialize and set the parameters

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    AllTypesPigeon.HostEverything.setup(flutterPluginBinding.binaryMessenger, this)}override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
    AllTypesPigeon.HostEverything.setup(binding.binaryMessenger, null)}Copy the code

The final result is as follows:

package com.example.flutter_pigeon_plugin

import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

/** FlutterPigeonPlugin */
class FlutterPigeonPlugin: FlutterPlugin.MethodCallHandler.AllTypesPigeon.HostEverything {

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    AllTypesPigeon.HostEverything.setup(flutterPluginBinding.binaryMessenger, this)}override fun onMethodCall(@NonNull call: MethodCall.@NonNull result: Result) {
    result.notImplemented()
  }

  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
    AllTypesPigeon.HostEverything.setup(binding.binaryMessenger, null)}override fun giveMeEverything(a): AllTypesPigeon.Everything {
    var everything: AllTypesPigeon.Everything = AllTypesPigeon.Everything()
    everything.aString = "Native string returned to Flutter"
    everything.aBool = false
    everything.anInt = 11
    return everything
  }

  override fun echo(everything: AllTypesPigeon.Everything?).: AllTypesPigeon.Everything? { everything? .aString ="Native exchanged strings for Flutter"everything? .aBool =falseeverything? .anInt =12
    return everything
  }
}

Copy the code

The project code is: Flutter_pigeon_plugin