上篇咱們介紹了 Flutter 模塊集成到已有的項目工程,接下來咱們看看 Native 跟 Flutter 間的交互問題。ios
交互通訊objective-c
Flutter 與原生之間的通訊依賴靈活的消息傳遞方式:app
1,Flutter 部分經過平臺通道將消息發送到其應用程序的所在的宿主環境(原生應用)。async
2,宿主環境經過監聽平臺通道,接收消息。而後它會調用平臺的 API,響應 Flutter 發送的消息。ide
Flutter主動 調用 宿主環境設計
在 Flutter 中經過 MethodChannel 的 API 能夠發送與方法相對於的消息,宿主環境 iOS 中經過 FlutterMethodChannel 接受方法的調用並返回結果。code
Flutter 須要引入 services.dart
模塊才能夠使用 MethodChannelorm
import 'package:flutter/services.dart';
Flutter 中的調用代碼事件
const methodChannel = const MethodChannel("com.pages.flutter/call_native");
RaisedButton( child: Text("call_native_method_no_params"), onPressed: (){ methodChannel.invokeMethod("call_native_method_no_params",null); }, ), RaisedButton( child: Text("call_native_method_params"), onPressed: (){ Map<String,String> params = {"params":"flutter params"}; methodChannel.invokeMethod("call_native_method_params",params); }, ), RaisedButton( child: Text("call_native_method_native_result_callback"), onPressed: (){ _nativeCallbackWithParams(); }, ), Text(_content,style: TextStyle(color: Colors.red),)
Future<Null> _nativeCallbackWithParams() async{ dynamic result; try { result = await methodChannel.invokeMethod( "call_native_method_native_result_callback", null); } on PlatformException catch (e) { result = "Failed to get params: '${e.message}'."; } setState(() { _content = result; }); }
iOS 中的調用代碼get
FlutterViewController* flutterViewController = [[FlutterViewController alloc] init]; flutterViewController.fd_prefersNavigationBarHidden = YES; FlutterMethodChannel * messageChannel = [FlutterMethodChannel methodChannelWithName:@"com.pages.flutter/call_native" binaryMessenger:flutterViewController]; [messageChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { NSLog(@"flutter call native:\n method=%@ \n arguments = %@",call.method,call.arguments); if ([call.method isEqualToString:@"call_native_method_native_result_callback"]) { if (result) { result(@"flutter hello"); } }else if([call.method isEqualToString:@"call_native_method_pop_flutter_nav"]){ [weakSelf.navigationController popViewControllerAnimated:YES]; } }]; [self.navigationController pushViewController:flutterViewController animated:YES];
分別看下控制檯輸出:
flutter call native: method=call_native_method_no_params arguments = (null)
flutter call native: method=call_native_method_params arguments = { params = "flutter params"; }
第三個事件會在 Flutter 頁面顯示flutter hello 該值由宿主環境返回。
注意:這裏有個設計上的細節,上節提到過就是導航欄的問題,由於宿主環境有個導航欄,而 Flutter 自身也有導航欄,出現了矛盾,到底咱們應該保留宿主環境的,仍是 Flutter 頁面使用自身,隱藏宿主環境的導航欄。我我的以爲後則更合理,Flutter 頁面更瞭解本身導航欄具體功能、主題、交互及顯示,咱們只須要處理點擊返回按鈕 pop 回到宿主環境中,以下:
appBar: AppBar( title: Text('Flutter Page') , leading: IconButton(icon: Icon(Icons.arrow_back_ios), onPressed:()=>methodChannel.invokeMethod("call_native_method_pop_flutter_nav",null)), ),
咱們只須要在宿主環境中監聽到該事件後調用導航的 pop 功能。
宿主環境主動調用 Flutter
通常能夠用做宿主環境爲 Flutter 提供參數
EventChannel 是 Flutter 監聽宿主環境的 API ,FlutterEventChannel 是 iOS 宿主環境與 Flutter 交互平臺通道的 API 。
Flutter 代碼片斷
const EventChannel eventChannel = const EventChannel('com.pages.flutter/call_flutter');
@override void initState(){ super.initState(); eventChannel.receiveBroadcastStream(12345).listen(_onEvent,onError: _onError); } void _onEvent(Object event){ setState(() { _content = event.toString(); }); } void _onError(Object error){ setState(() { _content = error.toString(); }); }
iOS 宿主環境代碼片斷
NSString *eventChannelName = @"com.pages.flutter/call_flutter"; FlutterEventChannel *eventChannel = [FlutterEventChannel eventChannelWithName:eventChannelName binaryMessenger:flutterViewController]; [eventChannel setStreamHandler:self];
- (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)events { if (events) { events(@"hi flutter"); } return nil; } - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments { return nil; }
兩端交互通訊方式就是這樣的,這裏也只是介紹了他們通訊的方式,具體如何優雅的封裝、規範交互流程還須要咱們本身去考慮下。