Flutter iOS跳转FlutterViewController 方案尝试

原生跳转FlutterViewController的几种方式

在将Flutter项目接入到iOS原生项目中,需要使用FlutterViewController进行跳转展示,目前官方给出了三种跳转方式:

  1. 单个Flutter页面
    官方推荐在程序启动时,先预热FlutterEngine,也就是在AppDelegate中先初始化FlutterEnging,具体的代码是: OC代码:
objectivec 复制代码
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];//FlutterEngine 名,每个Flutter对应的名称
  // Runs the default Dart entrypoint with a default Flutter route.
  [self.flutterEngine run];//启动FlutterEngine
  // Connects plugins with iOS platform code to this app.
  [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];//如果使用了插件,则需要使用对应的FlutterEngine注册

Swift代码:

php 复制代码
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
flutterEngine.run();
    // Connects plugins with iOS platform code to this app.
    GeneratedPluginRegistrant.register(with: self.flutterEngine);
    return super.application(application, didFinishLaunchingWithOptions: launchOptions);

然后在需要跳转到Flutter界面的时候直接将已经加载好的FlutterEngine传入进FlutterViewController中即可: OC代码:

ini 复制代码
    FlutterEngine *flutterEngine = ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
    FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
    [self presentViewController:flutterViewController animated:YES completion:nil];

Swift代码:

swift 复制代码
    let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
    let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
    present(flutterViewController, animated: true, completion: nil)

这种的好处是,由于FlutterEngine已经提前预热加载,在进行跳转的时候几乎和原生界面跳转无差异,用户体验良好。

  1. 隐式FlutterEngine创建FlutterViewController
    OC代码:
ini 复制代码
FlutterViewController *flutterViewController =
      [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
  [self presentViewController:flutterViewController animated:YES completion:nil];

Swift代码:

php 复制代码
    let flutterViewController = FlutterViewController(project: nil, nibName: nil, bundle: nil)
    present(flutterViewController, animated: true, completion: nil)

这种情况下,Flutter会在跳转FlutterViewController的时候创建FlutterEngine,虽然操作方便了,但是在跳转的时候会有明显的卡顿情况,用户体验不友好。

  1. 多个Flutter页面时,使用FlutterEngineGroup 代码:
ini 复制代码
创建EngineGroup
self.flutterEngineGroup = [[FlutterEngineGroup alloc] initWithName:@"flutterGroupName" project:NULL];

使用时:

objectivec 复制代码
FlutterEngine *engine = [[SVFlutterEngine shared].engineGroup makeEngineWithEntrypoint:nil libraryURI:nil initialRoute:nil];//使用Group创建一个FlutterEngine
FlutterViewController *flutterVC = [[FlutterViewController alloc]initWithEngine:engine nibName:nil bundle:nil];
[self presentViewController:flutterVC animated:YES completion:nil];

这种效果比第二种好一些,但是也会有稍微的卡顿,感觉就是不彻底。App要商用,肯定不能给这种让用户去体验。效果肯定是第一种最佳,但是第一种会引入新的问题,如果app中仅跳转一个固定页面作为根页面那么到还好,如果需要改变initialRoute页面,则需要寻找额外的方式。

Flutter 设置initialRoute的几种方式

目前Flutter给出这么几种方式设置跳转到FlutterView的方式,

  1. 在进行FlutterEngine初始化的时候进行设置,方法如下:
ini 复制代码
self.flutterEngine = [[FlutterEngine alloc]initWithName:@"flutter_engine"];
[self.flutterEngine runWithEntrypoint:nil libraryURI:nil initialRoute:@"/home"];

设置路由为/home,需要先在Flutter 的MaterialApp的参数getPages中设置路由 2. 隐式创建FlutterEngine的时候使用FlutterViewController初始化方法设置initialRoute

go 复制代码
FlutterViewController *flutterVC = [[FlutterViewController alloc]initWithProject:nil initialRoute:@"/home" nibName:nil bundle:nil];
  1. 使用EngineGroup创建Flutter Engine的时候也有对应的方法
go 复制代码
[engineGroup makeEngineWithEntrypoint:nil libraryURI:nil initialRoute:@"/home"];

但是需要注意的是,每个FlutterEngine仅能设置一次initialRoute,如果你的app有多个需要从原生直接跳Flutter页面的话,那么按照目前的情况你可能得维护多个FlutterEngine的缓存和生命周期。

这里顺带提一下,Flutter中的Entrypoint参数和libraryURI参数,这两个参数可以让你在启动Flutter界面是指定启动入口,其中Entrypoint指定启动参数名,libraryURI指定启动文件地址:

csharp 复制代码
//正常不设置Entrypoint和libraryURI情况下
void main() => runApp(const MyApp());
设置Entrypoint:routeParse libraryURI:nil时进这里,如果这个入口写在其他的文件里则在libraryURI参数中传入文件路径
@pragma('vm:entry-point')
void routeParse(){
  debugPrint("ssl current route1:routeParse");
  runApp(const MyApp());
}

最终解决方案

1、用空间换时间:提前缓存多个与FlutterEngine,需要跳转的时候使用对应的FlutterEngine跳转 2、使用FlutterViewController 自带的pushRoute,每次进入的时候传入对应需要push的路由,比如:

定义路由:

csharp 复制代码
static const root_router = '/home';
static const route_add = '/add';
static List<GetPage> pages = [
  GetPage(name: root_router, page: ()=> const SVHome()),
  GetPage(name: route_add, page: ()=> const SVAdd()),  
];
//初始化引擎根视图
_flutterEngine = [[FlutterEngine alloc]initWithName:@"flutter_engine"];
[self.flutterEngine runWithEntrypoint:nil libraryURI:nil initialRoute:@"/home"];

//在FlutterViewController 中调用,跳转到add路由
[self pushRoute:@"/add"];

这种方法和直接跳转到根视图从感官上几乎无感,可以很好的解决需要缓存多个FlutterEngine的问题,但是需要注意的是:当你从add界面直接退出Flutter界面时,需要先返回根视图,否则下次会从add界面push到新页面。 这个需要自己维护了。

相关推荐
笑尘pyrotechnic7 小时前
DocC的简单使用
ios·objective-c
谈吐大方的鹏sir8 小时前
SwiftUI-Text组件学习
ios
你听得到118 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构
不自律的笨鸟9 小时前
iOS 26,双版本更新来了
ios·iphone
RaidenLiu13 小时前
Flutter Shader预热技术解析与实践指南
flutter·前端框架
归辞...14 小时前
「iOS」————消息传递和消息转发
ios
他们都不看好你,偏偏你最不争气1 天前
iOS —— 天气预报仿写总结
ios
ITfeib1 天前
Flutter基础
flutter
RaidenLiu1 天前
RepaintBoundary是什么?怎么用?
flutter
白玉cfc1 天前
【iOS】网易云仿写
ui·ios·objective-c