Communication between Flutter and native relies on flexible messaging

  • The Flutter part of the application sends messages to its host (iOS or Android) application (native app) via the platform Channel.

  • The host listens on the platform channel and receives the message. It then invokes the platform’s API and sends the response back to the client, the Flutter part of the application.

There are three interaction modes between Flutter and the original, which are as follows:

  • MethodChannel: Method Invocation usually used to call a method in native

  • BasicMessageChannel: Used less frequently to pass strings and semi-structured information

  • EventChannel: Communication for Event streams. There are monitoring functions, such as power changes that push data directly to the flutter terminal

The three channels are independent and serve different purposes, but they are very similar in design. Each Channel has three important member variables:

  • Name: represents the name and unique identifier of a Channel

  • Messager: Type of BinaryMessenger, which stands for message messenger and is a tool for sending and receiving messages

  • Codec: The MessageCodec or MethodCodec type, which represents the codec for the message

The specific use

  • First, create Native project and Flutter Module respectively. I take the communication between iOS and Flutter as an example. After creating the iOS project, you need to manage the Flutter Module through CocoaPods.

  • Create a Podfile in the iOS project and import the Flutter Module as follows:
Platform: ios, '11.0' inhibit_all_warnings! #flutter Module file path 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) endCopy the code

Note: Flutter_application_path this is the path of the Flutter project, I am the native project and Flutter are in the same directory

  • And finally at the terminalpod installSee if the Flutter Module can be introduced properly. This can be imported in the iOS project#import <Flutter/Flutter.h>

Use of MethodChannel

The code written here does the following

1. Click the button of the native page to jump to the page of Flutter, and click the back button in the Flutter to return to the native page normally

2. Click the current charge on the Flutter page to transfer the value to the Flutter page from the native interface

Native code

@property (nonatomic, strong)FlutterEngine *flutterEngine; @property (nonatomic, strong)FlutterViewController *flutterVC; @property (nonatomic, strong)FlutterMethodChannel *methodChannel; - (void)viewDidLoad { [super viewDidLoad]; / / hide the underlying navigation self. The 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]; // create channel self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"methodChannel" binaryMessenger:self.flutterVC.binaryMessenger]; } - (void)onBtnClick {} - (void)onBtnClick { [self.methodChannel invokeMethod:@"EnterFlutter" arguments:@""]; / / a push into the Flutter page [self navigationController pushViewController: self. FlutterVC animated: YES]; __weak __typeof(self) weakSelf = self; // Listen for events from Flutter [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {if ([call.method isEqualToString:@"exit"]) { [weakSelf.flutterVC.navigationController popViewControllerAnimated:YES]; } else if ([call.method isEqualToString:@"getBatteryLevel"]) {// Pass the value back to the Flutter page [weakself. methodChannel invokeMethod:@"BatteryLevel" arguments:@"60%"]; } }]; } // Create an engine, which can be defined as a singleton in a real project. - (FlutterEngine *) FlutterEngine {if (! _flutterEngine) { FlutterEngine * engine = [[FlutterEngine alloc] initWithName:@"flutterEngin"]; if (engine.run) { _flutterEngine = engine; } } return _flutterEngine; }Copy the code

Flutter server-side code

class _MyHomePageState extends State<MyHomePage> { String batteryLevel = '0%'; Final MethodChannel _methodhannel = const MethodChannel('com.pages. Your /native_get'); @override void initState() { super.initState(); / / Flutter end to monitor data sent from _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: () {/ / send a message to native _methodhannel invokeListMethod (' exit ');}, child: Text (' return '),), ElevatedButton (onPressed: () {/ / send a message to native _oneChannel invokeListMethod (' getBatteryLevel);}, child: Text (' current charge ${batteryLevel} '),),),),),); }}Copy the code

BasicMessageChannel

It can communicate with Flutter. The Flutter end can send messages to iOS, and iOS can send messages to Flutter. This code allows you to input text into a TextField in Flutter, and to output text in a timely manner on iOS.

Native code

You need to add a MessageChannel to the code above, and receive and send messages

@property (nonatomic, strong) FlutterBasicMessageChannel *messageChannel; self.messageChannel = [FlutterBasicMessageChannel messageChannelWithName:@"messgaeChannel" binaryMessenger:self.flutterVC.binaryMessenger]; [self.messageChannel setMessageHandler:^(id _Nullable message, FlutterReply _Nonnull callback) {NSLog(@" Received a Flutter message: %@",message); }];Copy the code

Flutter server-side code

Final messageChannel = const BasicMessageChannel("messgaeChannel", StandardMessageCodec());Copy the code

Listen to the message

MessageChannel. SetMessageHandler ((the message) {print (' received $message from iOS); return Future(() {}); });Copy the code

Send a message

messageChannel.send(str);
Copy the code

Use of EventChannel

Only native messages can be sent to Flutter terminals, such as monitoring cell phone battery changes, network changes, sensors, etc.

Here I have implemented a timer on the native end that sends a message to the Flutter end every second to mimic this function.

Native code

Remember that the class implements the protocol 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]; // call createTimer [self createTimer]; / / create a timer - (void) createTimer {NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(timeStart) userInfo:nil repeats:YES]; } // Send a message - (void)timeStart{self.count += 1; NSDictionary *dic = [NSDictionary dictionaryWithObject:@(self.count) forKey:@"count"]; if (self.events ! = nil) { self.events(dic); }} // Indicates that the channel has been built, - (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)eventSink { self.events = eventSink; return nil; } - (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments {self.events = nil; return nil; }Copy the code

Flutter server-side code

Final EventChannel EventChannel = const EventChannel(' EventChannel '); . / / monitoring data eventChannel receiveBroadcastStream (), listen ((event) {print (event. The toString ()); });Copy the code

These are some of the ways iOS communicates with Flutter native. Welcome to follow, like and forward.