22*:Flutter之原生和Flutter交互
问题
目录
预备
正文
flutter MyApp界面里
1、flutter点击事件之后 iOS跳转界面
2、flutter传map类型参数给iOS进行相应交互
3、在flutter界面的事件响应之后,iOS返回响应数据给flutter
iOS代码如下:
// // ViewController.m // FlutterD // // Created by 侯佳男 on 2018/10/30. // Copyright © 2018年 侯佳男. All rights reserved. // #import "ViewController.h" #import "TargetViewController.h" #import <Flutter/Flutter.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)pushFlutterViewController { FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil]; // 设置路由名字 跳转到不同的flutter界面 /*flutter代码*/ /* import 'dart:ui'; void main() => runApp(_widgetForRoute(window.defaultRouteName)); Widget _widgetForRoute(String route) { switch (route) { case 'myApp': return new MyApp(); case 'home': return new HomePage(); default: return Center( child: Text('Unknown route: $route', textDirection: TextDirection.ltr), ); } } */ [flutterViewController setInitialRoute:@"myApp"]; __weak __typeof(self) weakSelf = self; // 要与main.dart中一致 NSString *channelName = @"com.pages.your/native_get"; FlutterMethodChannel *messageChannel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:flutterViewController]; [messageChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { // call.method 获取 flutter 给回到的方法名,要匹配到 channelName 对应的多个 发送方法名,一般需要判断区分 // call.arguments 获取到 flutter 给到的参数,(比如跳转到另一个页面所需要参数) // result 是给flutter的回调, 该回调只能使用一次 NSLog(@"method=%@ \narguments = %@", call.method, call.arguments); // method和WKWebView里面JS交互很像 // flutter点击事件执行后在iOS跳转TargetViewController if ([call.method isEqualToString:@"iOSFlutter"]) { TargetViewController *vc = [[TargetViewController alloc] init]; [self.navigationController pushViewController:vc animated:YES]; } // flutter传参给iOS if ([call.method isEqualToString:@"iOSFlutter1"]) { NSDictionary *dic = call.arguments; NSLog(@"arguments = %@", dic); NSString *code = dic[@"code"]; NSArray *data = dic[@"data"]; NSLog(@"code = %@", code); NSLog(@"data = %@",data); NSLog(@"data 第一个元素%@",data[0]); NSLog(@"data 第一个元素类型%@",[data[0] class]); } // iOS给Flutter返回值 if ([call.method isEqualToString:@"iOSFlutter2"]) { if (result) { result(@"返回给flutter的内容"); } } }]; [self.navigationController pushViewController:flutterViewController animated:YES]; } // 点击跳转到flutter界面 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self pushFlutterViewController]; } @end
flutter代码
import 'dart:ui' as ui; // 调用window拿到route判断跳转哪个界面 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_module/HomePage.dart'; void main() => runApp(_widgetForRoute(ui.window.defaultRouteName)); // 根据iOS端传来的route跳转不同界面 Widget _widgetForRoute(String route) { switch (route) { case 'myApp': return new MyApp(); case 'home': return new HomePage(); default: return Center( child: Text('Unknown route: $route', textDirection: TextDirection.ltr), ); } } class MyApp extends StatelessWidget { Widget _home(BuildContext context) { return new MyHomePage(title: 'Flutter Demo Home Page'); } @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), routes: <String, WidgetBuilder>{ "/home":(BuildContext context) => new HomePage(), }, home: _home(context), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { // 创建一个给native的channel (类似iOS的通知) static const methodChannel = const MethodChannel('com.pages.your/native_get'); _iOSPushToVC() async { await methodChannel.invokeMethod('iOSFlutter', '参数'); } _iOSPushToVC1() async { Map<String, dynamic> map = {"code": "200", "data":[1,2,3]}; await methodChannel.invokeMethod('iOSFlutter1', map); } _iOSPushToVC2() async { dynamic result; try { result = await methodChannel.invokeMethod('iOSFlutter2'); } on PlatformException { result = "error"; } if (result is String) { print(result); showModalBottomSheet(context: context, builder: (BuildContext context) { return new Container( child: new Center( child: new Text(result, style: new TextStyle(color: Colors.brown), textAlign: TextAlign.center,), ), height: 40.0, ); }); } } @override Widget build(BuildContext context) { return new Scaffold( body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new FlatButton(onPressed: () { _iOSPushToVC(); }, child: new Text("跳转ios新界面,参数是字符串")), new FlatButton(onPressed: () { _iOSPushToVC1(); }, child: new Text("传参,参数是map,看log")), new FlatButton(onPressed: () { _iOSPushToVC2(); }, child: new Text("接收客户端相关内容")), ], ), ), ); } }
iOS主动和flutter交互
flutter MyApp界面里
1、初始化flutter界面时候iOS传值给flutter
iOS代码
// // TargetViewController.m // FlutterD // // Created by 侯佳男 on 2018/10/30. // Copyright © 2018年 侯佳男. All rights reserved. // #import "TargetViewController.h" #import <Flutter/Flutter.h> @interface TargetViewController () <FlutterStreamHandler> @end @implementation TargetViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"TargetViewController"; self.view.backgroundColor = [UIColor whiteColor]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)pushFlutterViewController_EventChannel { FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil]; flutterViewController.navigationItem.title = @"Demo"; [flutterViewController setInitialRoute:@"home"]; // 要与main.dart中一致 NSString *channelName = @"com.pages.your/native_post"; FlutterEventChannel *evenChannal = [FlutterEventChannel eventChannelWithName:channelName binaryMessenger:flutterViewController]; // 代理FlutterStreamHandler [evenChannal setStreamHandler:self]; [self.navigationController pushViewController:flutterViewController animated:YES]; } #pragma mark - <FlutterStreamHandler> // // 这个onListen是Flutter端开始监听这个channel时的回调,第二个参数 EventSink是用来传数据的载体。 - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)events { // arguments flutter给native的参数 // 回调给flutter, 建议使用实例指向,因为该block可以使用多次 if (events) { events(@"push传值给flutter的vc"); } return nil; } /// flutter不再接收 - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments { // arguments flutter给native的参数 NSLog(@"%@", arguments); return nil; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self pushFlutterViewController_EventChannel]; } @end
flutter代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class HomePage extends StatefulWidget { _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { // 注册一个通知 static const EventChannel eventChannel = const EventChannel('com.pages.your/native_post'); // 渲染前的操作,类似viewDidLoad @override void initState() { super.initState(); // 监听事件,同时发送参数12345 eventChannel.receiveBroadcastStream(12345).listen(_onEvent,onError: _onError); } String naviTitle = 'title' ; // 回调事件 void _onEvent(Object event) { setState(() { naviTitle = event.toString(); }); } // 错误返回 void _onError(Object error) { } @override Widget build(BuildContext context) { return new MaterialApp( home: new Material( child: new Scaffold( body: new Center( child: new Text(naviTitle), ), ), ), ); } }
注意