本文章是参考 Flutter 官方提供的 demo 实现原生与 flutter 相互调用、传值。
下面是自己写的 demo 和代码解读,做个笔记方便以后查阅。
1、创建 flutter module
在原有项目的根目录,一般是 Podfile 文件的上一级目录下面,执行下面命令
flutter create -t module flutter_module
如果 flutter 命令不存在,请自行安装 flutter 环境,如果确定环境已经安装,需要检查下环境变量是否正确配置。
2、在 Podfile 中的改动
在 Podfile 中添加如下代码
flutter_application_path = '../flutter_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)
如果项目中有多个 target,如 targetA 和 targetB ,只需要在 targetA 中添加 flutter module 可以在 Podfile 中添加如下代码
flutter_application_path = '../flutter_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'targetA' do
install_all_flutter_pods(flutter_application_path)
end
target 'targetB' do
end
然后到对应的 Podfile 所在目录执行下面命令,这样 flutter module 就基本构建好了
pod install
3、在 AppDelegate 中的改动
先在 .h
引入对应的 flutter 头文件 #import
,添加代码,将 AppDelegate 的父类从 UIResponder
改为 FlutterAppDelegate
,再定义一个引擎组
@property (nonatomic,strong) FlutterEngineGroup * engines;
然后在 .m
文件中初始化对应的属性,name 参数是引擎组在线程中的名字,这个随意
self.engines = [[FlutterEngineGroup alloc] initWithName:@"my flutter engines" project:nil];
4、在需要调用 flutter 的类中
先添加下面的代码
@property (nonatomic, strong) FlutterEngine * flutterEngine; // flutter 引擎
@property (nonatomic, strong) FlutterMethodChannel * channel; // 用于传值和回调
@property (nonatomic, strong) NSNumber * count; // 将要传入到 flutter 的值
然后初始化上面定义的属性
self.count = @3;
FlutterEngineGroup * engines = ((AppDelegate*)[UIApplication sharedApplication].delegate).engines;
FlutterEngine * newEngine = [engines makeEngineWithEntrypoint:@"twInitParameter" libraryURI:nil];
self.flutterEngine = newEngine;
self.channel = [FlutterMethodChannel methodChannelWithName:@"multiple-flutters" binaryMessenger:self.flutterEngine.binaryMessenger];
twInitParameter
参数是对应到 flutter 里面初始化的一个方法,可以传 nil ,下面 flutter 里面的代码会解释,multiple-flutters
是一个通讯标识,flutter 代码中会用到。
下面的代码是给 flutter 传值,并添加回调函数,完成原生与 flutter 的双向通讯
// 给 flutter 发送一个 setCount 的消息,参数为 self.count
[self.channel invokeMethod:@"setCount" arguments: self.count];
@weakify(self);
[self.channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
@strongify(self);
// 监听 flutter 传来名字为 incrementCount 的回调,收到回调后 self.count 加1,然后再给 flutter 发送一个 setCount 的消息,参数为 self.count
if ([call.method isEqualToString:@"incrementCount"]) {
int count = self.count.intValue;
count++;
self.count = [NSNumber numberWithInt:count];
[self.channel invokeMethod:@"setCount" arguments: self.count];
} else {
NSLog(@"异常方法调用");
}
}];
下面是原生跳转到 flutter 界面的代码:
FlutterViewController * fvc = [[FlutterViewController alloc] initWithEngine:self.flutterEngine nibName:nil bundle:nil];
[self.navigationController pushViewController:fvc animated:YES];
5、flutter main.dart 中的代码
void main() => runApp(MyApp(Colors.blue));
@pragma('vm:entry-point')
void twInitParameter() => runApp(MyApp(Colors.red));
class MyApp extends StatelessWidget {
MyApp(this.color);
final Color color;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: this.color,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _counter = 0;
MethodChannel _channel;
@override
void initState() {
super.initState();
// 创建名字为 multiple-flutters 的监听方法,接受来自原生的信息
_channel = MethodChannel('multiple-flutters');
_channel.setMethodCallHandler((MethodCall call) async {
if (call.method == "setCount") {
// 收到回调后修改界面显示值
setState(() {
_counter = call.arguments as int;
});
} else {
throw Exception('not implemented ${call.method}');
}
});
}
void _incrementCounter() {
// 给原生发送名字为 incrementCount 的消息
_channel.invokeMethod("incrementCount", _counter);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
TextButton(
onPressed: _incrementCounter,
child: Text('Add'),
),
TextButton(
onPressed: () {
_channel.invokeMethod("next", _counter);
},
child: Text('Next'),
),
],
),
),
);
}
}
可以看出初始化方法有两个,twInitParameter
就是上面 self.channel
初始化时的参数。
6、总结下原生跳转到 flutter 后,的逻辑顺序
- 通过引擎初始化时传的不同值,调用对应的初始化方法
- 点击 flutter 界面上的 add 按钮,flutter 通知原生做 count++
- 原生完成 count++ 后,通知 flutter 刷新界面显示值
7、flutter model 官方示例
下载好后需要到 flutter_module 目录下执行
flutter pub get
然后到对应的 Podfile 所在目录执行
pod install
最后运行 .xcworkspace 文件。