环境及设备:
macOS Mojave 10.14.5
Xcode 11.2.1
Android Studio 3.5
iterm2+Zsh(非必须)
iPhone 7(13.3)(非必须,可以用模拟器)
这里推荐Xcode + Android Studio的方式,因为Flutter和Android Studio都出自Google团队,彼此之间兼容性好,坑也会比较少,功能也很强大完善,所以选择使用Android Studio作为Flutter开发的IDE,VScode是一个相对比较轻量的高效的开源的开发工具,有兴趣的同学同样也可以尝试。
1.MacOS环境下搭建Flutter环境
flutterchina.club/setup-macos… 这里是macOS下搭建flutter环境的官方指导,下面简单说下要点和需要注意的点。
国内访问Flutter有时候会有限制,和安装cocoaPods一样都需要设置镜像,在bash_profile文件添加一下两句:
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
注: 这是临时镜像,不一定总是可用,具体可以参考链接Using Flutter in China,或者搜索:flutter镜像,有很多方案可供选择。
下面是一些需要注意的点:
1.1 手动下载Flutter SDK,解压到某个文件夹运行 flutter doctor,它会提示你该文件夹不是一个Github的clone项目
去到github上搜索flutter,然后把sdk克隆到本地,这里建议跟踪flutter的stable分支,这是Flutter稳定分支,还有master和beta分支等,如果你想要查看flutter框架最新的变化,你可以跟踪master分支,但注意这是开发分支,所以稳定性比较低。
要查看当前使用的分支,运行flutter channel查看。
要切换分支,使用flutter channel beta 或 flutter channel master
1.2 下载Android Studio后的一些相关设置(安装Flutter和Dart插件):
- 打开 Android Studio
- 打开插件设置(macOS 系统打开 Preferences > Plugins, Windows 和 Linux 系统打开 File > Settings > Plugins)
- 选择 Marketplace,然后选择 Flutter 插件并点击 安装
- 当弹出安装 Dart 插件提示时,点击 Yes
- 当弹出重新启动提示时,点击 Restart
1.3 创建一个Flutter Module:
这里需要注意下,创建Flutter Module的时候需要填写Company domin,这个除了作为程序名外,在应用发布后,还将作为安卓项目的包名,以及iOS项目的bundle id,所以在创建之初就应该指定好它(例如车队项目的bundle id:com.foryou.ForyouAgent)。
至此你就有了一个Flutter Module,在实际项目中,我们需要把Flutter模组集成到原生iOS项目中,并建立起iOS原生项目和Flutter模组之间的数据通信,在Xcode开发原生页面,在Android Studio上开发Flutter Module。
补充:
如果你之前安装了flutter环境,现在想更新Flutter SDK和你的依赖包,在你的应用程序根目录(包含pubspec.yaml文件的目录)中运行flutter upgrade 命令:(Flutter项目根目录下的pubspec.yaml文件是Flutter的配置文件,里面包含着一些依赖库,图片素材,字体等)
flutter SDK更新成功:
2.在原有iOS项目中添加Flutter Module
到这一步,默认你应该已经做到:
- git clone下来的 Flutter SDK
- 一个iOS原生项目
- 一个Flutter Module模组
- Flutter Module运行开发环境(Andriod Studio)
2.1 将Flutter集成到原生项目
有两种方式:
- cocoaPods依赖管理 + Flutter SDK (推荐)
- 把 Flutter engine 、你的 dart 代码和所有 Flutter plugin 编译成 framework 。然后用 Xcode 手动集成到你的应用中,并更新编译设置。
注:模拟器不能运行Release和Profile模式,可以在模拟器和真机上运行Debug模式,真机上运行Release或Profile模式。(这里的Release、Debug模式指的是Flutter中的构建模式,不同模式有不同特点,例如Debug模式下的app的体积较大,性能较差,但是可以在热重载时快速响应变化;Profile模式用于在测试时分析性能等)
这里假设iOS原生项目、Flutter Module、安卓原生项目都在同一文件目录下,在podfile文件加入:
flutter_application_path = '../flutter_module/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
(podhelper.rb是个脚本,它会把你的plugins,Flutter.framework和App.framework集成到你原生项目中,Flutter.framework是Flutter engine的框架,App.framework是Dart代码编译产物)
并在target中集成这句代码:
install_all_flutter_pods(flutter_application_path)
然后运行pod install
2.2 添加Flutter页面
2.2.1 启动FlutterEngine
关于二者,这里我贴两个链接:
FlutterEngine:api.flutter-io.cn/objcdoc/Cla…
FlutterViewController:api.flutter-io.cn/objcdoc/Cla…
这里还有一个名词需要提一下:FlutterDartProject,它是用来获取 Flutter 资源和创建 FlutterEngine 实例
笼统地讲,FlutterEngine是Flutter engine的对象,用来渲染FlutterViewController的FlutterView,而FlutterViewController继承于UIViewController,Flutter根据需要对其做了扩展,本质是一个特殊控制器。
这里推荐在Appdelegate中创建一个全局的FlutterEngine,并初始化,建立起Flutter 路由运行默认入口。
当flutterEngine调用run方法的时候,默认会调用Flutter Module中的lib/main.dart文件里的main()函数。
flutterEngine的run方法有多种,比如:
这个方法意味着不在调用lib/otherFile.dart文件中的otherMain()函数作为入口。
这里提一下,一般都推荐优先创建FlutterEngine,而不是用的时候再创建,是因为FlutterEngine的生命周期可以和FlutterViewController一样,但是也可以比FlutterViewController更长,优先创建的好处是可以当开始调起Flutter页面的时候,可以更快更高效地展示,除此之外,还可以做到提前通信、逻辑交互等。
你也许注意到了FlutterAppDelegate这个东西,这个是什么呢?从名字就知道是Flutter针对UIApplicationDelegate的包装,或者定制的一个替代品。它本身包含了一些额外的功能,例如传递项目的回调(例如把指纹校验或者网络请求传递给Flutter模组等),或者传递状态栏点击事件传递给Flutter等等。
如果现有的项目无法直接继承FlutterAppDelegate,为了保证Flutter plugins能收到正确的回调,应该让项目中原有的AppDelegate实现FlutterAppLifeCycleProvider协议。
2.2.2 创建继承于FlutterViewController的页面
创建一个继承于FlutterViewController的页面,例如车队中的“设置”页面:FYMainSettingFlutterVC,需要引入Flutter框架
在页面里,我们需要建立起Flutter ⇄ 原生代码之间的双向通道,用来传递数据和点击事件:
- 首先建立原生->Flutter页面的路由通道
这里的main_setting作为页面路由辨识,决定了从原生页面跳转的是哪个flutter页面,这个‘main_setting’双端必须保持一致。
前面说过,dart入口是main.dart文件的main()函数,那么这个标识就是在那地方用到。
- 接下来是Flutter->原生的跳转路由通道,比如从flutter页面传过来的一些操作,例如点击事件等。
FlutterMethodChannel代表着一个信道,用来交互通信,这个通道的名字命名为“MethodChannelPlugin”,实际应用中可能存在多个channel,所以在创建的时候应该指定独一无二的名字,此外我们看到还有一个binaryMessenger参数,这个参数是BinaryMessenger类型,代表消息信使,是消息的发送与接收的工具,和它的名字一样,用来运输二进制类型的数据。
call是FlutterMethodCall类型的,有一个method属性,用来区别flutter页面产生的操作标识,这个标识双端必须保持一致,否则就不能形成正确的操作响应链。
result是FlutterResult类型的block,可以将任意类型的参数传到flutter模块。
(getCommomParams()方法用来传递一些接口的公共参数,因为车队项目接口参数中,有很多公共参数都是在底层获取,所以当Flutter Module中进行网络请求时,就需要把这些公共参数传过去,进而使flutter项目中的网络请求能正常进行,目前是这样,可以优化。)
至此,一个Flutter页面和原生页面之间的所有通道就搭建好了。
3.在Android Studio开发Flutter代码
Dart语言基础:www.dartcn.com/guides/lang…
Flutter中文网:flutterchina.club/