Flutter与Android通信机制

1,343 阅读6分钟

概述

Flutter属于UI框架,当用户需要和手机进行平台级交互就需要和原生进行通信来使用相关功能。Flutter需要调用原生的功能时,开发者可以在Flutter插件库中寻找相应的插件,当插件不符合需求,开发者可以进行改装或自定义,Flutter与Android的通信机制必不可少。Flutter与Android通信方式分为MethodChannel、EventChannel、BasicMessageChannel,本文主要讲一下具体使用。

MethodChannel

  • Flutter 首先创建通信渠道并定义相关方法:
class FlutterPluginTest {
  static const MethodChannel _channel =
      const MethodChannel('flutter_plugin_method_channel');

  static Future<String> get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

首先在Flutter端创建FlutterPluginTest类专门用来处理渠道通信。 flutter_plugin_method_channel则是定义了通信渠道的名称,这是Flutter与Android通信的唯一识别符,如果两端名称不一样,则通信失败。getPlatformVersion则是定义了调用方法的名称,两端也要保持一致,否则当Flutter调用platformVersion方法时,Android端不知道要干什么,通过getPlatformVersion可以知道Flutter端想要获取Android的版本信息。Future,async,await,则说明这个方法是异步且返回值为String类型的,详细使用请自行查看。 其次在需要的地方进行调用:

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  @override
  void initState() {
    super.initState();
    initPlatformState();
  }
  Future<void> initPlatformState() async {
    String platformVersion;
    try {
      platformVersion = await FlutterPluginTest.platformVersion;
    } on PlatformException {
      platformVersion = '获取版本失败';
    }
    if (!mounted) return;
    setState(() {
      _platformVersion = platformVersion;
    });
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home:...
        body: Center(
          child: Text('安卓版本号: $_platformVersion\n'),
        ),
      ),
    );
  }
 }

当手机加载上述代码所在页面进行初始化的时候,Flutter在initState(初始化)中调用initPlatformState方法,通过FlutterPluginTest.platformVersion向Android发送消息说:我想要你的版本信息,可不可以。若Android回答:可以,则在body中进行显示具体版本信息,如果回答:不可以或其他错误,则显示获取版本失败。当然也可以使用点击事件获取相关信息,使用方式不限。

  • Android 首先定义插件,连接通信渠道:
public class FlutterPluginTestPlugin implements FlutterPlugin, MethodCallHandler {
  private MethodChannel channel;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_plugin_method_channel");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}

FlutterPluginTestPlugin必须实现MethodCallHandler接口,这样才能在onMethodCall方法中获取到Flutter端传过来的消息进行相关消息处理。实现FlutterPlugin接口就必须实现onAttachedToEngine和onDetachedFromEngine方法,这样是为了在使用的时候通过new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_plugin_method_channel")创建MethodChannel并通过channel.setMethodCallHandler(this)进行注册使用,在不需要时候通过channel.setMethodCallHandler(null)进行注销,节省资源,方便管理。当Flutter发送消息,Android通过flutter_plugin_method_channel进行匹配,如果符合就接通,否则就不理睬。当通信渠道匹配成功后,onMethodCall才会被成功调用。getPlatformVersion是Flutter要调用的的方法名,如果不一致就 result.notImplemented(),如果两端方法名匹配成功,Android则通过result.success("Android " + Build.VERSION.RELEASE)返回版本号。 因为代码中使用的Flutter版本为1.22.2,属于比较新的版本,Android端在插件的创建使用进行了优化和统一,没有了老版本中的registerWith,也没有了代码注册插件 GeneratedPluginRegistrant.registerWith(flutterEngine),很多工作都可以自动完成,也避免了插件使用方式五花八门,既减少了代码量也方便了管理。 至此MethodChannel的使用介绍完毕,相关效果如下图所示: MethodChannel

EventChannel

EventChannel使用和MethodChannel相似,本质上EventChannel是MethodChannel的一种,EventChannel是MethodChannel和Stream的结合体,通常用于原生(Android/Ios)向Flutter发送消息。

  • Flutter
    eventChannel = EventChannel("flutter_plugin_event_channel");
    eventChannel.receiveBroadcastStream().listen(onEvent,onDone: onDone,onError: onError);
    
  void onEvent(event) {
    _platformVersion = event;
    setState(() {

    });
  }

  onError(error) {
  }

