接入 flutter 的第一步是打通 flutter 侧和 iOS 侧的协同开发、调试、发布的整个流程。
首先调研了 flutter 官方集成方式,根据官方文档 https://flutter.dev/docs/development/add-to-app/ios/project-setup,创建 demo 工程,研究了 demo 的工程结构和代码运行方式。
根据官方文档安装环境,生成 demo,在pubspec.yaml 中添加一个第三方依赖 flutter_boost ,方便分析组件添加方式。然后执行指令 flutter pub get ,得到以下工程结构
其中
lib 文件夹下是 dart 代码;
.ios 是 flutter 生成的ios宿主工程,用来在 iphone 手机上运行 app
.android 是安卓宿主工程
.flutter-plugins 是第三方依赖插件的存储路径,这个后面分析会用到
接下来打开.ios 下的 xcode 工程,在.ios文件夹下执行 pod install,我们发现第三方插件和 dart 代码生成的库,已经通过 pod 添加到了工程中,运行工程,即可联调 dart 代码。接下来分析一下这是如何做到。
打开 Podfile文件,发现加载了podhelper.rb文件,并调用了 ruby 方法来执行安装,根据podhelper.rb文件的加载路径,很容易找到该文件,打开文件看 ruby 函数定义。这里不再贴里面的全部代码了,简单的介绍一下,主要函数一共三个
#安装flutter引擎install_flutter_engine_pod#安装 flutter 组件,即第三方库install_flutter_plugin_pods(flutter_application_path)#安装 dart 应用代码install_flutter_application_pod(flutter_application_path)
1、install_flutter_engine_pod,这个是根据本地安装的 flutter 的路径, 向项目中安装 flutter库,具体路径,可以参考其代码
2、install_flutter_plugin_pods,读取前面提到的.flutter-plugins文件,拿到组件路径,生成快捷方式,放在了.symlinks文件夹下,并根据组件路径逐个pod加载安装组件
3、install_flutter_application_pod, 把 dart 代码打包生成 app.framework,并使用 pod 加载。生成app.framework的函数方法在xcode_backend.sh中,在代码中可以看到该脚本文件的存放路径
"$FLUTTER_ROOT"/packages/flutter_tools/bin/xcode_backend.sh"
打开xcode_backend.sh文件,主函数入口在文件的最下方
# Main entry point.# TODO(cbracken): improve error handling, then enable set -eif [[ $# == 0 ]]; then# Backwards-compatibility: if no args are provided, build. BuildAppelse case $1 in "build") BuildApp ;; "thin") ThinAppFrameworks ;; "embed") EmbedFlutterFrameworks ;; esacfi
在这个文件里,我们可以找到打包使用的各种指令和配置。
到这里已经了解了 flutter集成到 ios 中的方式,我们发现使用这种方式有以下几个问题,
1、很难用这种方式实现远端自动打包流程
2、flutter 侧和 ios 侧开发相互依赖
我们参考官方的打包脚本,可以来创建自己的脚本工具,解决集成问题。
下面讲一下我使用的解决方案
这里使用了58的开源项目magpie_workflow(https://github.com/wuba/magpie)。magpie_workflow很好的解决了上述问题。
magpie_workflow提供了脚手架,开发编译用的可视化界面。具体的使用,参看其文档。
使用magpie_workflow,可以得到相应的flutter侧打包产物,使用产物建立用于 ios 工程集成的 flutter lib 仓库 flutteriOSLib。
deubg :用于 debug 使用的flutter侧编译产物
release:用于发布打包使用,把magpie_workflow生成的产物中product文件夹,替换release下的product文件夹即可
flutterEngine:flutter 引擎,放在这里管理,是为了避免flutter 引擎自动升级,和避免在太阳花打包时,需要在远端安装 flutter 环境。
在我们的工程实践,使用自己创建的podFlutterHelper.rb文件中的方法加载其 flutter lib 库,根据ENV['debug'] = '1',来配置加载的 flutter 环境。
ps:podFlutterHelper.rb是自定义的,可以自己更改,修改时注意里面的相对路径不要错误
Podfile 文件相关代码
#配置 flutter 相关环境; 0 是 release 包,1 是 debug 吧ENV['debug'] = '0'load File.join('podFlutterHelper.rb')target 'myapp' doload_workflow_podhelper('git@igit.58corp.com:myapp/flutteriOSLib.git','master')end
podFlutterHelper.rb文件代码,代码仅供参考
# Install pods needed to embed Flutter application.# from the host application Podfile.## @example# target 'MyApp' do# load_workflow_podhelper( , )# enddef load_workflow_podhelper (path,tag=nil) if (path.start_with?('git')||path.start_with?('http')) if !tag puts('远端依赖必须指定branch或tag ! ') return end puts("开始下载 flutteriOSLib ") finish_dir="Pods/flutteriOSLib" temp_dir="~/.myappPods/flutteriOSLib" libPath="#{temp_dir}/release/product" flutter_engine_path="#{temp_dir}/flutterEngine" finish_flutter_dir="Pods/flutter" if ENV['debug'] == '1' libPath="#{temp_dir}/debug/product" puts("#{libPath}") end git_path="git clone -b #{tag} #{path} #{temp_dir}" system "rm -rf #{temp_dir}" system "mkdir -p #{temp_dir}" system "rm -rf #{finish_dir}" system "mkdir -p #{finish_dir}" system "rm -rf #{finish_flutter_dir}" system "mkdir -p #{finish_flutter_dir}" system git_path puts("cp -rf #{libPath} #{finish_dir}") system "cp -rf #{libPath} #{finish_dir}" #复制 flutter 引擎 system "cp -rf #{flutter_engine_path} #{finish_flutter_dir}" #安装 flutter引擎,如果此处不手动安装,会自动下载官方最新引擎,默认是 release 版,此处安装的包括 debug 版 puts("开始安装 flutter引擎") path="#{finish_flutter_dir}/flutterEngine" pod 'Flutter', :path => path end load File.join(finish_dir,'product','podhelper.rb') install_flutter_business_pods#移除下载缓存 system "rm -rf ~/.myappPods"end
原创内容,允许转载,但请注明原文链接