iOS集成flutter[一] 已有项目集成flutter资源包

首先,确保你的mac上面安装了flutter环境,如果没有,请参考入门: 在macOS上搭建Flutter开发环境

二是目前flutter提供的集成方案是cocoapods,所以项目必须是pod框架来搭建的,如果不是,请参考cocoapods的指南https://guides.cocoapods.org/using/getting-started.html

本篇内容都是根据flutter的github指南完成,主要参考了Add Flutter to existing apps,如果可能,建议先看完这边指南,尝试集成。本篇文章主要是记录集成中遇到的问题和解决方案,供读者参考。

这里简单归纳下指南中的步骤:

1、在iOS项目中创建flutter目录,并初始化flutter

1
2
$ cd some/path/ //这里的path是iOS项目文件夹,也就是说,最终的flutter文件夹和iOS项目平级
$ flutter create -t module my_flutter

2、在podfile中添加flutter相关命令,并执行pod命令

1
2
flutter_application_path = 'path/to/my_flutter/'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

执行pod install pod install

3、在xcode build phase中添加shell命令

1
2
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

4、 改造AppDelegate

1
2
3
4
5
6
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Only if you have Flutter Plugins
#include "AppDelegate.h"
@implementation AppDelegate
// This override can be omitted if you do not have any Flutter Plugins.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
[self.flutterEngine runWithEntrypoint:nil];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

5、 路由到FlutterViewController

1
2
3
4
FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:false completion:nil];
}

机会每个步骤都遇到了问题,下面一一描述

1、在iOS项目中创建flutter目录,并初始化flutter ,

这里是因为项目本身是集成了react-native的,而flutter又是一个独立的仓库,所以在react-native中增加了一个更新flutter代码的脚本,然后通过脚本来更新。

遇到的第二个问题是flutter项目因为是和android同时集成的,而使用了一个仓库的结果就是无法直接在目录中执行flutter create(因为该目录已存在),我的解决方案是flutter create tmp,然后将tmp中的iOS相关的文件复制到已存在的仓库中,主要是.ios文件夹,还有Flutter文件,还有pubspec.lock

2、在podfile中添加flutter相关命令,并执行pod命令

这里遇到的困难比较多,因为flutter为了保证bitCode等是关闭状态,执行了podhelper.rb的脚本,这个脚本中执行了post_install命令,如下:

1
2
3
4
5
6
7
8
9
10
11
#post_install do |installer|
# installer.pods_project.targets.each do |target|
# target.build_configurations.each do |config|
# config.build_settings['ENABLE_BITCODE'] = 'NO'
# xcconfig_path = config.base_configuration_reference.real_path
# File.open(xcconfig_path, 'a+') do |file|
# file.puts "#include \"#{File.realpath(File.join(framework_dir, 'Generated.xcconfig'))}\""
# end
# end
# end
#end

而我们的项目中也使用了这个命令,pod不支持多次使用,所以我修改了podhelper.rb文件,讲其中的代码,放到了iOS项目的podfile中。而因为.ios是ignore文件,所以我不得不将ios文件改为非ignore,这样带来的坏处是其中的Generated.xcconfig是生成的,记录的flutter的一些宏定义,而每个人的项目地址不同,所以需要其他使用者修改这个文件

3、在xcode build phase中添加shell命令

这个命令第一次执行非常慢,估计是需要将资源copy出来,后面就会快很多,但是因为和android的本地环境略有不同,所以有时候脚本会自动修改android的配置,需要后面想办法优化

4、改造AppDelegate

直接修改AppDelegate其实有些强耦合了,但是目前还看到更好的办法,我看咸鱼漏出来的一点代码是AppDelegate实现Flutter的一个协议,之后可以试试看

5、路由到FlutterViewController

这里首先遇到的问题是编译代码,提示[!] Unable to find a specification for path_provider depended upon by FlutterPluginRegistrant,查了文档,使用
cd my_flutter; flutter packages get可以解决

我们使用的新建一个viewController壳来加载这个FlutterViewController,因为可能还要做譬如打点等业务相关统计工作。