| leads all the cross-platform solutions, whether it is the earliest WebApp and HybridApp, still very hot before an RN and Weex, are faced with the question of how to balance the cross-platform and efficiency. Flutter is a new generation of cross-platform solutions that are rumored to perform as well as native. Why is Flutter so good? Let’s explore the secrets between Flutter and primortium, starting with Flutter’s communication mechanism. Note: Since the author is not familiar with iOS development, most of this article uses the Android perspective.

First, cross-platform mechanics are very different

Cross-platform solutions have been around for a long time, and the authors of Talk about Cross-platform Technologies on Mobile have broken them down into the following categories:

  • Web Flow: Also known as Hybrid technology, it is based on Web-related technologies to implement interfaces and functions

  • Transcoding flow: Convert a language to Objective-C, Java, or C#, and develop it using official tools for different platforms

  • Compile flow: Compiles a language to a binary file, generates a dynamic library, or packages it as an APK/IPA/XAP file

  • Virtual machine flow: Runs by porting virtual machines in one language to different platforms

In the past, the earliest Hybrid development mainly relied on WebView. However, WebView is a very heavy control, which is prone to memory problems, and complex UI display performance is not good on WebView. The React-Native technology eliminates WebView and uses JavaScriptCore as a bridge to convert JS calls into native calls, sacrificing only a small amount of cross-platform performance gains.

The Flutter implementation takes a more radical approach across platforms. It neither uses WebView nor JavaScriptCore, but their own implementation of a UI framework, and then directly system to draw UI on the lower rendering system. So instead of USING JS, it uses Dart. The Dart language has good properties suitable for Flutter. See the FAQ for more details. Why did Flutter choose to use the Dart language?

Ii. Communication between Flutter and native

The communication between Flutter and native can be divided into two types: Flutter active sending and native active sending. However, the official documentation of Flutter only introduces the mode of Flutter active sending. A plugin is provided as an example of native’s active sending method. The specific usage can be viewed by clicking on the official website link, which will not be described here. It is mainly to explore how the two sides of the code actually call each other.

  1. MethodChannel:

Message passing between a Flutter is done using a MethodChannel. Let’s look at its constructor first. As you can see, you need a name and an optional MethodCodec. Name is the identity for this MethodChannel, which you’ll use later. MethodCodec is a codec that determines what type of data we can pass. StandarMethodCodec has the following rules:

The Dart (RTX) Android iOS
null null nil (NSNull when nested)
bool java.lang.Boolean NSNumber numberWithBool:
int java.lang.Integer NSNumber
int if 32 bits not enough java.lang.Long
int if 64 bits not enough java.math.BigInteger
double java.lang.Double NSNumber numberWithDouble:
String java.lang.String NSString
Uint8List byte[] FlutterStandardTypedData
Int32List int[] FlutterStandardTypedData
Int64List long[] FlutterStandardTypedData
Float64List double[] FlutterStandardTypedData
List java.util.ArrayList NSArray
Map java.util.HashMap NSDictionary
  1. invokeMethod()

The invokeMethod() method is a MethodCall identifier, and arguments are a MethodCall parameter. Note that arguments must comply with the above rules (by default, custom classes cannot be passed directly, but we can convert them to Json and pass them). You can also modify MethodCode to pass complex data structures). Note: As you can see, this is an async method that returns a Future. We must await the return value of this method. To call with await, you must run in a function with the async flag. You can see the examples on the official website for specific invocation and usage. So let’s go a little bit further here.

  1. BinaryMessages.send()

One interesting thing to see when you look at the send() method is that if the value fetched by _mockHandlers is not null, the message is handled directly by the corresponding handler and is not sent. Look at the comments for setMockMessageHandler(), which officially intercepts messages and can be used for testing.

  1. _sendPlatformMessage () – Windows. SendPlatformMessage ()

There is a native method called, so we need to find this native method.

  1. Engine engine engine engine engine engine engine engine engine engine engine engine Then the corresponding native method can be found.

This is a long code, so let’s take a look at it a little bit. If you look at line 64 first, it’s useful to note that this suite only works on the ISOLATE. Then look at the key method: dart_state->window()->client()->HandlePlatformMessage()

Further down the line, you can find HandlePlatformMessage() in Windows Client, but you can see that this is a pure virtual function. This is a tricky way to find out which class inherits from WindowClient. You can find that only RuntimeController inherits from WindowClient. See the implementation of this method.

So what is this client? Is a RuntimeDelegate …………………… Finally, I found the implementation in PlatformViewAndroid (of course, there is also a corresponding iOS, here because I am more familiar with Android, I will only take out the Android), the middle process is not nutrition will not be detailed.

OK, after many obstacles, I finally found the way of JNI. In other words, if you find the method that g_handle_platform_message_method points to, you’re ready to enter the Android world. (Keep an eye out for pending_responses_ ahead of time, which will be mentioned later.)

Use the simple method of violence, go directly to the assignment statement, find only one, then don’t think, it must be that.

Then look for the class name to find the method in the Flutter Android project.

  1. Android

Finally back to the JAVA world, or quite moved. In fact, the core of this code is onMessage() to take a look at the implementation of this method.

It is an abstract function and has three implementations. So, without guessing, let’s go back and see what type this handler variable is. Handlers are fetched from a map (mMessageHandlers) with the channel’s name as the key. Where is this set? The trail seems to drop right here. Hold on, let’s just remember the steps we took to use MethodChannel. (Below is a screenshot of the Chinese official website tutorial)

Okay, I’ve circled the key points, so just jump in and see.

Then the handler is IncomingMethodCallHandler object is determined. Go straight to its onMessage method.

Finally, we see the familiar onMethodCall method.

  1. The message reply method is called, so the next step is to consider how the data is sent back. Remember in point 6 there was a callback function at the beginning? The above reply calls this callback function.

Take a look at this callback, which calls two native layer functions. You don’t need to read the empty one. If you know how to pass the non-empty one, you will know how to pass it. In platform_view_android_jni.cc, we can find the corresponding function.

Message_response looks like a callback function. It’s taken from Pending_responses_. Remember the callback function in point 4? It is encapsulated in the native layer and placed in the Pending_responses_ (see the process mentioned in point 5, so we won’t repeat the map here), so the message_response will return to the callback function after some processing. I won’t go into detail here.

  1. So there you have it, a closed loop. As can be seen, the overall communication flow is in a V shape.


IVWEB Technology Weekly shocked online, pay attention to the public number: IVWEB community, weekly timing push quality articles.

  • Collection of weekly articles: weekly
  • Team open source project: Feflow