Flutter+iOS混合开发实践

一、混合开发效果展示和描述

①、演示鲤读混合开发效果 ②、概述:

flutter与native混合开发,包含两个模块:flutter调用原生功能、原有项目嵌入flutter模块

主要内容:

  • flutter如何调用native原生硬件信息,flutter和native之间如何通信,方法互调 思路:我们熟悉的传统的H5页面和原生交互时,通过中间通信工具对象,定义好方法 或者属性进行通信。同理,Flutter与iOS原生交互也有专门的通信对象(Platform Channel),他有三种类型:

    • MethodChannel:用于最常见的方法传递,帮助Flutter和原生平台互相调用方法,也是本次我们重点介绍的。
    • BasicMessageChannel:用于数据信息的传递。
    • EventChannel:用于事件的监听传递等场景。
  • 原有项目嵌入flutter模块,如何进行交互,参数传递

二、flutter调用原生功能

  • 1、比如纯flutter项目中,flutter需要调用摄像机等硬件设备的时候。Flutter的官方提供了一个拍照或者相册管理的插件:image_picker,添加依赖 dependencies: image_picker: ^0.6.5

对于iOS平台,iOS开发的人都应该知道,如果用户想要访问照相机或者相册,麦克风,定位等相关功能的时候需要系统进行授权,否则运行项目会crash。添加相关权限如下: 具体插件的使用方法可以查看image_picker

2、比如电池等信息:某些原生的信息,如果没有很好的插件,我们可以通过platform channels(平台通道)来获取信息。平台是如何工作的呢? * 消息使用platform channels(平台通道)在客户端(UI)和宿主(平台)之间传递 * 消息和响应是以异步的形式进行传递的,以确保用户界面能够保持响应: 调用过程大致如下: * 客户端(Flutter端)发送与方法调用相对应的消息 * 平台端(iOS、Android端)接收方法,并返回结果; * iOS端通过FlutterMethodChannel做出响应; * Android端通过MethodChannel做出响应 以获取iOS电量信息示例: 当我们通过platform.invokeMethod调用对应平台的方法时,需要在对应的平台实现其操作: iOS中可以通过OC或者Swift来实现
使用Xcode打开Flutter根目录下面的ios->Runner.xcworkspace 在AppDelegate中编写相应的逻辑:

三、原有项目嵌入flutter模块

  • 首先,明确一点:Flutter设计的初衷并不是为了和其它平台进行混合开发,它的目的是为了打造一个完整的跨平台应用程序。但是,实际开发中,原有项目完全使用Flutter进行重构并不现实,对于原有项目我们更多可能采用混合开发的方式。
  • 通过阅读Flutter的官方文档了解到,iOS和Flutter混编的关键步骤,都需要将Flutter相关的文件编译成静态库framework,再通过cocoapods进行管理,集成到现有的项目中。

下面集成的三种方式都必须的步骤:

  • ①、原有的iOS项目使用CococaPods管理(现在的项目基本都使用Cocoapods进行管理)
  • ②、在原有项目的文件平级的位置,创建Flutter Module,比如我自己写的一个demo:使用命令flutter create -t module myflutter创建需要集成的flutter模块,这块的名字可以随便起,我按照文档起叫 myflutter 可以对比一下flutter的模板项目,和普通的flutter项目的目录结构区别,其中ios和android文件夹变成隐藏的。Mac下面 command+shif+.显示和不显示隐藏文件夹。

    • 使用Android Studio打开刚刚创建的flutter模板工程,在pubspec.yaml配置一些第三方依赖的插件比如:执行 flutter pub get下载flutter的第三方依赖插件(第三方库)
  • ③、将 Flutter Module编译成framework,引入iOS工程。

  • ④、编写测试代码,查看结果

方式一:使用Cocoapods依赖管理和已安装的Flutter SDK

通过上面的必须步骤之后,flutter必须的dart代码、第三方库都已编译成framework,打开iOS项目的Pofile文件添加如下指令:

执行pod install指令查看iOS项目工程目录结构:

可见Flutter.framework、FlutterPluginRegistrant、App.framework、第三方的库都加载到iOS项目中了(但是只是本地的pod依赖)可以在项目中进行加载flutter相关模块了。

方式二:将Flutter Module编译产物手动引入工程

方式三:将Flutter Module编译产物通过pod私有库(或者本地库)cococapods进行管理

方式二的弊端就是、每个参与混合开发的人员电脑都必须装有Flutter环境不利于多人进行开发而且生成的目录结构比较混乱。所以选择将编译的产物通过构建一个Pod私有库来通过Cocoapods管理。当flutter模块的dart代码改动,进入到flutter目录的根目录执行指令flutter build ios-framework --output=/Users/peixu/Desktop/FlutterProject/iOSFlutterMixBuilder/flutterframework把编译的产物放到指定的文件夹中。 本地文件夹目录结构: 在项目的同级目录使用 pod lib create创建pod私有库,将编译生成的产物放到pod模板工程的Classes文件夹下面,并修改.podspec文件指定framework路径 每次pod库更新完毕之后,进入到iOS原有工程Podfile目录执行pod install更新Flutter编译产物。

注:后期编译产物可以做一个脚本,每次改动,执行一下脚本,把产物直接放到pod模板库Classes文件夹下面

①、关键名词介绍: * FlutterViewController:Flutter页面控制器,我们可以直接push/present到该控制器,或将其作为ChildViewController嵌入到我们的页面当中。 * FlutterEngine:Flutter负责在iOS端执行Dart代码的引擎,将Flutter编写的UI代码渲染到FlutterViewController中。

方式三:使用闲鱼的开源插件FlutterBoost(推荐)

闲鱼的说法:上面的三种方式都是按照官方的集成方案来做的存在诸多弊病: * 日志不能输出到原生端 * 存在内存泄露的问题,使用Boost可以让内存稳定; * native调用flutter,flutter调用native,通道的封装,使开发更加简便; * 同时对于页面生命周期的管理,也梳理的比较整齐

集成流程: * 在flutter的moudle工程的pubspec.yaml中添加依赖 flutter_boost: ^1.12.13+3 * iOS原有项目通过上述方案三导入flutter必须的framework * 需要使用FlutterBoost的地方需要引入头文件 * 自定义FlutterBoots路由实现FLBPlatform协议,并重写里面的 open、present、close方法(方便项目后面的业务逻辑处理,也可以使用闲鱼自带的路由)(具体实现看代码) * 在AppDelegate启动的时候,初始化FlutterBoots的相关设置,在Flutter模块中需要注册你需要的页面跳转路由。(具体看代码)

三、混合开发文档:

作者介绍:裴旭,高级iOS开发工程师

微鲤技术团队

微鲤技术团队承担了中华万年历、Maybe、蘑菇语音、微鲤游戏高达3亿用户的产品研发工作,并构建了完备的大数据平台、基础研发框架、基础运维设施。践行数据驱动理念,相信技术改变世界。