Android 项目嵌入Flutter Module(三) 交互

1,448 阅读2分钟

前言

上篇文章说到了android 嵌入flutter后,通过自定义Activity去继承FlutterActivity,然后重写部分方法去打开一个FlutterActivity去达到我们想要的效果。这篇文章我们讲一下两者如何交互,并且同样适用于纯Flutter项目中,Flutter 和原生交互

Android 项目嵌入Flutter Module(二)

主要是需要通过 PlantformChannel 进行交互,PlantformChannel 有三种类型,BasicMessageChannel,EventChannel,MethodChannel。具体可以看这篇文章深入理解Flutter Platform Channel

正文

BasicMessageChannel,主要用于双向传递字符串和半结构化消息传递消息

class BasicTestChannel(dartExecutor: DartExecutor) : MessageHandler<String> {
    private val tag: String = "BasicTestChannel"
    private val basicMessageChannel =
        BasicMessageChannel(dartExecutor, "com.zww/basic", StringCodec.INSTANCE)

    fun send(content: String, callback: Reply<String>) {
        basicMessageChannel.send(content, callback)
        Log.d(tag, "android发送flutter内容为: $content")
    }

    init {
        basicMessageChannel.setMessageHandler(this)
    }

    override fun onMessage(message: String?, reply: Reply<String>) {
        Log.d(tag, "android收到flutter的消息: $message")
        reply.reply("android收到flutter的消息,内容为$message")
    }

    fun removeMessageHandler() {
        basicMessageChannel.setMessageHandler(null)
    }
}

onMessage是收到Flutter发送的消息的回调,然后调用reply方法可以回复 send方法是发送消息到Flutter,第二个参数是Flutter收到消息回复的回调

使用

class MyFlutterActivity : FlutterActivity() {
    private lateinit var basicTestChannel: BasicTestChannel
    override fun provideFlutterEngine(context: Context): FlutterEngine? {
        val flutterEngine = FlutterEngine(this, null, false);
        basicTestChannel = BasicTestChannel(flutterEngine.dartExecutor)
        return flutterEngine
    }

    override fun onStart() {
        super.onStart()
        basicTestChannel.send("Android To Flutter", callback = BasicMessageChannel.Reply {
            Log.d("basicTestChannel", "android 发送给Flutter的消息收到回复了,回复内容为:$it")
        })
    }

    override fun shouldDestroyEngineWithHost(): Boolean {
        return true
    }

    override fun onDestroy() {
        basicTestChannel.removeMessageHandler()
        super.onDestroy()
    }

    override fun onFlutterUiDisplayed() {
        super.onFlutterUiDisplayed()
        Toast.makeText(this, "onFlutterUiDisplayed", Toast.LENGTH_LONG).show()
    }
}

** Flutter **

  static const basicChannel =
      const BasicMessageChannel("com.zww/basic", StringCodec());
 
  @override
  void initState() {
    basicChannel.setMessageHandler((message) => _handlePlatform(message));
    super.initState();
  }

  Future<String> _handlePlatform(String message) async {
    print("收到Native消息:$message");
    setState(() {
      _counter++;
    });
    Future.delayed(const Duration(seconds: 3), () async {
      String result =
          await basicChannel.send("Flutter 发送Android内容为:Flutter To Android");
      print("Flutter 发送Android消息收到回复了,回复内容为: $result");
    });
    return "收到Native消息:$message";
  }

setMessageHandler这个异步监听就是Android发给Flutter的监听,返回值就是收到消息的回复的内容 send方法也是异步的,返回值就是Android收到消息的回复,即android里的reply返回的内容

** 流程 **

android 发送消息到Flutter,Flutter接收并返回收到消息的回复。三秒后,Flutter主动向android发送一条消息,android接收到并返回收到消息的回复。log如下

D/BasicTestChannel: android发送flutter内容为: Android To Flutter

I/flutter: 收到Native消息:Android To Flutter

D/basicTestChannel: android 发送给Flutter的消息收到回复了,回复内容为:收到Native消息:Android To Flutter

D/BasicTestChannel: android收到flutter的消息: Flutter 发送Android内容为:Flutter To Android

I/flutter: Flutter 发送Android消息收到回复了,回复内容为: android收到flutter的消息,内容为Flutter 发送Android内容为:Flutter To Android

