在iOS项目中依赖Flutter Module-①本地依赖
目录
"在iOS项目中依赖Flutter Module"系列文章和构建脚本都已放到了GitHub上,传送门🚪
本文整理的3种本地依赖方案都是Flutter开发文档- 章节:Adding Flutter to iOS
中推荐的,适用于在原有的iOS项目中依赖Flutter Module。依赖Flutter Module分为本地依赖和远程依赖,远程依赖会在后续的文章介绍,如果想提前看,可以进上面的传送门
。
在iOS项目依赖Flutter Module / 将Flutter Module添加到现有的iOS项目,要先创建一个Flutter Module。
cd some/path/
flutter create --template module flutter_module
flutter_module
目录的结构如下,.../flutter_module/lib/
里面放到的就是我们写的dart文件。
some/path/
├── flutter_module
│ ├── README.md
│ ├── build
│ ├── flutter_module.iml
│ ├── flutter_module_android.iml
│ ├── lib
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
建好flutter_module
后,随便加点flutter代码和第三方组件(比如flutter_boost),就可以测试了。
1.基于CocoaPods和podhelper.rb脚本本地依赖FlutterModule
这种接入方式是最常见的一种,容易上手,方便调试。ios_module
/flutter_module
/andriod_module
可以放到不同的Git仓库,依赖时填写好相对的目录即可。为了方便测试代码,我把ios_module
/flutter_module
/andriod_module
放在了一个Git仓库/目录下。ios_module
就是iOS项目所在目录,整体目录结构如下:
some/path/
├── andriod_module
│ ├── ...
├── flutter_module
│ ├── README.md
│ ├── build
│ ├── flutter_module.iml
│ ├── flutter_module_android.iml
│ ├── lib
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
├──ios_module
├── FlutterBoostPro
├── FlutterBoostPro.xcodeproj
├── FlutterBoostPro.xcworkspace
├── Podfile
├── Podfile.lock
└── Pods
然后在iOS项目的Podfile文件中增加以下代码,执行pod install or update
。
flutter_application_path = '../flutter_module/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)
podhelper.rb脚本会将Flutter组件代码编译成.xcframework
,并通过依赖本地路径导入到Pods中。
这种方式无论是Debug运行还是Release打包,都行得通,也方便单人开发调试两端,在1台电脑用2个IDE开发调试两端代码即可,模拟器也能正常运行。但也有明显的缺陷,需要所有的iOS开发人员都安装有Flutter开发环境,另外iOS项目编译时会很慢,每天编译的时间损耗还是不小的,打包时间也会增加不少。
2.编译FlutterModule,手动添加.xcframwork到iOS项目中
首先需要将FlutterModule编译成iOS的.xcframwork
动态库,使用的是flutter build ios-framework --xcframework
指令集。不过这个指令可以设置导出的目录,所以我们可以直接导出到ios_module/
里,完整的目录结构如下,相比方案1,这里只增加了FlutterFrameworks
目录,专门用来存放Flutter的编译产物xcframework
。
some/path/
├── andriod_module
│ ├── ...
├── flutter_module
│ ├── README.md
│ ├── build
│ ├── flutter_module.iml
│ ├── flutter_module_android.iml
│ ├── lib
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
├──ios_module
├── FlutterBoostPro
├── FlutterBoostPro.xcodeproj
├── FlutterBoostPro.xcworkspace
├── FlutterFrameworks # <- 新增这个文件夹
├── Podfile
├── Podfile.lock
└── Pods
执行这段完整的编译指令,即可导出Debug
/Profile
/Release
3种不同模式的xcframework
,并存放在这3个目录中。完整的指令如下:
这个过程会有点耗时
flutter build ios-framework --xcframework --no-universal --output=../ios_module/FlutterFrameworks/
然后在Xcode项目的根目录右键添加文件,即Add file to 'FlutterBoostPro'
,选择create groups
,记得勾选Add to targets
。添加好了后,xcode会自动把这些xcframework
文件添加到Build Phases
的Link Binary With Libraries
中。这个过程在Flutter文档说明中是手动拖的,添加文件就省去拖文件的操作了。
然后将framework
添加到Embed Frameworks
中,初次添加时是找不到Embed Frameworks
的,所以要到TARGETS
- General
下面的 Frameworks, Libraries, and Embedded Content
一栏操作。不过我们使用Add file to 'a project'
添加的文件会自动加到这一栏,不用再重复拖入文件。
在TARGETS
的Build Settings
里面设置Runpath Search Paths
,添加"$(SRCROOT)/FlutterFrameworks/Release"
,指定相对路径。
这个时候试着运行项目,会出现报错:
dyld: Library not loaded: @rpath/Flutter.framework/Flutter
Referenced from: /private/var/containers/Bundle/Application/0A64CC78-D8D3-433C-B794-B8F928525885/FlutterBoostPro.app/FlutterBoostPro
Reason: image not found
dyld: launch, loading dependent libraries
DYLD_LIBRARY_PATH=/usr/lib/system/introspection
DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
是因为我们没有设置Embed & Sign
,状态是Do Not Embed
,Flutter文档说明中也指明了这个操作,都选择Embed & Sign
即可,设置正确后就能正常运行项目了。
这种导入framework
的方式,增加了编译Flutter、设置Target配置流程,如果需要切换Debug/Release
环境,还需要重新添加framework
,并重新设置FRAMEWORK_SEARCH_PATHS
和Embed & Sign
,在调试期间会增加不少的手动操作,当然为了方便调试,在flutter_module/.ios/
下面的Runner项目中也可以依赖iOS的业务代码,也可以快速调试,只是Flutter clean
后又要重新依赖,相对来说还是有点繁琐的;另外由于把编译产物直接导入到了iOS项目目录中,而Flutter.xcframework
文件很大,会直接增加git的文件大小,影响git push和pull,每次编译也会影响到其他人员分支的同步。但这种导入framework
的方式也有个非常大的优点,编译运行iOS项目耗时短,因为已经是编译过的xcframework
文件,不用额外编译Flutter代码,相比之下能节省很多编译时间;另外其他的开发人员也不用安装Flutter开发环境,直接跑iOS项目就行。
3.编译FlutterModule,远程依赖Flutter.xcframework,本地依赖其余.xcframwork
前面2种方法都是依赖本机的编译产物,如果想把FlutterFrameworks
分享给同事,直接推到Git会很耗时。Flutter.xcframework
文件太大,超过了Github单个文件100M的限制,推到GitHub是行不通的,内部的Gitlab可以但很慢。为此Flutter官方特意给Flutter.xcframework
实现了本地podspec中转依赖远程zip文件。这种依赖Flutter组件的方法逻辑上跟方案2一致,先把flutter_module编译成framwork,存放在FlutterFrameworks
目录,再手动导入项目。区别在于Flutter.xcframework
是通过cocoaPods导入,依赖了Google的远程文件,这样就避免了git无法提交或提交很慢的问题。
首先还是编译Flutter,需要注意这里增加了--cocoapods
,编译后的产物包含了一个Flutter.podspec
,这个Flutter.podspec
依赖指向了Flutter.xcframework
的远程文件。
flutter build ios-framework --cocoapods --xcframework --no-universal --output=../ios_module/FlutterFrameworks/
我们可以看下Flutter.podspec
里面的具体内容,Flutter.xcframework
依赖了远程zip文件,并不是我们前面用指令编译出来的,而且编译导出的目录里面也没有Flutter.xcframework
(编译后就删除了),只有App.xcframework
、FlutterPluginRegistrant.xcframework
和第三方插件库 flutter_boost.xcframework
。
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '2.0.300' # 2.0.3
s.summary = 'Flutter Engine Framework'
s.description = <<-DESC
... 一些描述
DESC
s.homepage = 'https://flutter.dev'
s.license = { :type => 'MIT', :text => <<-LICENSE
... 一些版权声明
LICENSE
}
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :http => 'https://storage.flutter-io.cn/flutter_infra/flutter/3459eb24361807fb186953a864cf890fa8e9d26a/ios-release/artifacts.zip' }
s.documentation_url = 'https://flutter.dev/docs'
s.platform = :ios, '8.0'
s.vendored_frameworks = 'Flutter.xcframework'
end
然后我们在Podfile
新增依赖Flutter
,执行pod install or update
pod 'Flutter', :podspec => './FlutterFrameworks/Release/Flutter.podspec'
-> Installing Flutter (2.0.300)
> Http download
$ /usr/bin/curl -f -L -o /var/folders/jp/4slqd1n915b7s_dm47l0mk240000gn/T/d20210706-71545-f6gido/file.zip https://storage.flutter-io.cn/flutter_infra/flutter/3459eb24361807fb186953a864cf890fa8e9d26a/ios-release/artifacts.zip
--create-dirs --netrc-optional --retry 2 -A 'CocoaPods/1.10.1 cocoapods-downloader/1.4.0'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 194M 100 194M 0 0 10.0M 0 0:00:19 0:00:19 --:--:-- 10.8M
首次安装会从云端下载Flutter.xcframework
,文件大小在200M左右 (各版本Flutter对应的大小不一样),有点考验网络,解压后的Flutter.xcframework
大小在480M左右,所以务必要在.gitignore
中添加ios_module/Pods/Flutter/*.xcframework
。
如果这个时候我们运行项目,也是会报错的,因为目前为止只依赖Flutter.xcframework
,其它的编译产物还是没有导入。所以我们还需要按照方案2的流程把App.xcframework
、FlutterPluginRegistrant.xcframework
和第三方库 flutter_boost.xcframework
导入到项目中。不过这里我换了一种方式,不使用Add Files to 'a project'
来添加文件了,而是把这3个文件拖到Frameworks, Libraries, and Embedded Content
里面,设置Embed & Sign
,然后在Build Settings
的Runpath Search Paths
添加"$(SRCROOT)/FlutterFrameworks/Release"
,就可以正常运行项目了。
相比方案2,Flutter.xcframework
采用了CocoaPods依赖导入,但是其它的.xcframework
还是要手动导入。所以它的优缺点和方案2是基本一致的。Flutter.xcframework
是远程的静态资源,如果有自定义引擎需求,就得在方案2的基础上改了。
转载自:https://juejin.cn/post/6994738746486685704