Flutter 與原生通訊的三種方式
Flutter 與原生之間的通訊依賴靈活的訊息傳遞方式
-
應用的Flutter部分通過平臺通道(platform channel)將訊息傳送到其應用程式的所在的宿主(iOS或Android)應用(原生應用)
-
宿主監聽平臺通道,並接收該訊息。然後它會呼叫該平臺的 API,並將響應傳送回客戶端,即應用程式的 Flutter 部分。
Flutter 與原生存在三種互動方式,分別為:
-
MethodChannel:用於傳遞方法呼叫(method invocation)通常用來呼叫 native 中某個方法
-
BasicMessageChannel:用於傳遞字串和半結構化的資訊,這個用的比較少
-
EventChannel:用於資料流(event streams)的通訊。有監聽功能,比如電量變化之後直接推送資料給flutter端
三種 Channel 之間互相獨立,各有用途,但它們在設計上卻非常相近。每種 Channel 均有三個重要成員變數:
-
name: String型別,代表 Channel 的名字,也是其唯一識別符號
-
messager:BinaryMessenger 型別,代表訊息信使,是訊息的傳送與接收的工具
-
codec: MessageCodec 型別或 MethodCodec 型別,代表訊息的編解碼器
具體使用
- 首先分別建立 Native 工程和 Flutter Module。我這裡是以 iOS 端和 Flutter 通訊為例,建立完 iOS 工程後,需要通過 CocoaPods 管理 Flutter Module。
- 然後在 iOS 工程裡面建立 Podfile ,然後引入 Flutter Module ,具體程式碼如下:
``` platform :ios,'11.0' inhibit_all_warnings!
flutter module 檔案路徑
flutter_application_path = '../flutter_module' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'Native_iOS' do
install_all_flutter_pods(flutter_application_path)
end
``
注意:` flutter_application_path 這個是 Flutter 工程的路徑,我是原生專案和 Flutter在一個目錄下
- 最後在終端
pod install
一下,看是否能正常引入 Flutter Module。這樣就可以在iOS工程裡面匯入#import <Flutter/Flutter.h>
一、MethodChannel的使用
這裡寫的程式碼實現了以下功能
1.實現了點選原生頁面的按鈕跳轉到 Flutter 頁面,在 Flutter 點選返回
按鈕能正常返回原生頁面
2.實現在Flutter頁面點選當前電量
,從原生介面傳值到 Flutter 頁面
原生端程式碼
``` @property (nonatomic, strong)FlutterEngine *flutterEngine;
@property (nonatomic, strong)FlutterViewController *flutterVC;
@property (nonatomic, strong)FlutterMethodChannel *methodChannel;
- (void)viewDidLoad { [super viewDidLoad];
//隱藏了原生的導航欄 self.navigationController.navigationBarHidden = YES;
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 80, 80)]; btn.backgroundColor = [UIColor redColor]; [btn addTarget:self action: @selector(onBtnClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn];
self.flutterVC = [[FlutterViewController alloc] initWithEngine:self.flutterEngine nibName:nil bundle:nil]; //建立channel self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"methodChannel" binaryMessenger:self.flutterVC.binaryMessenger];
}
- (void)onBtnClick {
//告訴Flutter對應的頁面 //Method--方法名稱,arguments--引數 [self.methodChannel invokeMethod:@"EnterFlutter" arguments:@""];
//push進入Flutter頁面
[self.navigationController pushViewController:self.flutterVC animated:YES];
__weak __typeof(self) weakSelf = self; //監聽Flutter發來的事件 [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { //響應從Flutter頁面傳送來的方法 if ([call.method isEqualToString:@"exit"]) { [weakSelf.flutterVC.navigationController popViewControllerAnimated:YES]; } else if ([call.method isEqualToString:@"getBatteryLevel"]) { //傳值回Flutter頁面 [weakSelf.methodChannel invokeMethod:@"BatteryLevel" arguments:@"60%"]; } }]; }
//建立引擎,真正在專案中,引擎可以定義為一個單例。這樣處理防止在原生裡面存在多引擎,是非常佔有記憶體的 - (FlutterEngine *)flutterEngine { if (!_flutterEngine) { FlutterEngine * engine = [[FlutterEngine alloc] initWithName:@"flutterEngin"]; if (engine.run) { _flutterEngine = engine; } } return _flutterEngine; } ```
Flutter 端程式碼
```
class _MyHomePageState extends State
String batteryLevel = '0%'; //定義通道 final MethodChannel _methodhannel = const MethodChannel('com.pages.your/native_get');
@override void initState() { super.initState();
//Flutter端監聽傳送過來的資料
_methodhannel.setMethodCallHandler((call) {
if (call.method == 'EnterFlutter') {
print(call.arguments);
} else if (call.method == 'BatteryLevel') {
batteryLevel = call.arguments;
}
setState(() {});
return Future(() {});
});
}
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( children: [ ElevatedButton( onPressed: () { //傳送訊息給原生 _methodhannel.invokeListMethod('exit'); }, child: Text('返回'), ), ElevatedButton( onPressed: () { //傳送訊息給原生 _oneChannel.invokeListMethod('getBatteryLevel'); }, child: Text('當前電量${batteryLevel}'), ), ], ), ), ); } } ```
二、BasicMessageChannel的使用
它是可以雙端通訊的,Flutter 端可以給 iOS 傳送訊息,iOS 也可以給 Flutter 傳送訊息。這段程式碼實現了在 Flutter 中的 TextField 輸入文字,在 iOS 端能及時輸出。
原生端程式碼
需要在上面程式碼的基礎上增加 MessageChannel ,並接收訊息和傳送訊息
``` @property (nonatomic, strong) FlutterBasicMessageChannel *messageChannel;
self.messageChannel = [FlutterBasicMessageChannel messageChannelWithName:@"messgaeChannel" binaryMessenger:self.flutterVC.binaryMessenger];
[self.messageChannel setMessageHandler:^(id _Nullable message, FlutterReply _Nonnull callback) {
NSLog(@"收到Flutter的:%@",message); }]; ```
Flutter 端程式碼
//需要建立和iOS端相同名稱的通道
final messageChannel =
const BasicMessageChannel("messgaeChannel", StandardMessageCodec());
監聽訊息
messageChannel.setMessageHandler((message) {
print('收到來自iOS的$message');
return Future(() {});
});
傳送訊息
messageChannel.send(str);
三、EventChannel的使用
只能是原生髮送訊息給 Flutter 端,例如監聽手機電量變化,網路變化,感測器等。
我這裡在原生端實現了一個定時器,每隔一秒傳送一個訊息給 Flutter 端,模仿這個功能。
原生端程式碼
記得所在的類要實現這個協議 FlutterStreamHandler
``` //定義屬性 //通道 @property (nonatomic, strong) FlutterEventChannel *eventChannel; //事件回撥 @property (nonatomic, copy) FlutterEventSink events; //用於計數 @property (nonatomic, assign) NSInteger count;
//初始化通道 self.eventChannel = [FlutterEventChannel eventChannelWithName:@"eventChannel" binaryMessenger:self.flutterVC.binaryMessenger];
[self.eventChannel setStreamHandler:self];
//呼叫建立定時器 [self createTimer];
//建立定時器 - (void)createTimer {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector: @selector(timeStart) userInfo:nil repeats:YES]; }
//傳送訊息 - (void)timeStart{
self.count += 1; NSDictionary *dic = [NSDictionary dictionaryWithObject:@(self.count) forKey:@"count"]; if (self.events != nil) { self.events(dic); } }
//代表通道已經建好,原生端可以傳送資料了 - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)eventSink {
self.events = eventSink; return nil; }
//代表Flutter端不再接收 - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments {
self.events = nil; return nil; } ```
Flutter 端程式碼
``` //建立通道 final EventChannel eventChannel = const EventChannel('eventChannel');
//開始監聽資料 eventChannel.receiveBroadcastStream().listen((event) { print(event.toString()); }); ```
以上就是iOS原生和Flutter通訊的幾種方法。歡迎關注、點贊及轉發。
- Flutter:仿京東專案實戰(4)-購物車頁面功能實現
- Flutter整合原生遇到的問題彙總
- Flutter:仿京東專案實戰(3)-商品詳情頁功能實現
- Flutter-Dart中的非同步和多執行緒講解
- iOS-底層原理分析之Block本質
- Flutter-官方推薦的Flutter與原生互動外掛Pigeon
- Flutter-flutter_sound錄音與播放
- iOS-CocoaPods的原理及Podfile.lock問題
- iOS配置多環境的三種方案
- iOS-各種Crash防護
- iOS-Swift中常見的幾種閉包
- Flutter:仿京東專案實戰(2)-分類和商品列表頁面功能實現
- Flutter:仿京東專案實戰(1)-首頁功能實現
- Flutter-JSON轉Model的四種便捷方案
- Flutter-導航與路由堆疊詳解
- Flutter 與原生通訊的三種方式
- iOS-記憶體洩漏檢測
- Fastlane實現自動打包
- 懶人必備神器-Xcode程式碼塊
- Jenkins實現自動化打包