  void onDone() {
  }

首先指定EventChannel名称为flutter_plugin_event_channel,同时创建EventChannel对象,然后对Android向Flutter传递的消息进行监听eventChannel.receiveBroadcastStream().listen(onEvent,onDone: onDone,onError: onError),其中onEvent中event就是消息通道传递的消息实体,onError和onDone则是对错误及消息通道关闭的监听处理,其他的部分的使用和MethodChannel相同。

  • Android 首先在onAttachedToEngine中申明并创建渠道:
  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(),"flutter_plugin_event_channel");
    eventChannel.setStreamHandler(this);
  }

同时实现EventChannel.StreamHandler,重写onListen和onCancel方法:

  @Override
  public void onListen(Object arguments, EventChannel.EventSink events) {
    eventSink = events;
    eventSink.success("Android " + Build.VERSION.RELEASE);
  }

  @Override
  public void onCancel(Object arguments) {
    eventSink = null;

  }

onListen方法通常用于消息的发送,如果是确认无误的可以调用eventSink.success(...),如果是错误的消息可以调用event.error(...)。当销毁消息渠道或发生不可预知的错误的时候可调用onCancel()。详细效果如下: EventChannel

BasicMessageChannel

BasicMessageChannel通常用于Flutter与原生(Android,Ios)之间的频繁通信,通信自由,两端都可以是消息发起者。

  • Flutter 首先创建消息渠道,指定消息编解码格式:
static const String _channel = 'flutter_plugin_basic_message_channel';
BasicMessageChannel<String> basicMessageChannel=
      BasicMessageChannel<String>(_channel, StringCodec())

_channel是BasicMessageChannel的名称,StringCodec()是指定消息的编解码格式为UTF-8。 然后监听从Android发送过来的消息:

    basicMessageChannel.setMessageHandler(_handlePlatformIncrement);

 	 Future<String> _handlePlatformIncrement(String message) async {
  		...
  		return _emptyMessage;
  	}
    

setMessageHandler即是获取消息,_handlePlatformIncrement则是处理消息。 同时Flutter还可以发送消息:

basicMessageChannel.send("");

send就是Flutter向Android发送消息,消息格式开发者自定义,不止String一种。

  • Android 和Flutter步骤一样,先定义创建BasicMessageChannel:
    private static final String CHANNEL = "flutter_plugin_basic_message_channel";
    private BasicMessageChannel<String> basicMessageChannel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        basicMessageChannel= new BasicMessageChannel<>(flutterEngine.getDartExecutor(), CHANNEL, StringCodec.INSTANCE);
        basicMessageChannel.
            setMessageHandler(new MessageHandler<String>() {
                @Override
                public void onMessage(String s, Reply<String> reply) {
                    onFlutterIncrement();
                    reply.reply(EMPTY_MESSAGE);
                }
            });

在onCreate方法中创建BasicMessageChannel对象,同时通过setMessageHandler接口实现监听消息,获取到消息后调用 onFlutterIncrement()处理消息。也可以通过reply.reply()回复消息,让Flutter知道Android收到消息了,类似于网络请求的三次握手机制。 既然是双向通信,能接收消息肯定需要发送消息:

  basicMessageChannel.send("");

至此BasicMessageChannel就算打通了,可以相互通信,具体效果如下:

basicMessageChannel 详细使用请参考Flutter中嵌套Android布局

总结

  • 上述三种通信方式都是可以双向通信(全双工通信),即Flutter可以向Android发送消息,Android也可以向Flutter发送消息。因为定位不同,一些性能被弱化。
  • 上述三种通信方式使用场景不仅限于创建的plugin中,还可以在Activity、Fragment等等中创建使用,使用场景取决于实际情况。
  • 上述三种通信方式都是异步的。
  • 上述三种通信方式同样适用于IOS。
  • MethodChannel侧重于响应式通信,即Flutter向Android发送消息,Android处理完任务后可以进行响应,也可以不响应,相当于一次性通信。当再次发送消息实际上就是重新创建了一次。通常用于拍照,录音等功能的调用。
  • EventChannel使用数据流的方式进行通信,可用于持续通信,收到消息后没有回复功能。通常用于Android向Flutter通信,比如获取电池电量,网络变化等各种状态实时变化的功能。
  • BasicMessageChannel属于双向自由通信,可以传递字符串和半结构化的信息,通常用于需要两端持续交互功能。

说明

  • 本文使用的Flutter版本为1.22.2,Dart版本为Dart 2.10.2。
  • 本文测试机型为HONOR 9X。
  • 若有侵权或错误,请发送邮件至alphabetadata@163.com