开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
《Flutter 多引擎渲染,在稿定 App 的实践》 等介绍篇章,本专栏里可查看
前言
前面的篇章讲了笔者用 Flutter 多引擎渲染做到了什么程度,以及在过程中做了哪些探索和实践。但对于初入门的同学来讲并不算友好,没有太多的细节介绍如何开发、如何链接多端、如何贯通开发流程。
会包含以下部分:
- Flutter 多引擎渲染工作原理
- 如何从零开始搭建 Flutter 多引擎渲染组件应用在 iOS、Android 项目中
- 如何构建跨端工具链来优雅的抹平开发构建成本
围绕上图的 FGUIComponentAPI 实现过程展开。
特别说明
这一系列的目的是从零开始让大家能真正实操到项目中,适用于有语言基础(dart、objective-c、kotlin、java、ruby/python)的同学,所以除了各种语言的基础语法不会多做解释,其他都会逐步讲解,也会尽可能增加每行代码的注释。
但由于工作上事情也蛮多,所以会在12月把本系列的文章全部发出来给大家参考(尽量不鸽)。
读者将会本文中得到:
- 如何搭建的开发环境
- 须知的官网 Demo 及关键代码解释
环境搭建
从零开始,那就要从环境搭建开始。其实多引擎开发上并不需要什么特别的配置,flutter doctor
都能过就可以了,这里简单的写一下搭建过程,且只写笔者最推荐的方式。
以 Mac 电脑为例,Windows 已经很久没用过了,也不是很清楚要如何配置,具体的就 Flutter 官网看一下。
iOS 环境
iOS 集成很高,不用特别的操作,App Store 里搜一下 xcode 安装即可,现在膨胀到 10+G 大了,需要耐心的等
Ruby 安装
虽然 mac 都自带 Ruby,但系统的 Ruby 有诸多限制,建议还是装一个开发使用的 Ruby 环境。
也是通过 brew 安装:
brew install ruby
同样也需要配置下环境变量
echo 'export PATH="/usr/local/opt/ruby/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
安装完成后,执行下 which -a ruby
和 ruby -v
验证下
Android 环境
Android 麻烦一些,且准备好科学上网工具,google 不是你想访问就能访问的。
Android Studio
Android 开发 IDE,传送门:developer.android.google.cn/studio
安装完成后,各种 SDK Manager 需要装一下
全局环境变量也需要配置:
export
export ANDROID_HOME=/Users/yuanxiao/Documents/sdk/android
export PATH=${PATH}:${ANDROID_HOME}/platform-tools
export PATH=${PATH}:{ANDROID_HOME}/tools
Flutter 环境
Flutter 版本管理
强烈推荐使用 Flutter 版本管理工具:fvm 来管理 Flutter SDK,可以随时切换多个 Flutter 版本来进行开发。这点在 Flutter 开发上很有用,毕竟一直跟最新版当小白鼠风险很大,但还是要升级看看到底有没有风险[手动狗头]。
fvm 安装
brew tap leoafarias/fvm
brew install fvm
如果没有装 homebrew
的话,这里建议装一下 - -。
fvm 常用命令
fvm list
列出当前安装的 Flutter 版本列表
fvm global
全局切换版本至
fvm use
当前项目切换版本至
fvm install x.x.x
安装某一个版本的 Flutter
十分方便
配置环境变量
当然为了项目外也能使用,还是要配置下环境变量:
打开(或创建) $HOME/.bash_profile
增加 PATH 路径
export PATH=$HOME/fvm/default/bin:$PATH
export PATH=$HOME/fvm/default/bin/cache/dart-sdk/bin:$PATH
开发工具
Flutter 开发建议使用: VS Code
调试环境建议使用:Chrome (Web 开发调试)
工具链脚本开发
在后续篇章,我们会讲到跨端工具链的研发。如果对 Ruby 不算熟,也可以选择自己熟悉的脚本语言:Node、Python 等,但不建议用 dart 脚本,性能完全不行。
我们用到的脚本能力十分基础,具备文件操作即可。
环境测试
执行 flutter doctor
全对就 OK 了,至此整套开发环境已齐备。
官方源码
在讲我们如何实现多引擎渲染组件之前,建议大家都去了解一下官方提供的多引擎 Demo,比较简单易懂。
multiple_flutters
它的源码还是很简单的
关键代码解释
抛开 Channel
部分,因为我们也不会这么用它
Flutter 侧
@pragma('vm:entry-point')
// 这句是让 Flutter build 时要保留住,不不要被 treeshake 掉
void topMain() => runApp(const MyApp(color: Colors.green));
// runApp 跟 main() 的 runApp 没区别,但 MyApp 不能是一个 MaterialApp
@pragma('vm:entry-point')
void bottomMain() => runApp(const MyApp(color: Colors.purple));
topMain() 和 bottomMain() 相当于暴露给 Native 侧直接调用,原则上不能通过这里传递参数的(但有些厂也喜欢魔改一下,让这个方法可以传参)。
iOS 侧
iOS 侧的 Demo 有些差强人意,我把关键的代码从几个文件里抽出来介绍。
// 创建一个 FlutterEngineGroup,multiple-flutters 会是你的线程名称
let engines = FlutterEngineGroup(name: "multiple-flutters", project: nil)
// 从中创建出一个 FlutterEngine
// 其中 entryPoint = "topMain" / "bottomMain" 就是 flutter 里定义的暴露层,但这个有坑,先 mark
let newEngine = appDelegate.engines.makeEngine(withEntrypoint: entryPoint, libraryURI: nil)
// 完成 FlutterViewController 初始化,这样完成 FlutterEngine 与 VC 的绑定,页面上就可以显示出 VC.view
super.init(engine: newEngine, nibName: nil, bundle: nil)
Android 侧
也是差强人意,但其实和 iOS 一样,关键的也是这个过程代码
// 创建 FlutterEngineGroup
engines = FlutterEngineGroup(this)
// 从中创建出一个 FlutterEngine
// dartEntrypoint 就是 "topMain" / "bottomMain"
engine = app.engines.createAndRunEngine(activity, dartEntrypoint)
// 重写 provideFlutterEngine,完成 FlutterActivity 和 FlutterEngine 的绑定
override fun provideFlutterEngine(context: Context): FlutterEngine? {
return engineBindings.engine
}
pigeon
还要看一下 pigeon 的 demo,我们后面也是会集成 pigeon 到项目中。
传送门:
pigeon 的例子叫 books [滑稽]
它是一个跨端工具,让 dart 代码生成 iOS、Android 代码。
如下图位置,schema.dart
是源文件
// 定义一个模型
class Book {
// 要注意都必须是可为空的对象
String? title;
String? subtitle;
String? author;
String? summary;
String? publishDate;
int? pageCount;
// 模型可嵌套,也可以定义 List<Thumbnail?>?
Thumbnail? thumbnail;
}
class Thumbnail {
String? url;
}
// Native 调用 Flutter 增加 @FlutterApi()
// 这里只能是抽象类,且里面只能写方法,不能写别的
@FlutterApi()
abstract class FlutterBookApi {
void displayBookDetails(Book book);
}
// Flutter 调用 Native 增加 @HostApi()
@HostApi()
abstract class HostBookApi {
void cancel();
void finishEditingBook(Book book);
}
实际使用上限制非常多,且不能引用任何其他库,包括 Flutter 自身的库。
Flutter 生成在 flutter_module_books/lib/Api.dart
iOS 生成在 ios_books/IosBooks/api.h
Android 生成在 android_books/app/src/main/java/dev/flutter/example/books/Api.java
脚本
再说一下为什么会生成在这些位置上,怎么做到的,其实是执行了一段脚本:run_pigeon.sh
#!/bin/sh
flutter pub run pigeon --input pigeon/schema.dart \
--dart_out lib/api.dart \
--objc_header_out ../ios_books/IosBooks/api.h \
--objc_source_out ../ios_books/IosBooks/api.m \
--objc_prefix BK \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \
--java_package "dev.flutter.example.books"
--input
解析的源文件
--dart_out
dart 文件输出位置
--objc_header_out / --objc_source_out
iOS 代码输出位置
--objc_prefix
OC 代码因为没有命名空间,所以需要增加的前缀
--java_out
Android 代码输出位置
--java_package
Java 包名
这实质上调用的是 flutter pub run pigeon
,dart 脚本执行效率确实很堪忧。
传送门
《从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇》
《从零开始|构建 Flutter 多引擎渲染组件:Flutter 代码篇》
感谢阅读,如果对你有用请点个赞 ❤️