Flutter工程化之iOS混编集成

混编过程中的问题

  1. 由于笔者在搭建iOS项目过程中涉及了原本OC项目的迁移和通过Framework做了模块化分层,导致Podfile文件和主项目的.xcodeproj文件并不在同一层级,flutter的pod脚本存在路径引用不准确的问题,需要每次手动更改,这不太科学。
  2. Flutter的插件在项目中失效的问题

集成过程

在flutter官网上推荐了iOS项目中两种混编方式:

  1. 通过flutter tool中自带的脚本工具通过Cocoapods和Shell脚本去集成
  2. flutter build ios-framework获取编译产物集成

笔者在采用两种集成方式的过程中,因为iOS项目结构设计导致这两种简单的集成方式都有些麻烦,所以在实践中更改和优化了集成方式,使之在笔者的项目中能够更加简单和快速的集成。

实际工程化中碰到的问题

iOS工程结构
  1. 通过framework和workspace的方式去做了项目依赖的拆解
  2. podfile和.workspace平级,.xcodeproj在深层
Flutter默认脚本添加的Script Phase

问题:在不更改flutter tool中相关脚本的前提下,添加的Script Phase中的脚本相对路径错误,如果只是开发,手动更改下路径就可以了,但是在考虑到CI中不能每次在pod install之后都去更改,所以在开发调试中采用该集成方式,结合flutter attach的方式去调试。

解决方式

通过编译相关的 xcframework + Cocoapods私有库的集成方式在CI中集成,这样QA的CI不需要配置flutter的相关依赖

  1. 创建pod相关私有仓库
  2. flutter build ios-framework 编译,将编译产物移到相关仓库:Engine、App和Plugins
  3. iOS工程通过pods集成
  4. CI通过pod install去集成和更新flutter模块

自动脚本化实现过程

iOS-Flutter混编的底层编译产物分析

# ios-framework   Produces .xcframeworks for a Flutter project and its plugins for integration into existing, plain Xcode projects.
flutter build ios-framework

根据flutter编译工具的提示: 上面的编译命令是打包flutter工程项目和插件的产物,在实际开发过程中可以发现是否引入了依赖Native的插件会导致贬义编译产物的不同。


未添加依赖原生插件
依赖了cached_network_image插件

根据上面的对比:

第一部分:基础的 Flutter Engine + Flutter App 编译后的产物 Flutter.xcframwork -- Flutter引擎的包 App.xcframework -- 工程项目对应的AOT的编译产物 第二部分:三方插件的注册中心 FlutterPluginRegistrant.xcframework -- 第三方插件的注册中心,其实是Native + iOS通信的集合 第三部分:依赖iOS Native的原生 FMDB.xcframwork path_provider_ios.xcframework sqflite.xcframework -- cached_network_image依赖的原生实现

根据上面的编译产物可以知道Flutter和App是编译后必有的包,后面的两个部分完全是服务于三方插件的,到这可以解答第二个问题:笔者App的混编过程中混编插件失效是因为笔者在NativeApp中重写了Flutter的容器,使用了FlutterEngineGroup动态创建多引擎去对应进入不同的功能模块,混合插件是因为重写过程中没有通过GeneratedPluginRegistrant注册插件,所以需要在Native的Flutter容器中注册插件,使之生效。

自动化混编思路

1. 将编译产物拆分成两个git私有仓库:
  • flutter-engine-lib -- 存放Flutter.xcframwork ,其中包含了skia和dart virtual engine,因为在工程开发中Flutter会维持在稳定版本,所以这个私有仓库一般不需要变化

  • flutter-libs: 包含下面在迭代过程中变化的编译包

    -- App.xcframework -- FlutterPluginRegistrant.xcframework -- 原生依赖Pod化后的依赖包

2. 在开发完成后编译iOS相关的frameworks,上传更新两个依赖库:

  • 在不更新Flutter版本的时候,flutter-engine-lib一般不需要更新,主要是更新flutter-libs
3. 修改Native项目中的Podfile,添加两个私有仓库的依赖:
 # Flutter集成模块:Gitlab上的私有库只能内网拉取
 # Flutter Engine
 pod 'flutter-engine-lib', :git => 'http://xxx/xxx/flutter-engine-lib.git'
 # Flutter App + Plugin + Plugin loader
 pod 'flutter-lib', :git => 'http://xxx/xxx/flutter-libs.git', :commit=>'7b016680458fbcf9668d1dc6d851880dd69ce0c2'

在这为什么使用commit的hash作为flutter-libs的依赖,因为pod install的时候会有缓存,除了版本好,commit hash也能保证每次CI编译通过pod install来更新flutter-libs依赖产物

4. 脚本化完成上述过程:
#!/bin/bash

# project name
ios_project_name='flutter-libs'
# out path
ios_out_path='flutter-libs/frameworks'
# flutter lib git repo path
flutter_git_path='http://xxx/xxx/xxx/flutter-lib.git'

customEcho(){
  # echo -e "\E[1;32m""$1 \033[0m" 
  echo -e "\033[1;32m $1 \033[0m"
}

customEcho '\n0\. 请输入commit message'
read commit_message

customEcho '\n1\. 执行 flutter clean'
flutter clean || exit -1

customEcho '\n2\. 清空build文件夹'
rm -rf $ios_project_name
rm -rf build
echo '清空完成'

customEcho '\n3\. 生成 iOS frameworks'
flutter build ios-framework || exit -1 

customEcho "\n4\. 从 git 上克隆 frameworks 项目"
git clone $flutter_git_path  || exit -1 

customEcho "\n5\. 输出文件到 $ios_out_path"
rm -rf $ios_out_path
mkdir $ios_out_path

cp -r build/ios/framework/Release/App.xcframework $ios_out_path
# cp -r .ios/Flutter/App.framework $ios_out_path
echo 'App.xcframework搬运完成'

customEcho "\n6\. 提交文件到 git"
cd $ios_project_name
git add .
git commit -m $commit_message
git push -u origin master

customEcho "\n7\. 获取Flutter-lib仓库的commit-code"
commit_code=`git log  -1 | awk 'NR==1 { print substr($2,0) }'`

customEcho "\n8\. 删除该文件夹"
cd ..
rm -rf $ios_project_name

customEcho "\n9\. 粘贴下面的commit_code到Podfile中flutter-lib私有库的依赖提交号: "
echo -e "\033[1;31m $commit_code \033[0m" 

customEcho "\nAll Done."

完成!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容