在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/Release3种不同模式的xcframework,并存放在这3个目录中。完整的指令如下:

这个过程会有点耗时

flutter build ios-framework --xcframework --no-universal --output=../ios_module/FlutterFrameworks/
复制代码

image.png

然后在Xcode项目的根目录右键添加文件,即Add file to 'FlutterBoostPro',选择create groups,记得勾选Add to targets。添加好了后,xcode会自动把这些xcframework文件添加到Build PhasesLink Binary With Libraries中。这个过程在Flutter文档说明中是手动拖的,添加文件就省去拖文件的操作了。

image.png

然后framework添加到Embed Frameworks,初次添加时是找不到Embed Frameworks的,所以要到TARGETSGeneral 下面的 Frameworks, Libraries, and Embedded Content一栏操作。不过我们使用Add file to 'a project'添加的文件会自动加到这一栏,不用再重复拖入文件。

TARGETSBuild 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 EmbedFlutter文档说明中也指明了这个操作,都选择Embed & Sign即可,设置正确后就能正常运行项目了。

image.png

这种导入framework的方式,增加了编译Flutter、设置Target配置流程,如果需要切换Debug/Release环境,还需要重新添加framework,并重新设置FRAMEWORK_SEARCH_PATHSEmbed & 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/
复制代码

image.png

我们可以看下Flutter.podspec里面的具体内容,Flutter.xcframework依赖了远程zip文件,并不是我们前面用指令编译出来的,而且编译导出的目录里面也没有Flutter.xcframework(编译后就删除了),只有App.xcframeworkFlutterPluginRegistrant.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.xcframeworkFlutterPluginRegistrant.xcframework第三方库 flutter_boost.xcframework导入到项目中。不过这里我换了一种方式,不使用Add Files to 'a project'来添加文件了,而是把这3个文件拖到Frameworks, Libraries, and Embedded Content里面,设置Embed & Sign,然后在Build SettingsRunpath Search Paths添加"$(SRCROOT)/FlutterFrameworks/Release",就可以正常运行项目了。

相比方案2Flutter.xcframework采用了CocoaPods依赖导入,但是其它的.xcframework还是要手动导入。所以它的优缺点和方案2是基本一致的。Flutter.xcframework是远程的静态资源,如果有自定义引擎需求,就得在方案2的基础上改了。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享