
Flutter 混合开发(二):iOS 项目集成 Flutter 模块详细指南
前一篇文章讲解了 Android 原生工程如何集成 Flutter 项目的具体过程,Flutter 混合开发(一):Android 项目集成 Flutter 模块详细指南 ,本篇将带着大家来一起学习原生 iOS 项目如何集成 Flutter。
因为每个版本的集成逻辑都是有差别的,所以这里交代下本篇文章的集成版本:
Flutter ( channel dev,v1.10.16 ) dart ( v2.7.0 ) Xcode ( v11.2 ) cocoapds ( 1.8.4 ) 假如 iOS 项目的路径是这样的:flutter/flutter_hybrid/iOS Project,那么我们需要在 iOS Project 上一层目录 flutter_hybrid 中创建 Flutter module。
cd flutter/flutter_hybrid/ flutter create -t module flutter_module 输入后控制台打印如下:
$ flutter create -t module flutter_module Creating project flutter_module... flutter_module/test/widget_test.dart (created) flutter_module/flutter_module.iml (created) flutter_module/.gitignore (created) flutter_module/.metadata (created) flutter_module/pubspec.yaml (created) flutter_module/README.md (created) flutter_module/lib/main.dart (created) flutter_module/flutter_module_android.iml (created) flutter_module/.idea/libraries/Flutter_for_Android.xml (created) flutter_module/.idea/libraries/Dart_SDK.xml (created) flutter_module/.idea/modules.xml (created) flutter_module/.idea/workspace.xml (created) Running "flutter pub get" in flutter_module... 1.2s Wrote 12 files. All done! Your module code is in flutter_module/lib/main.dart. 看到 All done 就表示我们项目创建好了。整个 module 目录和原生 Flutter 基本一样,主要就是 Android、iOS 的宿主工程和 lib 目录以及 pubspec.yaml 文件。
#添加 Flutter module 依赖
为 iOS 项目添加依赖需要使用 CocoaPods,如果你还没有用到 CocoaPods,可以参考https://cocoapods.org/上面的说明来安装 CocoaPods。
如果你的项目之前没有使用过 cocoapods,那么需要进行初始化生成 podfile 文件,进入 iOS 项目的根目录执行:
pod init 然后打开 podfile 文件,进行配置:
# 配置 flutter_application_path = '../flutter_module/' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'iOSFlutterHybrid' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! # Pods for iOSFlutterHybrid # 配置 install_all_flutter_pods(flutter_application_path) target 'iOSFlutterHybridTests' do inherit! :search_paths # Pods for testing end target 'iOSFlutterHybridUITests' do # Pods for testing end 配置添加好后在项目根目录运行以下命令进行安装:
pod install 控制台输出:
Analyzing dependencies Downloading dependencies Installing Flutter (1.0.0) Installing FlutterPluginRegistrant (0.0.1) Installing flutter_module (0.0.1) Generating Pods project Integrating client project [!] Please close any current Xcode sessions and use `iOSFlutterHybrid.xcworkspace` for this project from now on. Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed. [!] Automatically assigning platform `iOS` with version `13.2` on target `iOSFlutterHybrid` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`. 这里我们看到有三个依赖安装完成了。并提醒我们关闭当前项目,在根目录下面使用 iOSFlutterHybrid.xcworkspace 来打开运行项目。这里可能很多人在执行命令的时候会发现提示 0 个依赖完成。这里有可能是你的 Xcode 版本的问题。因为 Flutter 要求最低版本是 10.2 及以上。
当在 flutter_module/pubspec.yaml 中添加一个 Flutter 插件时,需要在 flutter_module 目录下运行:
flutter packages get 来刷新 podhelper.rb 脚本中的插件列表,然后在 iOS 目录下运行:
pod install 这样 podhelper.rb 脚本才能确保添加的插件和 Flutter.framework 能够添加到 iOS 项目中。
目前 Flutter 还不支持 Bitcode,所以集成了 Flutter 的 iOS 项目需要禁用 Bitcode。
在以下路径下找到 Bitcode 并禁用:
Build Settings->Build Options->Enable Bitcode flutter 以前的版本是需要添加 build phase 以构建 Dart 代码,但是最新的版本已经不需要添加了,可以自动构建。
Flutter 为我们提供了两种调用方式:FlutterViewController 和 FlutterEngine,FlutterEngine 在使用的时候会有一些问题,将在下文进行说明。
我们打开 ViewController.m 文件,在里面添加一个加载 flutter 页面的方法并且添加一个按钮看来调用:
#import "ViewController.h" #import <Flutter/Flutter.h> #import "AppDelegate.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button addTarget:self action:@selector(handleButtonAction) forControlEvents:UIControlEventTouchUpInside]; [button setTitle:@"加载 Flutter" forState:UIControlStateNormal]; [button setBackgroundColor:[UIColor blueColor]]; button.frame = CGRectMake(100, 100, 160, 60); [self.view addSubview:button]; } - (void)handleButtonAction{ FlutterViewController *flutterViewCOntroller=[FlutterViewController new]; //设置路由参数 [flutterViewController setInitialRoute:@"route2"]; [self presentViewController:flutterViewController animated:false completion:nil]; } @end 当我们运行项目点击加载 Flutetr 按钮时,将会调用 Flutter 页面。和 Android 项目集成一样,这里的 setInitialRoute 可以设置一个 json 数组来传递需要交互的参数。并在 Flutter 中使用 window.defaultRouteName 来获取传递的参数。
我们需要在 AppDelegate 中对 FlutterEngine 进行初始化。打开 AppDelegate.h 文件:
#import <UIKit/UIKit.h> #import <Flutter/Flutter.h> @interface AppDelegate : FlutterAppDelegate @property (nonatomic,strong) FlutterEngine *flutterEngine; @end 在打开 AppDelegate.m 文件:
// 如果你需要用到 Flutter 插件时 #import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> #include "AppDelegate.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil]; [self.flutterEngine runWithEntrypoint:nil]; [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine]; //如果你需要用到 Flutter 插件时 return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end 然后在 ViewController.m 文件定义的 handleButtonAction 中调用:
- (void)handleButtonAction{ FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine]; FlutterViewController *flutterViewCOntroller= [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil]; [flutterViewController setInitialRoute:@"route2"]; [self presentViewController:flutterViewController animated:false completion:nil]; } 当我们运行项目点击加载 Flutter 按钮时,将会调用 Flutter 页面。前文讲到使用 FlutterEngine 会有问题,就是我们 setInitialRoute 传递的参数在 flutter 中永远获取到的都是 “/” ,这个是 Fltter SDK 的一个 Bug,所以如果必须依赖 setInitialRoute,还是使用 FlutterViewController 的形式来加载 Flutter 模块。
大家在写纯 Flutter 应用的时候,知道是有热重启 /重新加载功能的,但是在做混合开发的过程中,你会发现热重启 /重新加载功能失效了。那么如何在混合开发中开启热重启 /重新加载功能呢?
$ flutter attach Waiting for a connection from Flutter on Android SDK built for x86... 复制代码此时就在等待设备的连接。这里要注意的是,如果电脑连接了多台设备需要使用 -d 命令来指定一台设备,参数为设备的 id。
flutter attach -d '你的设备 id' 然后启动我们的应用会看到控制台输出:
Done. Syncing files to device Android SDK built for x86... 1,393ms To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R". An Observatory debugger and profiler on Android SDK built for x86 is available at: http://127.0.0.1:59354/zRsDBfpesrk=/ For a more detailed help message, press "h". To detach, press "d"; to quit, press "q". 这样就表示我们连接成功了。在输出的日志中也告诉了我们如何使用热重启 /重新加载功能。
在 Terminal 中输入以下命令:
r : 热加载; R : 热重启; h : 获取帮助; d : 断开连接; q : 退出; 这里的的 d 和 q 的命令都有退出调试,区别在于 d 命令只是单纯的断开而 q 命令会将应用退到后台。
同样在混合开发过程中我们如何调试 dart 代码呢?
接下来就可以像调试普通 Flutter 项目一样来调试混合开发模式下的 Dart 代码了。
本文主要是讲解了 iOS 集成 Flutter 项目的步骤,其中也遇到了一些问题,由于我的 Xcode 版本较低,在集成的过程中 iOS 项目的依赖一直失败。最后才发现是 Xcode 的版本问题。这里花费了很多时间去排查问题,所以大家在集成的过程中有问题可以关注公众号加我微信,给我留言,我会帮助大家解决问题。
全部 Demo 源码已经上传到后台,关注公众号回复「混合开发」即可获得下载链接。
如果你觉得文章还不错,请大家点赞分享下,你的肯定是对我最大的鼓励和支持。
1 so898 2019-12-13 16:27:18 +08:00 iOS 上的 Flutter 混合开发不叫 iOS 项目集成 Flutter 模块,是 Flutter 项目添加 iOS 项目代码,集成 iOS 项目 |