Flutter Course — Message Communication between Flutter and iOS Native Code
It will be good if you read this blog before continue reading this one. Here are the few terms you should know
host → Native iOS code. Also called platform
Flutter portion → having flutter , dart code (also called client or UI )
platform channel → host and flutter portion communication channels send and receive message
- Messages are passed between the client (UI) and host (platform) using platform channels as illustrated in this diagram: Messages and responses are passed asynchronously, to ensure the user interface remains responsive.
- Even though Flutter sends messages to and from Dart asynchronously, whenever you invoke a channel method, you must invoke that method on the platform’s main thread.
Send Message to Native iOS Code
We will use the same code that we previously write here in this blog
First is to import these files
import 'package:flutter/services.dart';
import 'dart:async';
As shown in Figure 2 we did a few things
- The client and host sides of a channel are connected through a channel name passed in the channel constructor
MethodChannel
. All channel names used in a single app must be unique; prefix the channel name with a unique ‘domain prefix’, for example:my_flutter_app.sendMessage
.MethodChannel
exists inimport ‘package:flutter/services.dart’;
- Next, invoke a method on the method channel, specifying the concrete method to call using the
String
identifiersendMessage
. The call might fail—for example, if the platform doesn’t support the platform API (such as when running in a simulator), so wrap theinvokeMethod
call in a try-catch statement. - Use the returned result to update the user interface state in
_messageText
insidesetState
.
As shown in Figure 3 , when we tap on button _sendMessageToNativeCode
method will execute that will communicate to our native code, Here we are showing Text(_messageText)
return by our native code
As shown in Figure 4, here we handle code to receive message in native code send by our flutter portion code , here are the few things
- create a FlutterMethodChannel tied to the channel name
my_flutter_app.sendMessage
- add the iOS Swift code
callSomeMethod
that currently return some hard coded message as a result , note since this code is async you can do whatever you want , call some API, logging everything
Send Message to Native iOS Code with param using manual technique
As shown in Figure 5, we are now passing Map<String, String>
to native iOS code
As shown in Figure 6, we are now parsing these param value and combining these value to our hardcoded string and sending back to flutter code
Send Message to Native iOS Code with param using code generation libraries
To include json_serializable
in your project, you need one regular dependency, and two dev dependencies. In short, dev dependencies are dependencies that are not included in our app source code—they are only used in the development environment.
As show in Figure 8, we add new packages, and save it , it will automatically install this package it not so you can run this command in terminal in flutter portion of git sub module
flutter pub get
As shown in Figure 9 , we created a class name User but we get some error. These errors are entirely normal and are simply because the generated code for the model class does not exist yet. To resolve this, run the code generator that generates the serialization boilerplate
By running flutter pub run build_runner build — delete-conflicting-outputs
in the project root, you generate JSON serialization code for your models whenever they are needed. This triggers a one-time build that goes through the source files, picks the relevant ones, and generates the necessary serialization code for them. As shown in Figure 10 now error gone
remember, you have to run the build manually every time you make changes in your model classes.
flutter pub run build_runner build --delete-conflicting-outputs
As shown in Figure 11, we did few things
- Create user model instance and populate with data
- using
import ‘dart:convert’;
lib we convert model to json string that will pass to our native code
In our native code we parse it as String json and using swift Codable feature we convert it to User struct instance
Receive Message from Native iOS Code with param
As shown in Figure 13, we created a class FlutterNativeCodeListenerMethodChannel
, this class will be responsible for handling message from native code
As shown in Figure 14, in main.dart main method we called configure method of FlutterNativeCodeListenerMethodChannel
which basically create a MethodChannel
and create a communication channel between native and flutter code
As shown in Figure 15, we called setMethodCallHandler
to handle message from native code , we expect string from native code , then we convert it into Map<String, dynamic>
and finally User
using dependency we previously installed, after that we update _messageText
property setState
callback which re-render build method for this screen
As shown in Figure 16, when user tap on button in native code , previously we are opening flutter screen, now we send message to flutter screen then open that screen,
Note : In AppDelegate
didFinishLaunchingWithOptions
we already warm up our flutter engine which means that flutter screen is loaded but not showing and also main.dart
loaded as well and our listener is setup, so when user tap on button it first send message to flutter code which already warm up so it receive first callback update _messageText
property and then we open flutter controller which basically show directly the screen with proper message as shown in Figure 17
Update git submodule
As you see in previous blog, we are using flutter code using git submodule and we already see how we can update it, so in root folder of your native . platform code just run these commands
cd my_flutter_app
git add .
git commit -m 'communication between platform'
git push
Now run git pull and quit source tree and open again , in my case, now our git sub module now pointing to latest master, push that code,
git pull
cd my_flutter_app
flutter build ios --simulator
cd ..
pod install
You can checkout code until this here