8天让iOS开发者上手Flutter之八
介绍四种Flutter Project
先介绍一下这四个的差别和使用的场景。
Flutter App
如果是想要使用flutter开发一个新的项目,那么就选择Flutter App。就像我们之前的wechat_demo
Flutter Module
但是很多时候我们目前手上的原生APP可能会很庞大,不是随便就可以重新使用flutter重新再写一遍的。但是又想在现有的APP中体验一下flutter,那么就选择Flutter Module
Flutter Package
Flutter 支持使用其他开发者向 Flutter 和 Dart 生态系统贡献的共享 package(类似于iOS中的第三方库吧,AFNetworking,YYKit等等...),这意味着你可以快速构建应用而不是一切从零开始。
Package最低要求是包含一个 pubspec.yaml
文件。此外,一个 package 可以包含依赖关系 (在 pubspec.yaml
文件里声明)、 Dart 库、应用、资源、测试、图片和例子等。 pub.dev 上列出了很多 package,由 Google 工程师和 Flutter 和 Dart 社区的开发者开发和发布,你可以用在自己的应用里。
Flutter Plugin
插件 (plugin) 是 package 的一种,全称是 plugin package,我们简称为 plugin,中文叫插件。插件 (plugin package) 是一种特别的 package,特别指那些帮助你获得原生平台特性的 package。插件可以为 Android (使用 Kotlin 或 Java 语言)、 iOS (使用 Swift 或 Objective-C 语言)、Web、macOS、Windows、Linux 平台,或其任意组合的平台编写。比如:某个插件可以为 Flutter 应用提供使用原生平台的摄像头的功能。
使用Flutter Module进行混合开发
我们前七天开发的项目就是Flutter App,今天主要介绍如何使用Flutter Module进行混合开发。混合开发官方推荐只使用单个Flutter页面,多个Flutter页面也能支持,但有可能会出现稳定性、性能问题以及 API 仍然可能变动的问题。请大家谨慎使用。官方介绍链接
iOS原生项目中导入Flutter
准备一个原生iOS项目
进行混合开发就一定需要一个原生项目,根据你的需求,可以使用目前手上的APP,也可以临时创建一个Demo来先练练手。我们这里就临时新建一个iOS原生Demo。
这个原生项目很简单,就这么两行代码。
新建Flutter Module项目
新建一个Flutter Module项目,项目名就叫module。
最好将两个项目放在同级目录下,因为原生项目需要知道Flutter Module项目的位置。
使用cocoapods建立关联
在原生项目Demo里建立Podfile文件,然后编辑Podfile。
flutter_application_path = 'Podfile相对flutter module的路径'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
在每个需要集成flutter module的target添加如下代码
target '你的APP' do
install_all_flutter_pods(flutter_application_path)
end
编辑完之后的Podfile如下。
然后执行
pod install
命令
如上图所示就表示集成好了。就接下来就是如何在原生项目中展示flutter的内容了。
展示单个Flutter页面
展示单个Flutter页面的方式有两种,一种是使用FlutterEngine的方式,一种是不使用FlutterEngine的方式,其实不使用FlutterEngine的说法是不严谨的,只是我们没有使用代码创建FlutterEngine而已,Flutter框架内部自己创建了FlutterEngine,但是为了方便记忆,我们可以这么理解。但是这种不使用FlutterEngine的方式官方并不推荐。因为按需创建FlutterEngine
的话,在 FlutterViewController
被 present 出来之后,第一帧图像渲染完之前,将会引入明显的延迟。但是当 Flutter 页面很少被展示时,当对决定何时启动 Dart VM 没有好的启发时,当 Flutter 无需在页面(view controller)之间保持状态时,此方式可能会有用。
不使用FlutterEngine展示单个Flutter页面(官方并不推荐)
来到ViewController.m
文件中导入Flutter
的头文件
直接创建
FlutterViewController
对象,并使用present和push两种方式展示
APP显示如下图所示:
present方式显示如图:


