Flutter和原生之间的秘密

| 导语 所有的跨平台方案,不管是最早的WebApp和HybridApp,还是之前非常火热的RN和Weex,都面临着如何平衡跨平台性和效率这一问题。Flutter作为新一代的跨平台解决方案,传说中性能直逼原生,它为何如此优秀呢?让我们以Flutter的通信机制为起点,一起探索Flutter和原生之间的小秘密。注:由于作者不太熟悉iOS开发,所以本文大部分使用的都是Android视角。

一、跨平台机制大不同

跨平台解决方案由来已久,《聊聊移动端跨平台开发的各种技术》的作者将其大致分为了以下几种流派:

  • Web 流:也被称为 Hybrid 技术,它基于 Web 相关技术来实现界面及功能

  • 代码转换流:将某个语言转成 Objective-C、Java 或 C#,然后使用不同平台下的官方工具来开发

  • 编译流:将某个语言编译为二进制文件,生成动态库或打包成 apk/ipa/xap 文件

  • 虚拟机流:通过将某个语言的虚拟机移植到不同平台上来运行

以往最早的Hybrid开发,主要依赖于WebView。但是WebView是一个很重的控件,很容易产生内存问题,而且复杂的UI在WebView上显示的性能不好。react-native技术抛开了WebView,利用JavaScriptCore来做桥接,将js调用转为native调用,只牺牲了小部分性能获取的跨平台开发。

Flutter实现跨平台采用了更为彻底的方案。它既没有采用WebView也没有采用JavaScriptCore,而是自己实现了一台UI框架,然后直接系统更底层渲染系统上画UI。所以它采用的开发语言不是JS,而是Dart。Dart语言有着适合Flutter的良好的特性,详情可以看FAQ.为什么Flutter选择使用Dart语言?

二、Flutter和native的通信方式

Flutter和native间的通信,应该分为 Flutter主动发送 和 native主动发送 两种情况,而Flutter的官方文档却仅仅介绍了Flutter主动发送的方式。对于 native主动发送的方式提供了一个plugin作为例子。具体的使用方式可以点开官网链接查看,在这就不再赘述了,主要是探寻一下两边的代码到底是怎么相互调用的。

  1. MethodChannel:

Flutter之间的消息传递,是通过 MethodChannel 来完成。我们先看它的构造函数。可以发现,需要一个 name和一个可选的 MethodCodec。 name是这个 MethodChannel的标识,在后面会用到。 MethodCodec是个编/解码器,其决定了我们能传递什么类型的数据。 StandarMethodCodec有如下规则:

Dart名(rtx)AndroidiOS
nullnullnil (NSNull when nested)
booljava.lang.BooleanNSNumber numberWithBool:
intjava.lang.IntegerNSNumber
intif 32 bits not enoughjava.lang.Long
intif 64 bits not enoughjava.math.BigInteger
doublejava.lang.DoubleNSNumber numberWithDouble:
Stringjava.lang.StringNSString
Uint8Listbyte[]FlutterStandardTypedData
Int32Listint[]FlutterStandardTypedData
Int64Listlong[]FlutterStandardTypedData
Float64Listdouble[]FlutterStandardTypedData
Listjava.util.ArrayListNSArray
Mapjava.util.HashMapNSDictionary
  1. invokeMethod()

查看invokeMethod()方法, method为 MethodCall的标识, arguments则自然是参数了,值得注意的是这里的参数必须要遵守上面的规则(默认情况下不能直接传自定义类,但是我们可以将其转为Json之后再传递,也可以去改造 MethodCode,以此进行复杂数据结构的传递)。 注:可以看到,其是一个 async标记的方法,返回值为Future。那么我们在接受这个方法的返回值的时候,就必须要使用 await进行修饰。要调用使用 await,必须在有 async标记的函数中运行。具体调用和使用的方式可以看官网的例子。在这我们先继续深入。

  1. BinaryMessages.send()

查看send()方法可以发现一个很有意思的事情,如果 _mockHandlers取出来的值不为空的话,则message会直接被对应handler处理,不会再发送。查看 setMockMessageHandler()的注释,官方的解释是,该方法会将Message拦截,可以用于测试。

  1. _sendPlatformMessage()——window.sendPlatformMessage()

