目前对于Flutter开发来说,主要的场景还是Native和Flutter混合开发的模式,而如何正确的在Native中集成Flutter则是我们的第一步。
现在网上关于Flutter集成的文章还是很多的,但是大多数还是不够详细,而且同样的方式去集成的话没办法集成成功。在这里主要分享一下自己的集成经验。
尝试的几种集成方式:
1、手动集成,手动去进行每一步的环境配置
2、参考闲鱼的集成方案,使用开源组件Flutter-boot集成
3、使用cocoapods集成
对于前两种方式,目前没有能成功的去配置好集成的环境(可能是姿势不对吧~)。而第三种方式,虽然也经历了一点小波折,但是最后还是成功的集成了开发环境。下面会对前两种失败的经历做一个简要描述,接着会着重介绍下第三种方式的集成过程。
1、手动集成,手动去进行每一步的环境配置(目前不能支持插件生效):
1)引入Flutter Module模块
打开终端,进入项目“Flutter_Code”的根目录,执行以下命令
cd Flutter_Code
flutter create -t module flutter_app
完成后,会生成名为flutter_app的文件夹,其和ios、android项目同级
2)创建依赖配置文件
打开iOS工程,在工程目录下新建文件夹(此文件夹的位置没有要求),用以保存配置文件,根据官网,需要创建三个配置文件:Flutter.xcconfig、Debug.xcconfig、Release.xcconfig。如图:
在Flutter.xcconfig中填写:
//这里填写建立的flutter module 的 Generated.xcconfig的路径,添加flutter的依赖关系
#include "../flutter_module/.ios/Flutter/Generated.xcconfig"
ENABLE_BITCODE=NO
在Debug.xcconfig中填写:
#include "Flutter.xcconfig"
在Release.xcconfig中填写:
#include "Flutter.xcconfig"
FLUTTER_BUILD_MODE=release
Ps:如果工程中用cocopods管理,则需要在Debug.xcconfig、Release.xcconfig中添加pod的路径
准备好上述xcconfig文件后,需要到PROJECT中的Configurations中设置相关配置,将对应的targer设置成前面生成的xcconfig文件,Debug选择Debug.xcconfig,Release用Release.xcconfig。如图:
Ps:在进行打包时,无论是Debug还是Release,都需要切换到Release.xcconfig,否则会报错
3)为编译Dart引入相关脚本
在工程的Build Phase中新建一个Script Phase,用于运行Flutter脚本
新建Run Script Phase后,名字改为了“Flutter load”,需要移动其位置,需要在Dependencies之后(如上图),如果用cocoapods管理工程,则需要在Check Pod项目后。
在”Flutter load”里,在脚本框内,需要写入以下代码,用于加载Flutter的xcode_backend脚本:
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
4)修改Flutter SDK脚本:
这一步至关重要,因为每次修改main.dart文件后,都需要Command+B后才能生效,而进行Command+B后会生成、更新App.framework、engine、flutter_assets文件,所以这三个文件的依赖关系一定要添加正确,而且要保证每次编译工程时,所依赖的这三个文件都能即时更新。
4.1)默认情况下Xcode Run Script编译好的Framework并不在项目中,而在我们创建的flutter module文件夹下(一般路径是./ios/Flutter/)
4.2)而在Flutter脚本代码中有判断,文件生成的目录,需要注释掉相应的代码才能让其生成在当前的目录中
4.3)终端执行命令:
open $FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh
4.4)打开Flutter脚本后,注释掉以下代码:
5)生成、添加Framework
完成上述配置后,使用Xcode编译工程(Command+B),编译成功后,会在iOS工程文件夹中生成一个Flutter文件夹。
项目中添加Flutter文件的依赖。进入项目目录,选择Add Files to ‘xxx’依次去添加App.framework、engine、flutter_assets三个内容,
(注意:下述图中第2步,“.ios”是隐藏文件,可以使用快捷键“Command+Shift+.”来使之显示)
其中,添加App.framework、engine两项内容时,需要选择“Copy Items If needed”、“Create groups”
第三项,flutter_assets添加是,需要选择“Copy Items If needed”、“Create folder references”
上述操作完成后,文件夹目录是这样的,注意:flutter_assets是蓝色文件,engine是黄色文件
然后,添加App.framework、Flutter.framework。
注意:添加成功后将Embed选择为“Embed & Sign”,否则启动程序会崩溃。
6)修改Generated.xcconfig文件路径:
一般自动生成的Generated.xcconfig中的路径都是绝对路径,如果更改项目名称或位置,会找不到依赖的Flutter文件而导致编译失败。
解决方法:
将划红线部分的路径替换为”../”,表示在flutter_module上一级的文件夹中查找对应的路径,如图:
接下来就是在AppDeleaget.h、.m中添加相应的代码即可正常编译使用。
注意:通过这种方式集成后,去使用Flutter的插件时(如image_picker),插件无法生效。这是因为插件生效需要引用GeneratedPluginRegistrant文件,而目前这种方式并没有去引用,所以插件无法生效。
扩展:可以尝试通过cocoapod的方式,将flutter module中的GeneratedPluginRegistrant文件进行打包成framework,然后引用到Native项目中,这样的话这种集成方式也可以使用。
最后这一步具体如何去做,这里就不再去分析了,大家有兴趣的话可以在研究一下。
原文参考链接:https://www.jianshu.com/p/10237bf13789
2、参考闲鱼的集成方案,使用开源组件Flutter-boot集成(目前通过官网的操作步骤集成后无法使用)
1)下载和使用工具flutter-boot
开源地址:https://github.com/alibaba-flutter/flutter-boot
下载安装flutter-boot必须使用npm(前端的包管理工具),常使用brew去下载,结果不行~
使用npm的过程中可能会报错,大家可以自行百度,一般情况下重新对npm进行更新、启动等操作后就OK了。
若是还无法正常安装flutter-boot,可以尝试在命令前加上sudo命令:
sudo npm install -g flutter-boot
2)下载成功后,通过flutter-boot去集成环境
一般情况下,我们直接通过终端进入项目的根目录,如这里的"Flutter_Native_0328",里边包含了ios、android项目。
此时,在终端输入以下命令:
flutter-boot init
终端会提示输入flutter工程名称,我们这里直接输入"app"(经过各种尝试,之后将flutter module命名为“app”时,才不会报错,可能和集成工具内部的命名有关吧)
接着会提示输入关联的iOS工程等,其他的按照提示操作即可,完成后目录结构如图,多出了名称为app的flutter module
接下来的其他步骤按照官网知道即可。
但是我通过官网的知道去操作后,发现最终的Native项目(即ios项目)并没有和flutter关联起来,再下去就没法进行了,进行了各种资料的查找、各种尝试、或者在开源社区中求助,都未能能到有效的回应,暂时搁浅了......
不知道是不是中间哪里的操作姿势不对,有兴趣的可以在研究一下flutter-boot该怎么才能正确使用。
3、使用cocoapods集成
1)引入Flutter module模块
打开终端,进入项目“Flutter_Native_Mix_0330”的根目录,执行以下命令
cd Flutter_Native_Mix_0330
flutter create -t module flutter_module
完成后,会生成名为flutter_app的文件夹,其和ios、android项目同级
2)使用cocoapods
2.1)若当前项目中未使用cocoapods,则先进行安装https://cocoapods.org(若已安装,则跳过)
如果下载cocoapods失败,排查是不是“gem”工具的问题,一般都是简单的问题,可以自行百度解决
我目前使用的cocoapods版本为1.9.1,而Flutter SDK版本是1.12
2.2)若项目未使用cocoapods,则进行初始化(若已使用,则跳过)
进入ios项目文件夹,执行命令
pod init
完成后,会在ios项目文件夹下生成一个Podfile的文件。
2.3)接着,打开 Podfile 这个文件,添加以下代码
flutter_application_path = '../flutter_module/'
load File.join(flutter_application_path,'.ios','Flutter','podhelper.rb')
注意:这段代码得写到文件的顶部。这里使用相对路径,不要写绝对路径
例如,我的Podfile文件是这样的:
添加完成后,在终端输入以下命令:
pod install
如图:
会直接将Flutter的相关依赖和库的添加到iOS项目中。
2.4)接下来,打开ios项目,直接Command+B编译代码。
若当前没有导入插件,则直接编译成功。
若当前引入了插件,并使用GeneratedPluginRegistrant初始化插件,编译后,发现报错了,如下:
这是因为使用cocoapods导入了Flutter相关的库,需要在Build Setting->Linking->Other Linker Flags,添加 $(inherited)
这时候,能够看到,将Flutter相关的库导入了进来,插件也导入了。
此时,在编译工程,发现可以成功运行了。
3)添加新的插件
3.1)添加新的插件时,在pubspec.yaml中添加依赖后,进入flutter_module目录,在终端执行:
flutter pub get
会将插件下载下来,但是还不能立即使用。需要进入ios项目目录,终端输入命令:
pod install
执行这个命令,相当于更新了ios项目和flutter项目的依赖关系(新的插件引用)。更新过后,编译ios项目,新的插件就可以使用了。
ps:对于这种混合项目,建议使用flutter-boost插件来开发,这个插件是闲鱼的开源组件,会解决混合开发中遇到的大部分问题,很方便
4)项目路径修改为相对路径
若是多人开发时,或者自己重新拉取代码时,会重新命名本地项目文件夹名称,此时编译iOS项目会报错,如图:
从这个错误可以看出来,我们在集成的时候,一些编译路径自动编译为了绝对路径,我们根据报错的信息,找到了是在编译以下脚本文件时,报错了,如图:
我们根据路径找到对应的脚本文件后,打开发现“FLUTTER_APPLICATION_PATH”被定义为了绝对路径,如图:
其项目名称和路径是写死的,因此我们把这里的路径改为相对路径即可,如下:
"FLUTTER_APPLICATION_PATH=../flutter_module"
除此之外,我们还需要把这个路径下“../flutter_module/.ios/Flutter/Generated.xcconfig”,Generated.xcconfig文件中的绝对路径修改为相对路径。
至此,我们可以随意命名项目文件夹,程序都可以正常编译。
研究了许久集成完后,就大功告成了。
4、使用Xcode集成Flutter的Framework
除了上面的方法,你也可以创建必备的 frameworks,手动修改既有 Xcode 项目,将他们集成进去。当你组内其它成员们不能在本地安装 Flutter SDK 和 CocoaPods,或者你不想使用 CocoaPods 作为既有应用的依赖管理时,这种方法会比较合适。但是每当你在 Flutter module 中改变了代码,都必须运行 以下终端代码
首先,在已经创建了flutter_module的前提下,我们在ios的项目文件夹内新建文件夹Flutter,主要用来保存Flutter相关的framework。
接着,在终端执行以下命令:
cd flutter_module
flutter build ios-framework --output=/yourPath/ios/Flutter/
参考链接:https://flutter.cn/docs/development/add-to-app/ios/project-setup
https://flutter.cn/docs/development/add-to-app/android/project-setup