Flutter如何调用原生代码
我们要做的是在Flutter上实现实时音视频。那么在开始具体的工作之前,首先需要了解Flutter是如何调用诸如“获取媒体设备”这类原生平台API的。

上方来自官方的架构图已经足够清晰了,Flutter通过MethodChannel发起某一方法的调用,然后原生平台收到消息后执行相应的实现(Java/Kotlin/Swift/Object-C)并异步地返回结果,以getUserMedia为示例,首先在Flutter层中声明这一方法,具体实现则是通过MethodChannel发送一条携带调用方法名和相应参数的信息。

Future表示一个异步的调用,类似Javascript的Promise;async/await类似,在一个async函数中,会类似同步地按顺序去执行await方法,尽管await后面的是异步方法。
当平台在MainActivity中同样注册MethodChannel,通过MethodChannel收到方法调用的消息和参数后,基于本平台实现相应逻辑,并返回执行结果,此处仅以Android平台为例:


更多详细的信息可以参考Flutter官方示例与解释:
https://flutter.io/docs/development/platform-integration/platform-channels
实现音视频SDK的思路
了解上述Flutter调用原生平台方法的原理后,我们就有两种思路来实现一个音视频SDK。
1.先在原生平台实现音视频SDK,后Flutter通过MethodChannel直接调用SDK提供的方法。
具体的方案为直接通过MethodChannel调用已有的声网AgoraSDK,并在Flutter层抹去可能存在的差异,诸如参数不同、部分方法名不同。
这种做法的主要优点在于可以最大程度复用已有的SDK,类似于建立了一层桥接。
2.先基于原生平台实现WebRTC标准,然后在Flutter层通过MethodChannel调用WebRTC接口,再实现音视频SDK逻辑。
这种方案先利用原生平台实现WebRTC标准(前一节实现的getUserMedia就是此标准的一部分),然后在Flutter层注册为WebRTCPlugin。在这个FlutterWebRTCPlugin的基础上参照声网音视频SDK,连接到AgoraSD-RTN?全球虚拟通讯网络。
这种方案相比前一点,相当于实现一个全新的Dart语言的SDK,需要用到更多Dart的标准库(诸如math、io、convert之类)与第三方生态(如(flutter_webrtc)。假设要支持更多的平台时(比如Windows),只需要该平台实现WebRTC标准就可以直接使用。
熟悉WebRTC的同学们可能知道在实现浏览器WebRTC应用的时候有一个Adapter的概念,目的就是为了掩藏几大主流浏览器WebRTC接口的些许差异,和本方案的思路是类似的,只不过适配的平台从Firefox/Chrome/Safari变为了Windows/iOS/Android等。
最终出于调研的目的,同时也是为了更加迎合Flutter一套代码,多平台通用的思想(理论上SDK就是一层设计完备的客户端逻辑,在WebRTC受良好支持的情况下,工作的内容就变为:如何使用Dart语言在WebRTC的标准上实现音视频通信逻辑),我们选择采用这个方案,因此读者可能会发现这个FlutterSDK整体上不少概念上更接近于声网Web平台的音视频SDK一些。
3.SDK的结构

SDK的主要功能大致包含了音视频采集与播放,与AgoraGateway建立P2P连接并管理,以及与Gateway之间的消息交换和处理。
虽然Flutter社区相对较新,但是Dart的标准库可以算得上是非常完备了,同时也已经有不少优秀的第三方Plugin。
代码可以主要拆分为以下模块:
基于dart:io中Websocket相关的方法实现与Gateway之间的消息通信(比如publish/subscribe这类消息和回复)
基于开源社区的flutter_webrtc项目实现音视频采集以及p2p连接等WebRTC相关功能
基于dartStream对象或是简单的Map来实现EventEmitter这些SDK所需的辅助类(当然也可以直接采用Dart的Stream/Sink概念进行替代)。
这些模块完成后,在此之上就可以实现类似声网WebSDK中的Client与Stream对象。
其中值得一说的是视频流的播放,可以借助flutter_webrtcplugin中的RTCVideoView对象来实现,想要深入了解具体原理的可以学习一下Flutter外接纹理(Texture)相关概念。
到此SDK就已经基本形成了,之后便是UI层的开发,Flutter这一部分很大程度上受到了React框架的启发,熟悉该框架的Web开发者可以基于此SDK轻松的实现一个可运行在Android/iOS平台的视频通话App。我们此前分享过的demo已经成功和已有的声网Android/iOS/WebSDK进行互通,相应的代码也许将在不久未来进行开源。
4.总结
尽管Flutter社区仍然很年轻,但是已经逐渐有不少优秀的第三方插件涌现出来,加上Dart相对全面的标准库,实现这样一个音视频SDK或是类似的功能并不需要自己大量地去造轮子,加上Flutter本身环境搭建/构建/调试都非常的方便,因此整个开发过程中几乎没有遇到什么坑。
此外在应用层的开发过程中,风格非常接近于使用React进行Web开发,加上Flutter亚秒级的HotReload等特性,在开发体验与效率上相比原生开发确实有着不小的优势。
再考虑到逐渐完善的跨平台特性(桌面端的flutter-desktop-embedding项目与浏览器端的hummingbird项目)以及可能会到来的谷歌新操作系统Fuchsia,对于无论是想要接触到原生开发的Web开发者,还是追求更高的开发效率和更好的开发体验的原生开发者来说,Flutter都是一个非常适宜的切入角度,值得在新的一年里加入自己的技术栈中。