这里调用了一个native方法,那么我们就需要去找这个native方法。

  1. native 遇到native方法,先去engine中找同名的文件试试看,果然在window.cc中,找到了这个方法。然后可以找到对应的native方法。

这段代码比较长,我们一点点来看。 首先看64行,可以获取到一个有用信息,这个套机制仅能在主线程(isolate)上运行。 然后看最关键的方法: dart_state->window()->client()->HandlePlatformMessage()

顺着找下去,可以在 WindowClient中找到 HandlePlatformMessage(),但是可以发现,这是一个纯虚函数。这里使用了一个比较取巧的方式去找,直接去找都有哪个类继承了 WindowClient,可以发现只有 RuntimeController是继承了这个类的,去看看这个方法的实现。

那么这个client是什么呢?是一个 RuntimeDelegate …………………… 跳啊跳啊,终于在 PlatformViewAndroid 找到了实现(当然对应的iOS的也有一个,这里因为我比较熟悉Android,就只把Android的拿出来看),中间的过程没什么营养就不进行详述了。

OK,经历了重重关卡,终于找到了jni的方法。那么也就是说,只要找到 g_handle_platform_message_method 所指向的方法,就能走入Android的世界了。(可以提前关注一下 pending_responses_,这个变量在后面会提到)

用简单暴力点的方法,直接去找赋值语句,发现只有一处,那么不用想,肯定是它了。

然后再找这个类名,就可以在Flutter的Android工程中找到这个方法了。

  1. Android

终于回到了JAVA的世界,还是比较感动的。其实这段代码核心就在 onMessage()直接看一看这个方法的实现。

果然是一个抽象函数,而且有三个实现。那么我们就不能乱猜了,再回头看一下 handler这变量到底是个什么类型。从133行可以看到 handler 是以channel的name为key从一个map( mMessageHandlers)中取出来的,那这个值是在哪被设置的呢?线索仿佛到这就断掉了。别急,我们先来回忆一下,使用 MethodChannel的步骤。(下图为中文官网教程截图)

好了重点我已经圈出来了,跳进去看看就明白了。

那就确定了 handler是 IncomingMethodCallHandler的对象。直接去看它的 onMessage方法。

终于,我们看到了熟悉的 onMethodCall方法。

  1. 消息回复 方法是调用了,那下一步就该考虑数据怎么传回去了。还记得第6点一开始有个回调函数吗?上面的几个reply调用的就是这个回调函数。

再看看这个回调函数,分别是调用了两个native层的函数。empty的那个就不用看了,知道非empty的怎么传自然也就知道它怎么传了。在 platform_view_android_jni.cc中,我们可以找到对应的函数。

message_response看起来就像是一个回调函数。它是从 pending_responses_中取出来的。还记得第4点中有一个回调函数吗?它在 native层中被封装,并置入了 pending_responses_中(具体可以仔细看第5点的过程,中间有提到,在这就不重复贴图了),那么这里的 message_response经过一些处理之后,最终还是会回到那个回调函数,这里的过程就不详述了。

  1. 总结 好了,至此一个闭环也就形成了。可以看到,整体的通讯流程是一个V形。


