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到新页面。 这个需要自己维护了。

相关推荐
DisonTangor2 小时前
苹果发布iOS 18.2首个公测版:Siri接入ChatGPT、iPhone 16拍照按钮有用了
ios·chatgpt·iphone
- 羊羊不超越 -2 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
problc8 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
lqj_本人17 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
2401_8658548818 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
lqj_本人20 小时前
Flutter&鸿蒙next 状态管理框架对比分析
flutter·华为·harmonyos
起司锅仔1 天前
Flutter启动流程(2)
flutter
hello world smile1 天前
最全的Flutter中pubspec.yaml及其yaml 语法的使用说明
android·前端·javascript·flutter·dart·yaml·pubspec.yaml
lqj_本人1 天前
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
flutter·harmonyos
iFlyCai1 天前
极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果
flutter