Issue
Note: This question is specifically for `flutter.android.dart`.
How does the MethodChannel of Flutter works internally, like:
I know that MethodChannel first serializes the messages, before passing, but how, and what?
Is the kotlin/java side, always listening for a connection from dart side, like a web server does?, or
Is it android which calls the kotlin-side code, upon request from dart-side?, or
something else
Also, how is a MethodChannel different, from the Kotlin/Java interop with dart (which is an incoming feature, coming with dart 3, next year), like:
Is one efficient, than the other, or are they almost similar, in performance, and at other parameters, and
For example, to use
PDFRenderer
on a document(Uint8List
), of size 4 MiB, needs to be processed, which one method (among MethodChannel and interop)would be a better choice,
How is the following code expected to be changed to, to use kotlin interop, both at dart, and kotlin side:
package com.exa.mple
import android.net.Uri
import android.os.Build
import android.os.ParcelFileDescriptor
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.io.File
class MainActivity : FlutterActivity() {
private val METHOD_CHANNEL: String = "com.example/method-channel";
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, METHOD_CHANNEL).setMethodCallHandler { request: MethodCall, response: MethodChannel.Result ->
if (request.method == "getPlatformSDKVersion") {
response.success(Build.VERSION.SDK_INT.toString());
} else if (request.method == "getPrivateFilesDirPath") {
response.success(context.filesDir.absolutePath);
} else {
response.notImplemented();
}
}
}
}
I searched google, reddit, stack-overflow, even quora, thoroughly, tought found some info, but nothing satisfactory
Thanking you...
Solution
Method channels use a "method codec" and "message codec" to serialize the messages. There are a few flavours, but start by looking at StandardMessageCodec
and friends. The standard codec handles a broad range of types.
In terms of message passing, first take a look at the thread model diagram. The "Platform thread" is the main native thread vs the "Dart UI thread" is the main thread of the Dart VM. These two need to pass messages between themselves - using the codecs above. Essentially the mechanism is to drop a numbered message into a queue, which is processed periodically by the other thread. The other thread unmarshalls the request and dispatches it to the relevant registered handler (which are identified by their name, e.g. "com.somewhere.someplugin/somename" (which is just a naming convention)). The handler is passed the argument (one of the above supported types - often a map of key value pairs) and some form of a 'result' which allows the return value to be passed (which can again be any supported type).
That result (for example, generated by calling result.success(123.45)
in Android) creates a reply message with the serialized response (in this example a single double) and the original request message number which is added to the queue going the other way. When it is collected on the other thread the message number allows the caller to match up the result with the original request and (as example in a Dart->native call) completes the completer that allows the await channel.invokeMethod('someMethod');
future to complete.
In terms of performance, FFI is typically much more performant as there is no/minimal marshalling. It's reasonable to expect jnigen
to be too, but as it is highly experimental, you will need to wait and see.
Answered By - Richard Heap
Answer Checked By - Pedro (JavaFixing Volunteer)