原生跳转FlutterViewController的几种办法

在将Flutter项目接入到iOS原生项目中,需求运用FlutterViewController进行跳转展现,现在官方给出了三种跳转办法:

  1. 单个Flutter页面
    官方推荐在程序发动时,先预热FlutterEngine,也便是在AppDelegate中先初始化FlutterEnging,具体的代码是:
    OC代码:
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代码:

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代码:

    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代码:

    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代码:
FlutterViewController *flutterViewController =
      [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
  [self presentViewController:flutterViewController animated:YES completion:nil];

Swift代码:

    let flutterViewController = FlutterViewController(project: nil, nibName: nil, bundle: nil)
    present(flutterViewController, animated: true, completion: nil)

这种情况下,Flutter会在跳转FlutterViewController的时分创立FlutterEngine,虽然操作方便了,可是在跳转的时分会有显着的卡顿情况,用户体会不友好。

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

运用时:

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初始化的时分进行设置,办法如下:
self.flutterEngine = [[FlutterEngine alloc]initWithName:@"flutter_engine"];
[self.flutterEngine runWithEntrypoint:nil libraryURI:nil initialRoute:@"/home"];

设置路由为/home,需求先在Flutter 的MaterialApp的参数getPages中设置路由
2. 隐式创立FlutterEngine的时分运用FlutterViewController初始化办法设置initialRoute

FlutterViewController *flutterVC = [[FlutterViewController alloc]initWithProject:nil initialRoute:@"/home" nibName:nil bundle:nil];
  1. 运用EngineGroup创立Flutter Engine的时分也有对应的办法
[engineGroup makeEngineWithEntrypoint:nil libraryURI:nil initialRoute:@"/home"];

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

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

//正常不设置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的路由,比如:

界说路由:

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