flutter 与native通信初探

2,683 阅读3分钟

flutter 从入门到放弃

背景

从搭建环境到项目开发,入坑flutter已经快一周了,不得不说,从android原生开发者角度来说,相对于其他的跨平台方案,不管是性能,UI渲染还是学习成本,flutter还是相对比较友好的,内部维护几套UI逻辑,skia引擎渲染,而不依赖于原生控件的局限性,Hotload开发快捷等等,但我们要明白一点,flutter始终是一个跨平台的UI方案,最终还是要根据平台生成.apk(android)/.ipa(ios)包的,所以在涉及到一些系统平台的接口或者数据,比如系统电量什么的,还是需要native层去搞定的,再将数据返回给flutter层去展示,所以难免就会出现flutter与native的通信问题,那么Flutter是如何做到的呢?答案是Platform Channels

Platform Channels

1975877-6079b324ae9d7bf7

上图来自Flutter官网,表明了Platform Channels的架构示意图。有细心的同学就要问了,你不是说Flutter和Native通信是通过Platform Channels吗?怎么架构图里面连接他们的是MethodChannel? 其实呢,MethodChannel是Platform Channels中的一种,顾名思义,MethodChannel用起来应该和方法调用差不多。那么还有别的channel?有的,还有EventChannel,BasicMessageChannel等。如果你需要把数据从Native平台发送给Flutter,推荐你使用EventChannel。Flutter framework也是在用这些通道和Native通信

例子1:flutter调用android logcat

虽然flutter本身提供了2种日志输出方式,print(),debugprint(),但是对于android开发者来说还是不太习惯,而且信息冗余在console栏里面,没法过滤等等,所以可以通过这个Channels去调用android原生的logcat

Flutter端
import 'package:flutter/services.dart';

class LogUtils {
  static const perform = const MethodChannel("android_log");

  static void v(String tag, String message) {
    perform.invokeMethod('logV', {'tag': tag, 'msg': message});
  }

  static void d(String tag, String message) {
    perform.invokeMethod('logD', {'tag': tag, 'msg': message});
  }

  static void i(String tag, String message) {
    perform.invokeMethod('logI', {'tag': tag, 'msg': message});
  }

  static void w(String tag, String message) {
    perform.invokeMethod('logW', {'tag': tag, 'msg': message});
  }

  static void e(String tag, String message) {
    perform.invokeMethod('logE', {'tag': tag, 'msg': message});
  }
}

可以看到,代码很简单,初始化一个MethodChannel对象,然后去调用invokeMethod方法,传入参数即可

android端
public class MainActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
        new MethodChannel(getFlutterView(),CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
                String tag = methodCall.argument("tag");
                String msg = methodCall.argument("msg");
                switch (methodCall.method) {
                    case "logV":
                        Log.v(tag,msg);
                        break;
                    case "logD":
                        Log.d(tag,msg);
                        break;
                    case "logI":
                        Log.i(tag,msg);
                        break;
                    case "logW":
                        Log.w(tag,msg);
                        break;
                    case "logE":
                        Log.e(tag,msg);
                        break;
                    default:
                        Log.d(tag,msg);
                        break;
                }
            }
        });
}

这里也是创建一个MethodCallHandler对象,在回调中收到MethodCall对象,取出对应的method和arguments,这里判断method来调用android本身的log方法即可。

例子2:android推送消息到flutter

因为现在其实大部分都是flutter和native原生开发,所以有很多flutter需要主动去推送消息给native层,native层就可以创建EventChannel来监听与flutter的状态,再通过EventSink对象回复消息obj

android端
new EventChannel(getFlutterView(), "com.flutter/notify").setStreamHandler(
                new EventChannel.StreamHandler() {
                    private TokenReceiver tokenReceiver;
                    @Override
                    public void onListen(Object args, final EventChannel.EventSink events) {
                        Log.e("tag", "adding listener");
                        events.success("data callback");
                    }

                    @Override
                    public void onCancel(Object args) {
                        Log.e("tag", "cancelling listener");
                    }
                }
        );
flutter
static const EventChannel eventChannel = EventChannel('com.flutter/notify');
@override
  void initState() {
    // TODO: implement initState
    super.initState();
    //初始化监听
   eventChannel.receiveBroadcastStream().listen(_onDataBack, onError: _onError);
  }
void _onError(Object error){

  }
void _onDataBack(String callback) {
   print(callback)
  }

代码也很简单,创建相同Channel名字的EventChannel,监听到数据做相应的逻辑即可