{{announcement.body}}
{{announcement.title}}

Platform Channel in Flutter — Benefits and Limitations

DZone 's Guide to

Platform Channel in Flutter — Benefits and Limitations

In this article, we discuss basics behind Flutter's Platform Channel and how to implement it to better communicate between Dart and native code.

· Web Dev Zone ·
Free Resource

One of the biggest challenges for mobile cross-platform frameworks is how to achieve native performance and how to help developers create different kinds of features for different devices and platforms with as little effort as possible. In doing so, we need to keep in mind that UX should remain the same but with unique components that are specific for each particular platform (Android and iOS).

Although cross-platform frameworks (in most of these cases) can resolve platform-specific tasks, there is a certain number of tasks which, with custom platform-specific code, can be achieved only through native. The question is, how can those frameworks establish communication between the specific platform and application? The best example is the Flutter's Platform Channel.

What Is Platform Channel and When Should We Use it?

As the Flutter community grows, more and more community plugins and packages that execute platform-specific functionalities appear. If your project requires a specific feature that is not supported in Flutter or it's easier to implement it on the native side, you need to establish communication between native platforms (Android or iOS) and Flutter in order to execute that custom platform-specific code.

Platform Channel operates on the principle of sending and receiving messages without code generation. The communication is bidirectional and asynchronous. The Flutter application (the portion of the app that is written in Dart) in this communication represents a client that sends messages to the host (Android or iOS) and expects a response back, either as success or failure.

When the message is received on the host's side, we can execute the necessary logic in native code (Java/Kotlin for Android or Objective-C/Swift for iOS) or call any platform-specific APIs and send a response back to the Flutter application through the channel. When channels are created, we need to be mindful of naming conventions. The name of the channel in the Flutter application needs to be the same as the one on the native side.

You may also like: Flutter Tutorial for Developers: Step-by-Step Guide to Building Apps.

Setup

One of the basic characteristics of Platform Channel is the fact that it is easy to set up and understand both on the Flutter-side, and the native side. It's also well documented and explained in the official documentation

In order to explain how to setup/create a channel, I will create a simple example of communication between a Flutter app and Android native (Kotlin).

First, we need to create a channel in the Flutter app with an appropriate name. In this case, we can name it "platform_channel":

Dart




x


 
1
static const MethodChannel _channel = const MethodChannel('platform_channel');



Then, we need to create a channel on the Android-side with the same name:

Kotlin




xxxxxxxxxx
1


 
1
companion object {
2
 @JvmStatic
3
 fun registerWith(registrar: Registrar) {
4
 val channel = MethodChannel(registrar.messenger(), "platform_channel")
5
 channel.setMethodCallHandler(PlatformChannelPlugin(registrar.activity()))
6
 }
7
}



Once we create a channel, we need to create a method in our Flutter app in the PlatformChannel class, which will communicate with native:

Dart




xxxxxxxxxx
1


 
1
static Future<String> dummy_func() async {
2
 String result = await _channel.invokeMethod('dummy_func');
3
 return result;
4
}



Now, to get a response from this function and from native, we need to add this in the Flutter app where we want to collect the result:

Dart




xxxxxxxxxx
1


 
1
static Future<String> getDummyFunc() async => await PlatformChannel.dummy_func();



The final step is to provide an implementation for dummy_func in native:

Kotlin




xxxxxxxxxx
1
10


1
override fun onMethodCall(call: MethodCall, result: Result) {
2
 when {
3
 call.method == "dummy_func" -> result.success(setupDummyFunc(call))
4
 else -> result.notImplemented()
5
 }
6
}
7
 
          
8
private fun setupDummyFunc(call: MethodCall): String {
9
 return "return dummy string from native"
10
}



With this piece of code, we can say that we established basic communication between the Flutter app and native. Of course, this can be extended to provide any implementation that we need. If we want to pass arguments to native functions, we can create a Map of values and pass it to the invokeMethod as a second parameter:

Dart




xxxxxxxxxx
1


 
1
Map<String, dynamic> args = <String, dynamic>{};
2
args.putIfAbsent("dummy1", () => “dummy1”);
3
args.putIfAbsent("dummy2", () => “dummy2”);
4
args.putIfAbsent("dummy3", () => “dummy3”);



Dart




xxxxxxxxxx
1


 
1
static Future<String> dummy_func() async {
2
 String result = await _channel.invokeMethod(‘dummy_func’, args);
3
 return result;
4
}



Now, we can access those values in native with their IDs:

Kotlin




xxxxxxxxxx
1


 
1
dummy1 = call.argument<String>("dummy1").toString()
2
dummy2 = call.argument<String>("dummy2").toString()
3
 
          
4
dummy3 = call.argument<String>("dummy3").toString()



Here, it is essential to mention that if we are planning to create complex communication between Dart and a platform-specific code, which involves the usage of complicated data structures, I strongly suggest using some mechanism for serializing structured data. Luckily, there is a simple solution for this provided by Google. It's called Protocol Buffers.

Protocol buffers are platform and language-neutral mechanisms for data serialization. Even-more, Google provided tutorials on how to use Protocol Buffers for your desired language.  

Benefits of Platform Channel

When we are dealing with any communication, whether we are talking about communication between two or more apps, communication inside a single app, or, as in our case, communication with Dart and native code, a logical question arises: is that communication safe and reliable?

The Platform Channel is secured, and that's one of the important benefits that Platform Channel offers. Within our process, there is a memory buffer for communication between Dart and native code, and there is not any interprocess communication required to establish this communication; thus, there is no way that any other outside process can access this communication. This means that Platform Channel has the same level of security as any other native Android or native iOS application.

One of the benefits of Platform Channel is communication, which is itself asynchronous and bidirectional, meaning that Platform Channel doesn't block execution of other tasks that are independent of native code. Once the native code finishes its work, the result will be passed to the Dart, and the appropriate callback will be triggered and vice versa.

Another benefit is serialization and deserialization of values to and from messages that happens automatically when you send and receive values. This represents the valuable benefit of Platform Channel, alongside an ability to use Protocol Buffers for serializing structured data.

Limitations

Currently, the channel method can be called only from a UI thread (from the main Isolate). Calling MethodChannel and EventChannel from a spawned Isolate is not possible at this moment. Performing long-running operations on the main thread can cause "junk" on the Flutter application, and the platform-side will block other message channels. Maybe it's possible to create a workaround for this with ports, but the best advice is to avoid heavy lifting work on the main thread until Flutter resolves problems that happen during the call of platform channel methods from another Isolate.

Overview

Overall, Platform Channel represents a way to connect native code with a Flutter app (Dart). It can be used to implement any Flutter missing functionality using a platform-specific code (plugins) and call any APIs. Moreover, it's well documented and well described in the official documentation and continues to be a handy tool in cross-platform development.


Further Reading

Topics:
dart, flutter, kotlin, mobile app, native, platform channel, tutorial, web dev

Published at DZone with permission of Radivoje Ostojic . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}