Flutter与原生通信pigeon的使用

2,512 阅读4分钟

前言

pigeon是谷歌官方的一个为了方便开发者在Flutter与原生通信时需要维护大量的成员变量出的一个基于dart代码自动生成三端代码的插件,可以极大的提高原生混合开发时通信的开发效率,如果使用MethodChannelEventChannel等,需要维护三端的变量,方法名等,通信数据多的话,会对维护造成很大的压力,但是用了pigeon这个插件,就不需要维护这些变量了,全部自动生成,并且所有的数据都是以对象的形式传递,非常的面向对象。接下来就让我看下如何使用这个插件。

当然如果你想开发一个packages插件,用这个也是非常方便的。

引入插件:

dev_dependencies:下引入 pigeon: ^3.0.3。目前最新版本。
这里以最新版本为例:

dev_dependencies:
  flutter_test:
    sdk: flutter
  pigeon: ^3.0.3 #生成跨端协议文件用于跨端通信

创建传输数据实体类

需要实现的功能:
1、原生(Android和iOS)调用Flutter
2、Flutter调用原生(Android和iOS)
3、可携带自定义参数、可返回自定义结果、可异步返回。

Android实现步骤:

1、新建一个pigeons文件夹与lib同级目录存储生成的类

image.png
我这里分别创建input和output两个文件夹,input是我们编写的目录,output是自动生成的目录。

2、创建.sh脚本用来执行插件

flutter pub run pigeon \
  --input pigeons/input/pigeon_input.dart \
  --dart_out pigeons/output/pigeon_out.dart \
  --objc_header_out pigeons/output/iOSPigeon.h \
  --objc_source_out pigeons/output/iOSPigeon.m \
  --java_out pigeons/output/AndroidPigeon.java \
  --objc_prefix FLT \
  --java_package "com.instrument.plugins"

上面脚本内容分别代表执行的dart文件和分别输出的4个文件的目录地址和Android的包名。 生成之后将这四个文件分别粘贴到我们对应的项目中即可。

注:这里的文件名只是说明,在粘贴的时候我们需要进行重新命名,增强代码的可读性。

3、创建pigeon需要的基于dart的实现类pigeon_input

import 'package:pigeon/pigeon.dart';

/// 原生数据
class NativeBean {
  final int id;
  final String name;
  NativeBean(this.id, this.name);
}
/// Flutter数据
class FlutterBean {
  final int fId;
  final String fName;
  FlutterBean(this.fId, this.fName);
}

/// 重点关心这两个抽象类
@HostApi()// Flutter调用原生的方法写在下面  原生去实现
abstract class FlutterToNative {

  // 通过id从原生获取信息
  NativeBean loadNativeInfo(int id);

}
@FlutterApi()// 原生调用Flutter的方法 Flutter去实现
abstract class NativeToFlutter {

  FlutterBean getFlutterInfo(int id);
}

这个类是我们编写的类,重点就是下方的两个注解的抽象类,需要我们定义通信方法。
创建完毕之后,执行.sh文件脚本即可生成上面4个文件。

4、Android实现Flutter调原生

将上面生成的java文件粘贴到Android原生项目中,重新命名TestPluginPigeon。并创建对应的实现类。

image.png
TestPlugin代码

import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;

public class TestPlugin implements FlutterPlugin,TestPluginPigeon.FlutterToNative {
    /// 绑定
    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
        ///注册
        TestPluginPigeon.FlutterToNative.setup(binding.getBinaryMessenger(),this);
    }
    /// 解绑
    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {

    }
    @NonNull
    @Override
    public TestPluginPigeon.NativeBean loadNativeInfo(@NonNull Long id) {
        // 原生实现这个方法 
            TestPluginPigeon.NativeBean nativeBean = new TestPluginPigeon.NativeBean();
        nativeBean.setId(0L);
        nativeBean.setName("");
        return nativeBean;
    }
}

将TestPlugin注册到FLutter引擎中,这里我使用了flutter_boost进行注册。(flutter引擎注册插件)

image.png

在Flutter中调用原生方法,将生成的pigeon_out拷贝到lib目录下,

image.png

在需要的地方直接调用,

FlutterToNative().loadNativeInfo(id).then((value) {
});

至此,FLutter调用原生Android完毕。

5、Android实现原生调Flutter
流程差不多,只不过反过来了,
首先在Flutter进行注册绑定,上面的test_plugin就是我们需要实现的原生调用Flutter的方法。

/// 这里实现原生调用的方法
class TestPlugin implements NativeToFlutter {
  @override
  FlutterBean getFlutterInfo(int id) {
    
    return  FlutterBean(fId: 0, fName: '');
    
  }
}

在初始化Flutter模块时注册TestPlugin,

NativeToFlutter.setup(TestPlugin());

原生调用这个方法:
首先我们在绑定的时候获取实体类,

public static TestPluginPigeon.NativeToFlutter nativeToFlutter;
/// 绑定
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
    ///注册
    TestPluginPigeon.FlutterToNative.setup(binding.getBinaryMessenger(),this);
  nativeToFlutter = new TestPluginPigeon.NativeToFlutter(binding.getBinaryMessenger());
}

在需要的地方调用,

TestPlugin.nativeToFlutter.getFlutterInfo(id, flutterBean -> {
    /// 调用Flutter方法 获取返回值
    
});

自此,Android调用Flutter结束。

上面的通信都是同步的,如果需要异步在方法体上注解@aysnc,用法大同小异,只是返回结果是异步返回。

@async
FlutterBean getFlutterInfo(int id);

iOS待补充

小结

通过查看生成的代码我们可以知道pigeon生成的代码可以发现是基于BasicMessageChannel实现的,我们只需要关心传输的具体数据,生成接口,实现接口即可,不需要关心维护具体的变量方法名等,对后续的维护成本有了极大的降低。

插件地址:pub.flutter-io.cn/packages/pi…