上一期我们聊了下<Flutter与原生项目Android混合开发的集成>,移动端的开发IOS自然是少不了,那么今天我们来聊一聊Flutter与原生项目IOS混合开发的集成。
还是说一下前提吧:大家在项目的开发中除了那种新立项的而且规模较小的项目可能是纯Flutter开发,大部分在项目中都可能是混合开发的模式,而且是以原生为主Flutter为辅的开发模式,很大部分原因就是你原来原生的项目不可能马上全部用Flutter重写一遍,而且是集成一部分Flutter的页面而已,像这种情况的话那么混合开发就是必须的,那么我们今天就先来聊聊怎么在原生项目去集成Flutter
我们还是回到最初看看一个完成Flutter项目是什么样的:
Pasted Graphic.png如图一个新建的Flutter项目里面就包括了他的Android/IOS宿主,如果是Flutter为主原生为辅的开发可以就在这里面进行,而且这种项目适合一个全新的项目,就像上面提到的那样,不适合那种原生项目就很成熟了再集成Flutter框架的情况
如果我们要爱原有成熟的原生项目里面再集成Flutter的话首先要创建一个Flutter Module,如下:
Pasted Graphic 1.png创建的项目路径要选择好,一般我们会与原生项目目录并排,如下:
Pasted Graphic 2.pngFlutter Module已经创建好了,我们来看看一个Flutter Module大概是什么样子的,如图:
Pasted Graphic 3.png是不是与一个Flutter Project很像啊,是的可以说本质没有什么变化,Flutter Module依然是一个可以运行的项目,你可以进入该目录下运行 flutter run 就可以看到运行效果,上面我们说过一个Flutter的Project需要他们原生的宿主才能运行,Flutter Module也一样他们也需要原生宿主,就是红框里面的部分,不过这里面不建议你去修改(这一点不像Flutter Project)所以他们的文件夹在mac里面隐藏的
那么我们今天看看IOS项目怎么去集成:
目前为止有两种方案可以将flutter集成进iOS项目中
-
使用CocoaPods和已安装的Flutter SDK(推荐使用这一种)。
-
为Flutter引擎,已编译的Dart代码和所有Flutter插件创建生成 frameworks,手动在Xocde中嵌入这些frameworks。
-
第一种方案的优点:该方案是Flutter官方推荐的方案;集成过程相对简单;
-
第一种方案的缺点: 需要求项目中工程师的电脑上都要配置Flutter环境;并且 iOS项目里面要掺着一些Flutter相关的项目工程代码(不过这个不能说为一个明显的缺点)
-
第二种方案的优点:如果团队成员无法在本地安装Flutter SDK
-
第二种方案的缺点:集成步骤过于复杂;而且Flutter相关的代码有改动(哪怕是你想升级Flutter框架)则需要 flutter build ios 生成新的Frameworks集成在项目中;
所以我们今天就只介绍第一种集成的方式:使用CocoaPods和已安装的Flutter SDK,目前该版本的Flutter对于这种集成方式做得更加的优化了,目前只需要一个步骤即可:
我们只需要在iOS工程的podfile文件中添加如下命令:
# Flutter
flutter_application_path = '../flutter_module/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'XXXAPP' do
use_frameworks!
# Flutter
install_all_flutter_pods(flutter_application_path)
end
就可以一次性将flutter的编译的库由此依赖进入iOS宿主项目中, 不用再每次去在Xcode->Build Phases中去添加设置脚本文件路径等繁琐操作,简化了集成的步骤。
我做过实验你只要在Flutter项目修改的代码只需要在Xcode运行他的宿主项目就可以,我想这个是因为你在Xcode点击Run的时候他也会编译Flutter里面的代码,这样编译运行就会变得方便很多
现在我们需要开发一个Flutter页面去验证是否集成成功
IOS混合开发的页面也分两种情况:
-
一种是从原生跳转到一个Flutter页面,
-
一种是Flutter与原生混合在一个页面,
我们先看第一种的情况:
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlutterHybird',
theme: ThemeData(
primarySwatch: Colors.blue,
),
//window.defaultRouteName可以接收从Native传过来的参数
home: _widgetForRoute(window.defaultRouteName),
);
}
}
Widget _widgetForRoute(String route) {
switch (route) {
case 'route1':
return Center(
child: Text("route1"),
);
case 'route2':
return Center(
child: Text("route2"),
);
default:
return Center(
child: Text('route3’),
);
}
}
其中通过window.defaultRouteName可以按照Native传递过来的参数来选择启动的Widget
我们再开发一个Native的页面用于承载上面的Flutter,用于被原生页面跳转
#import "ViewController.h"
#import "AppDelegate.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(100, 100, 200, 100)];
[button setTitle:@"Click" forState:UIControlStateNormal];
[button addTarget:self action:@selector(button_click) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)button_click {
FlutterViewController *flutterViewController = [[FlutterViewController alloc] init];
[flutterViewController setInitialRoute:self.inputParams];
[self.navigationController pushViewController:flutterViewController animated:YES];
}
然后在原生进行跳转即可,通过setInitialRoute传递参数,对应就是Flutter的window.defaultRouteName来获取参数
是的你没有看错,就是这样就可以了,他内部帮你做了很多处理,例如默认找到了Flutter的main.dark,默认执行里面的main方法,这种情况再ReactNative是想都不敢想的,因为我们知道ReactNative的JS module至少是要指定跳转的moduleName的,因为在ReactNative里面每个module都是需要注册的,这个在Flutter没有这个步骤
initialRoute从名称上看起来是Flutter提供给我们进行Native与Flutter交互的路由跳转的,
但是实际上他就是一个字符串,我们可以传递一个路由名称,有时候我们也可以通过这个参数传递一个字符串,然后在Flutter端进行解析,就像上面一样,下面我们来一个传递路由页面的例子来使用他
我们先指定一个注册了路由的Flutter页面(因为只有你注册了路由才知道要跳转到哪个路由),如下:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
'one_page':(context){
return OnePage();
},
'two_page':(context){
return TwoPage();
}
},
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
然后我们使用initialRoute传递跳转的路由页面即可:
FlutterViewController *flutterViewController1 = [[FlutterViewController alloc] init];
[flutterViewController1 setInitialRoute:@“one_page”];
[self.navigationController pushViewController:flutterViewController animated:YES];
OK 上面聊了下Flutter里面简单的页面跳转,我们再来聊聊在IOS原生页面中嵌入FlutterUI组件:
- 第一种方式非常的简单,直接把FlutterViewController当做子VC集成在主ViewController里面即可如下:
FlutterViewController *fluvc = [[FlutterViewController alloc]init];
[self addChildViewController:fluvc];
fluvc.view.frame = self.view1.bounds;
[fluvc didMoveToParentViewController:self];
[self.view1 addSubview:fluvc.view];
[self.navigationController pushViewController:fluvc animated:YES];
这种方式非常的简单,也是我非常推荐的一种方式
- 第二种方式针对于Xib或者StoryBoard开发的情况操作也是非常的简单,这种方式也是我从网上看到的,如下:
里面拖拉了两个Container View ,与两个ViewController,两个Container View与两个ViewController通过Segue相连,Segue的连接方式为Embed即可,这样的话你的XIB或者StoryBoard上面也可以通过拖拉控件去与Flutter页面混合集成
最后说一说Flutter页面的性能问题,加载 FlutterActivity 页面时明显看到一段时间的黑屏,这段时间主要是启动 Flutter 引擎(FlutterEngine),Flutter 引擎启动的时间在不同手机上不同,每一个 FlutterActivity 页面都会重新启动一个Flutter 引擎,所以不要在一个项目中创建多个 FlutterActivity(或者启动多个 FlutterActivity 实例),否则内存会越来越大,为了减少 FlutterActivity 页面的延迟时间和多个 FlutterActivity 实例内存一直增长问题,我们可以缓存 Flutter 引擎(FlutterEngine),在启动 App 的时候先启动 Flutter 引擎,然后使用缓存的引擎加载页面,通常将其放在 AppDelegate 中:
import UIKit
import Flutter
@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
flutterEngine.run();
return super.application(application, didFinishLaunchingWithOptions: launchOptions);
}
}
使用的时候再取出来就可以了:
@objc func showFlutter() {
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController =
FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
present(flutterViewController, animated: true, completion: nil)
}
好了,我们的《Flutter与原生混合开发项目集成之IOS篇》已经到结尾了,相信上面的内容还是比较简单易懂的,如果你有什么问题可以给我留言,欢迎大家一起讨论,如果想看<Flutter与原生项目Android混合开发的集成>的话可以点击这里,Flutter是一个非常庞大的框架,希望接下来的学习中可以输出更多高质量的文章,好了我们一起期待吧···
网友评论