这个混合场景举例:

android 列表页 启动Flutter的时候,传递一个itemId,并指定路由为列表详情界面,然后界面接收到这个Id去请求详情数据并加载

EventChannel

** 用于传递事件流。**

class EventTestChannel(dartExecutor: DartExecutor) : EventChannel.StreamHandler {
    private var eventChannel: EventChannel = EventChannel(dartExecutor, "com.zww/event")

    init {
        eventChannel.setStreamHandler(this)
    }

    override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
        events?.success("1")
        events?.success("2")
        events?.success("3")
        events?.success("4")
        events?.error("1001", "This is error", "This is details")
        events?.endOfStream()
        events?.success("5")
    }

    override fun onCancel(arguments: Any?) {
    }

    fun removeStreamHandler() {
        eventChannel.setStreamHandler(null)
    }
}

class MyFlutterActivity : FlutterActivity() {
    private lateinit var eventTestChannel: EventTestChannel
    override fun provideFlutterEngine(context: Context): FlutterEngine? {
        val flutterEngine = FlutterEngine(this, null, false);
        eventTestChannel = EventTestChannel(flutterEngine.dartExecutor)
        return flutterEngine
    }


    override fun shouldDestroyEngineWithHost(): Boolean {
        return true
    }

    override fun onDestroy() {
        eventTestChannel.removeStreamHandler()
        super.onDestroy()
    }

    override fun onFlutterUiDisplayed() {
        super.onFlutterUiDisplayed()
        Toast.makeText(this, "onFlutterUiDisplayed", Toast.LENGTH_LONG).show()
    }
}

**Flutter **

 static const eventChannel = const EventChannel("com.zww/event");

  @override
  void initState() {
    super.initState();
    basicChannel.setMessageHandler((message) => _handlePlatform(message));
    eventChannel.receiveBroadcastStream().listen(
      (event) {
        print("event 收到值为 $event");
      },
      onError: (Object error, StackTrace stackTrace) =>
          print("onError: $error $stackTrace"),
      onDone: () => print("onDone"),
    );
  }

** Log**

I/flutter: event 收到值为 1
I/flutter: event 收到值为 2
    event 收到值为 3
    event 收到值为 4
I/flutter: onError: PlatformException(1001, This is error, This is details) 
I/flutter: onDone

MethodChannel

** 用于传递方法调用,是比较常用的 PlatformChannel**

这里就看下Flutter如何调用Android方法,以Toast为例

class ToastChannel(context: Context, dartExecutor: DartExecutor) : MethodChannel.MethodCallHandler {
    private val mContext: Context = context
    private val methodChannel: MethodChannel = MethodChannel(dartExecutor, "com.zww/toast")

    init {
        methodChannel.setMethodCallHandler(this)
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        when (call.method) {
            "show" -> {
                val content: String? = call.argument("content")
                Toast.makeText(mContext, content, Toast.LENGTH_SHORT)
                    .show()
                result.success(null)
            }
        }
    }

    fun removeMethodCallHandler() {
        methodChannel.setMethodCallHandler(null)
    }
}

class MyFlutterActivity : FlutterActivity() {
    private lateinit var toastChannel: ToastChannel
    override fun provideFlutterEngine(context: Context): FlutterEngine? {
        val flutterEngine = FlutterEngine(this, null, false)
        // 直接实例化一个新的MethodChannel
        toastChannel = ToastChannel(this.context, flutterEngine.dartExecutor)
        return flutterEngine
    }

    override fun shouldDestroyEngineWithHost(): Boolean {
        return true
    }

    override fun onFlutterUiDisplayed() {
        super.onFlutterUiDisplayed()
        Toast.makeText(this, "onFlutterUiDisplayed", Toast.LENGTH_LONG).show()
    }

    override fun onDestroy() {
        toastChannel.removeMethodCallHandler()
        super.onDestroy()
    }
}

** flutter **

 static const toastChannel = const MethodChannel("com.zww/toast");
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });

    toastChannel.invokeMethod(
        "show", {"content": "Flutter Module Call  ToastPlugin's show method"});
  }

总结

这篇文章我们能学到

  • android 和Flutter是如何交互的
  • 文头推荐的文章建议大家一定要去看