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

相关推荐
嵩风抚28 分钟前
一款HK银行APP的业务+技术
android·flutter·react native·html5
00后程序员张3 小时前
怎么用 Egret(白鹭引擎)打包 iOS 应用并上架 App Store?
android·ios·小程序·https·uni-app·iphone·webview
不羁的木木3 小时前
给鸿蒙 App 增加广播收发能力 —— flutter_broadcasts 的鸿蒙使用指南
flutter·harmonyos
风雨_3 小时前
show-me + grill-me 结合使用总结
ios
不羁的木木3 小时前
给鸿蒙 App 增加打开外部网页能力 —— flutter_web_browser 的鸿蒙使用指南
前端·flutter·harmonyos
安好说AI4 小时前
Flutter 三方库 sound_mode 的鸿蒙化适配指南:免权限读取与受限写入的契约对齐
flutter·harmonyos·鸿蒙
●VON4 小时前
Flutter 鸿蒙 disk_space_2 1.0.13 使用实战:下载前检查磁盘空间
flutter·华为·harmonyos·鸿蒙
●VON14 小时前
Flutter 鸿蒙插件适配实战:用 device_screen_brightness 2.0.0 控制并监听屏幕亮度
flutter·华为·harmonyos
风早爽太1 天前
Flutter 开发笔记:share_plus 分享插件
笔记·flutter
●VON1 天前
Flutter 鸿蒙插件适配实战:用 boot_time_plugin 1.0.0 读取启动时间与运行时长
flutter·华为·harmonyos