《IVWEB 技术周刊》 震撼上线了,关注公众号:IVWEB社区,每周定时推送优质文章。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Flutter是一种跨平台的移动应用开发框架,可以同时在iOS和Android上运行。Flutter使用Dart语言编写,具有热重载功能,可以快速开发高性能、美观的应用程序。FlutterUI是自己绘制的,不依赖于操作系统的原生控件,因此可以实现高度自定义的UI效果。 Android原生开发是指使用Java或Kotlin编写Android应用程序,使用Android SDK提供的原生控件和API。原生应用程序可以充分利用Android操作系统的功能和性能,但需要针对不同的设备和版本进行适配。 总的来说,Flutter和Android原生开发的区别在于开发语言、UI实现方式和跨平台能力。Flutter使用Dart语言,UI自绘,可以跨平台运行;而Android原生开发使用Java或Kotlin语言,依赖于操作系统的原生控件和API,只能在Android上运行。 ### 回答2: Flutter是一个开源的移动应用开发框架,而Android原生是指使用Java或Kotlin等本地语言编写的应用程序。下面是Flutter和Android原生之间的主要区别: 1. 学习曲线:Flutter使用Dart语言开发,如果你已经熟悉了JavaScript或Java等其他语言,学习Flutter也许会花费你一些时间。但是Flutter的开发文档与工具是易于理解和使用的,所以Flutter的学习曲线相对于Android原生会更加平缓。 2. 性能:Flutter使用自己的渲染引擎来绘制用户界面,其称为“Skia”。与Android原生相比,FlutterUI性能上可能会有一些优势。Flutter采用了一些复杂的技术来在运行时优化代码,并且可以使用Google的Dart编译器来生成高效的原生代码。 3. 开发效率:Flutter的开发速度相对于Android原生也许更快。由于Flutter的热重载功能,您可以更快地查看您所做的更改,并在不刷新应用程序的情况下保存这些更改。此外,Flutter具有很好的跨平台开发支持,您可以在同一代码库中以相同的方式开发iOS和Android应用。 4. 生态系统:Flutter生态系统中的插件和库数量与Android原生相比仍然不足。但是,越来越多的开发人员和组织机构开发了各种各样的插件和库来帮助Flutter开发人员快速开发应用。 5. 设计自由度:Flutter相对于Android原生提供了更多灵活的设计自由度。Flutter应用程序可以组合使用各种小部件和布局,以创建非常独特的用户界面和动画效果。 综上所述,Flutter和Android原生的区别在于性能、学习曲线、开发效率、生态系统和设计自由度等方面。选择一种适合自己的框架取决于您的具体需求和项目要求,需要根据实际情况进行权衡。 ### 回答3: Flutter(也称为Flutter UI框架)是一个跨平台的移动应用程序开发框架,由谷歌(Google)开发。 它允许开发人员以一种统一的语言(Dart)构建高性能,高保真度的移动应用程序,可在Android和iOS等平台上运行。Flutter基于自己的渲染引擎和框架建立,其中包括许多构建UI的内置组件。Flutter具有以下区别和优势: 1.基于Dart语言:与Java和Kotlin不同,Dart是一种强类型静态语言,也支持动态语言特性。Flutter的完整生态系统都是Dart编写,因此开发人员可以在编写Flutter代码时使用所有Dart的语言特性。 2.完全自定义UIFlutter的Widget框架提供了大量的预置组件,可以自定义和扩展,使得开发人员可以自由地构建独特的,自定义的UI。 3.高性能:Flutter 框架可以通过达到每秒60帧(FPS)的性能来实现对动画和过渡的支持,这是传统的基于WebView的Hybrid移动应用程序难以匹敌的。 4.快速迭代和快速开发:由于Flutter使用Hot reloading可以快速加载并重新加载UI,因此可以大大减少调试时间和部署时间。 5.跨平台开发:Flutter 允许开发人员在所有平台上构建相同的应用程序,包括Android和iOS,从而实现在延长开发周期的同时实现保证强一致性的开发。 与Flutter相比,Android原生的开发主要集中在Java和Kotlin之上,以使用Android SDK为框架,以构建在Android上原生应用程序。而Android原生的应用程序开发具有以下优势和限制: 1.更快的性能:Android原生应用程序始终是高性能的,因为它们直接在设备上运行而不需要中间层。 2.外观和风格与设备一致:为了确保Android应用程序看起来和操作体验与设备相同,Android原生开发支持通过设置特定的样式,颜色和控件来实现此目的。 3.专业开发支持:Android原生应用程序开发具有良好的集成开发环境,具有权限系统,可提供良好的面向开发人员的支持。 4.固定生态系统:Android原生应用程序必须在特定版本的Android API上运行,这意味着必须使用不同的软件包,类和框架,这可能会引起问题。 总之,Flutter和Android原生应用程序开发是为相同平台开发应用程序的两种不同方法。Flutter提供了快速迭代和跨平台开发的优势,而Android原生应用程序则提供了更快的性能可靠性和与设备外观和风格的一致性优势。根据不同的需求,开发人员可以选择使用适合他们需求的一种或同时使用这两种方式来开发移动应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值