Flutter中的信鸽 Pigeon使用

788 阅读3分钟

Pigeon是Flutter官方为了解决Flutter和Native互相调用过于繁琐,所发布的一款插件。使用Pigeon开发插件,过程会变得非常简单。

本文档编写时间为2022年4月24日,使用Flutter版本为 stable 2.10.4 Pigeon版本为3.0.3

新建plugin并引入pigeon

flutter create --template=plugin --platforms android,ios flutter_pigeon_plugin

pubspec.yaml中加入以下代码

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0
  
  # 将下方代码加入对应位置
  pigeon: 

执行flutter pub get

编写pigeon文件

项目内新建文件夹pigeons,并在其中新建message.dart(此为示例,实际开发中文件名及文件夹随意)

编写message.dart

// pigeons/message.dart

import 'package:pigeon/pigeon.dart';

class F2NMessage{
  String? msg;
}

class N2FMessage{
  String? msg2;
}

@HostApi()
abstract class FlutterMessage{
  void flutterSendMessage(F2NMessage msg);
}

@FlutterApi()
abstract class NativeMessage{
  void nativeSendMessage(N2FMessage msg);
}

在demo中,我新建了一个flutter发往native的方法flutterSendMessage,参数为F2NMessage。新建了一个native发往flutter的方法nativeSendMessage,参数为N2FMessage

新建一个sh脚本(作者为Mac系统,windows系统请自行编写)run_pigeon.sh

# run_pigeon.sh


mkdir -p android/src/main/java/com/example/flutter_pigeon_plugin

flutter pub run pigeon \
  --input pigeons/message.dart \
  --dart_out lib/message.dart \
  --objc_header_out ios/Classes/Message.h \
  --objc_source_out ios/Classes/Message.m \
  --java_out android/src/main/java/com/example/flutter_pigeon_plugin/Message.java \
  --java_package "com.example.flutter_pigeon_plugin" 

由于我新建的是kt/swift插件,所以需要新建android/src/main/java/com/example/flutter_pigeon_plugin文件夹用于存放自动生成的Message.java文件,pigeon目前仅支持java和objc类型,不过由于kt/swift与java/objc均可互相调用,所以没有任何影响。

编写插件

上一步sh执行完成后,插件自动在lib下生成了对应的message.dart文件,我们这时候可以在lib/flutter_pigeon_plugin.dart中开始编写插件。

// lib/flutter_pigeon_plugin.dart


import 'package:flutter_pigeon_plugin/message.dart';

class FlutterPigeonPlugin extends NativeMessage {
  static final FlutterMessage _flutterMessage = FlutterMessage();

  factory FlutterPigeonPlugin() => _getInstance();

  static FlutterPigeonPlugin get instance => _getInstance();

  static FlutterPigeonPlugin? _instance = null;

  static FlutterPigeonPlugin _getInstance() {
    _instance ??= FlutterPigeonPlugin._internal();
    NativeMessage.setup(_instance);
    return _instance!;
  }

  FlutterPigeonPlugin._internal();

  void sendMessage() {
    F2NMessage message = F2NMessage();
    message.msg = "这是一条从Flutter发往Native的消息";
    _flutterMessage.flutterSendMessage(message);
  }

  @override
  void nativeSendMessage(N2FMessage msg) {
    print("收到了Native发来的消息:${msg.msg2}");
  }
}

从以上代码中,我们可以了解到如何向Native发送消息,及如何接收Native发来的消息。

编写iOS端代码

由于插件使用swift开发,故仅提供swift类型插件的相关说明,Objective-C可以参阅swift代码自行修改

run_pigeon.sh文件执行完成后,ios/Classes文件夹中已经自行生成大量代码。首先我们需要新建flutter_pigeon_plugin.h文件,方便让swift文件自动引入我们新建的代码

// ios/Classes/flutter_pigeon_plugin.h

#import "Message.h"

编写SwiftFlutterPigeonPlugin.swift文件

// ios/Classes/SwiftFlutterPigeonPlugin.swift


import Flutter
import UIKit

public class SwiftFlutterPigeonPlugin: NSObject, FlutterPlugin,FlutterMessage {
    public func flutterSendMsg(_ msg: F2NMessage, error: AutoreleasingUnsafeMutablePointer<FlutterError?>) {
        print("收到来自于Flutter的消息"+msg.msg!)
        let message:N2FMessage = N2FMessage.make(withMsg2: "iOS返回的消息")
        nativeMessage.nativeSendMsg(message, completion: {e in})
    }
    public var nativeMessage:NativeMessage!
    public static func register(with registrar: FlutterPluginRegistrar) {
        let messenger: FlutterBinaryMessenger = registrar.messenger()
        let api = SwiftFlutterPigeonPlugin.init()
        FlutterMessageSetup(messenger, api)
        api.nativeMessage = NativeMessage(binaryMessenger: messenger)
    }
}

编写example中的main.dart看一下效果

import 'package:flutter/material.dart';

import 'package:flutter_pigeon_plugin/flutter_pigeon_plugin.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late FlutterPigeonPlugin _flutterPigeonPlugin;


  @override
  void initState() {
    super.initState();
    _flutterPigeonPlugin = FlutterPigeonPlugin();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: TextButton(
              child: Text("点击这里向native发送消息"),
              onPressed: () {
                _flutterPigeonPlugin.sendMessage();
              }),
        ),
      ),
    );
  }
}

点击屏幕中的按钮,控制台打印返回消息

image.png

编写Android端代码

由于插件使用kt开发,故仅提供kt类型插件的相关说明,java可以参阅kt代码自行修改

run_pigeon.sh文件执行完成后,src/main/java/com/example/flutter_pigeon_plugin文件夹中已经自行生成大量代码。

直接开始编辑FlutterPigeonPlugin.kt

// src/main/kotlin/com/example/flutter_pigeon_plugin/FlutterPigeonPlugin.kt

package com.example.flutter_pigeon_plugin

import android.util.Log
import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin

/** FlutterPigeonPlugin */
class FlutterPigeonPlugin : FlutterPlugin, Message.FlutterMessage {
    lateinit var nativeMessage: Message.NativeMessage

    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        Message.FlutterMessage.setup(flutterPluginBinding.binaryMessenger, this)
        nativeMessage = Message.NativeMessage(flutterPluginBinding.binaryMessenger)
    }

    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {

    }

    override fun flutterSendMessage(msg: Message.F2NMessage) {
        Log.d("FlutterPigeonPlugin", msg.msg.toString())
        var respMsg: Message.N2FMessage = Message.N2FMessage()
        respMsg.msg2 = "Android的返回值"
        nativeMessage.nativeSendMessage(respMsg, {})

    }
}

点击屏幕中的按钮,控制台打印消息

image.png

GitHub源码
Gitee源码