使用FlutterEngine展示单个Flutter页面
创建FlutterEngine
创建 FlutterEngine
的合适位置取决于您的应用。作为示例,我们将在应用启动的AppDelegate
中创建一个 FlutterEngine
,并作为属性暴露给外界。
在AppDelegate.h
中
在
AppDelegate.m
中
展示FlutterViewController
现在,你的 iOS 应用中集成了一个 Flutter 页面。
展示多个Flutter页面
使用上面的方式,最终展示的Flutter页面都是同一个页面。而在实际混合开发中,想要展示多个不同的Flutter页面的需求应该是普遍的。那么Flutter能做到吗?答案是可以的,官方的说法是自Flutter 2.0.0开始,可以同时添加多个Flutter实例。由于稳定性,性能问题以及API任然可能变动,请谨慎使用。链接
使用FlutterEngineGroup
展示多个Flutter页面需要使用到FlutterEngineGroup
来创建FlutterEngine
,而不是上面直接使用FlutterEngine
的方式。
在AppDelegate.h
中
在
AppDelegate.m
中
新建一个flutter页面
来到Android Studio中的Flutter module项目,新建一个page_two.dart文件,并做些简单的展示
PageTwo
页面写好之后,还需要到main.dart文件中声明一个新的dart入口。这样才能在原生中找到这个PageTwo
页面,代码如图:
page_two
就是PageTwo
的入口函数,在原生中待会就会用到。
展示两个Flutter页面
回到原生项目的ViewController.m文件中,实现如下代码:
在第0行,我们创建
engine
的时候,并没有传入Entrypoint参数,所以就会展示默认的入口函数main
对应的页面。在第1行中,我们创建engine
的时候,指定了入口函数为page_two
,那么就会展示page_two()所对应的页面。
present展示的页面如图:


Flutter与iOS端通信
Flutter和iOS端的通信主要是使用各种通道。有MethodChannel
,BasicMessageChannel
,EventChannel
等等,这里主要介绍前面两种通道。通道通过名称来建立联系,所以通道的名称需要确保是唯一的。如果有同名的通道,通信会受到干扰
MethodChannel 方法通道
方法通道主要用了传递方法名称和参数。在前面我们新建PageTwo的时候,就已经创建了一个MethodChannel
了,名字为page_two_channel
。然后在文本‘返回上一页’的点击手势里面调用了一个方法invokeMethod()
。这个方法可以传递多个参数,第一个参数就是方法名称,后面是方法参数。我们这里没有参数,就只传入一个方法名pop
。那么Flutter端的工作就完成了,再回到我们的iOS原生端,ViewController.m里面。实现如下代码:
在iOS中给
MethodChannel
加了一个Flutter
前缀。然后初始化FlutterMethodChannel
的时候,传入的名字一定要和flutter端是一致的,不然是无法建立通讯的。然后调用setMethodCallHandler:
方法传入一个block参数。block参数会在channel.invokeMethod()的时候被调用。block参数call
就是对invokeMethod参数的一个封装。call
的method
就是方法名,还有一个arguments
就是方法参数。这样就可以根据方法名进行判断后作出处理了。现在是从flutter向iOS原生通信,实现了在flutter中点击方法实现了pop回到上个页面的。相反的,也可以从iOS端向flutter端通信。在iOS端,使用channel
调用invokeMethod()
就可以向flutter发送消息了,在flutter端同样设置channel
的setMethodCallHandler
就可以接收了。flutter端setMethodCallHandler
代码如下:
这里说一句,这些通道不能在无状态的Widget里使用,改为有状态的就可以了。
BasicMessageChannel 基础消息通道
除了上面提到的MethodChannel
,你还可以使用BasicMessageChannel
,它支持使用自定义消息编解码器进行基本的异步消息传递。 此外,您可以使用专门的BinaryCodec
,StringCodec
和 JSONMessageCodec
类,或创建自己的编解码器。
BasicMessageChannel
这个通道的使用方法跟上面的MethodChannel
是一样的,不同点是在flutter中创建BasicMessageChannel
这个通道需要传入一个编解码器,使用一个标准的编解码器StandardMessageCodec
可以将基本的数据类型进行编解码。BasicMessageChannel
通道可以实现基础数据类型的通讯。iOS和flutter的基础数据类型对应编解码关系:
总结
本来还想写一个混合开发的实际案例的,但是鉴于本人目前的重点并不是flutter,而且网上也有较多的介绍这种混合开发的实际案例,所以这里篇文章就写到这里了。这8篇文章的内容应该说只是一个iOSer入门flutter的教程,只是些皮毛东西,离掌握flutter,Dart还差的很远。而flutter的出现也并不是说会完全取代Android和iOS开发者,flutter只能用来搭建一套各平台统一的UI,而各个平台相关的功能,和硬件相关的需求,都依然需要各个平台的开发者去实现。
转载自:https://juejin.cn/post/7001658729179381796